Merge "ARM: 7125/1: Add unwinding annotations for 64bit division functions" into msm-3.0
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 50db52c..3ee63c0 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -15,19 +15,21 @@
 KERNEL_USE_OF ?= $(shell $(PERL) -e '$$of = "n"; while (<>) { if (/CONFIG_USE_OF=y/) { $$of = "y"; break; } } print $$of;' kernel/arch/arm/configs/$(KERNEL_DEFCONFIG))
 
 ifeq "$(KERNEL_USE_OF)" "y"
+DTS_NAME ?= $(MSM_ARCH)
+DTS_FILES = $(wildcard $(TOP)/kernel/arch/arm/boot/dts/$(DTS_NAME)*.dts)
+DTS_FILE = $(lastword $(subst /, ,$(1)))
+DTB_FILE = $(addprefix $(KERNEL_OUT)/arch/arm/boot/,$(patsubst %.dts,%.dtb,$(call DTS_FILE,$(1))))
+ZIMG_FILE = $(addprefix $(KERNEL_OUT)/arch/arm/boot/,$(patsubst %.dts,%-zImage,$(call DTS_FILE,$(1))))
 KERNEL_ZIMG = $(KERNEL_OUT)/arch/arm/boot/zImage
-DTB_FILE = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH).dtb
-DTS_FILE = $(KERNEL_OUT)/../../../../../../kernel/arch/arm/boot/dts/$(MSM_ARCH).dts
-FULL_KERNEL = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH)-zImage
 DTC = $(KERNEL_OUT)/scripts/dtc/dtc
 
 define append-dtb
-md $(KERNEL_OUT)/arch/arm/boot;\
-$(DTC) -p 1024 -O dtb -o $(DTB_FILE) $(DTS_FILE);\
-cat $(KERNEL_ZIMG) $(DTB_FILE) > $(FULL_KERNEL)
+mkdir -p $(KERNEL_OUT)/arch/arm/boot;\
+$(foreach d, $(DTS_FILES), \
+   $(DTC) -p 1024 -O dtb -o $(call DTB_FILE,$(d)) $(d); \
+   cat $(KERNEL_ZIMG) $(call DTB_FILE,$(d)) > $(call ZIMG_FILE,$(d));)
 endef
 else
-FULL_KERNEL = $(KERNEL_IMG)
 
 define append-dtb
 endef
diff --git a/Documentation/ABI/testing/sysfs-bus-pil b/Documentation/ABI/testing/sysfs-bus-pil
new file mode 100644
index 0000000..797b2ea
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-pil
@@ -0,0 +1,18 @@
+What:		/sys/bus/pil/devices/.../name
+Date:		March 2012
+Contact:	Stephen Boyd <sboyd@codeaurora.org>
+Description:
+		Shows the name of the peripheral used in pil_get().
+
+What:		/sys/bus/pil/devices/.../state
+Date:		March 2012
+Contact:	Stephen Boyd <sboyd@codeaurora.org>
+Description:
+		Shows the state state of a peripheral. Current states
+		supported are:
+
+			OFFLINE - peripheral is offline
+			ONLINE - peripheral is online
+
+		This file supports poll() to detect when a peripheral changes
+		state.
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 81bc1a9..f7ade3b 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -275,8 +275,8 @@
 If no 2.6.x.y kernel is available, then the highest numbered 2.6.x
 kernel is the current stable kernel.
 
-2.6.x.y are maintained by the "stable" team <stable@kernel.org>, and are
-released as needs dictate.  The normal release period is approximately 
+2.6.x.y are maintained by the "stable" team <stable@vger.kernel.org>, and
+are released as needs dictate.  The normal release period is approximately
 two weeks, but it can be longer if there are no pressing problems.  A
 security-related problem, instead, can cause a release to happen almost
 instantly.
diff --git a/Documentation/development-process/5.Posting b/Documentation/development-process/5.Posting
index 903a254..8a48c9b 100644
--- a/Documentation/development-process/5.Posting
+++ b/Documentation/development-process/5.Posting
@@ -271,10 +271,10 @@
    the linux-kernel list.
 
  - If you are fixing a bug, think about whether the fix should go into the
-   next stable update.  If so, stable@kernel.org should get a copy of the
-   patch.  Also add a "Cc: stable@kernel.org" to the tags within the patch
-   itself; that will cause the stable team to get a notification when your
-   fix goes into the mainline.
+   next stable update.  If so, stable@vger.kernel.org should get a copy of
+   the patch.  Also add a "Cc: stable@vger.kernel.org" to the tags within
+   the patch itself; that will cause the stable team to get a notification
+   when your fix goes into the mainline.
 
 When selecting recipients for a patch, it is good to have an idea of who
 you think will eventually accept the patch and get it merged.  While it
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
new file mode 100644
index 0000000..eb3986e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -0,0 +1,23 @@
+* ARM architected timer
+
+ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which
+provides a per-cpu local timer.
+
+The timer is attached to a GIC to deliver its two per-processor
+interrupts (one for the secure mode, one for the non-secure mode).
+
+** Timer node properties:
+
+- compatible : Should be "arm,armv7-timer"
+
+- interrupts : One or two interrupts for secure and non-secure mode
+
+- clock-frequency : The frequency of the main counter, in Hz. Optional.
+
+Example:
+
+	timer {
+		compatible = "arm,armv7-timer"";
+		interrupts = <1 13 0xf08 1 14 0xf08>;
+		clock-frequency = <100000000>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
new file mode 100644
index 0000000..f50e021
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -0,0 +1,42 @@
+* ARM L2 Cache Controller
+
+ARM cores often have a separate level 2 cache controller. There are various
+implementations of the L2 cache controller with compatible programming models.
+The ARM L2 cache representation in the device tree should be done as follows:
+
+Required properties:
+
+- compatible : should be one of:
+	"arm,pl310-cache"
+	"arm,l220-cache"
+	"arm,l210-cache"
+- cache-unified : Specifies the cache is a unified cache.
+- cache-level : Should be set to 2 for a level 2 cache.
+- reg : Physical base address and size of cache controller's memory mapped
+  registers.
+
+Optional properties:
+
+- arm,data-latency : Cycles of latency for Data RAM accesses. Specifies 3 cells of
+  read, write and setup latencies. Minimum valid values are 1. Controllers
+  without setup latency control should use a value of 0.
+- arm,tag-latency : Cycles of latency for Tag RAM accesses. Specifies 3 cells of
+  read, write and setup latencies. Controllers without setup latency control
+  should use 0. Controllers without separate read and write Tag RAM latency
+  values should only use the first cell.
+- arm,dirty-latency : Cycles of latency for Dirty RAMs. This is a single cell.
+- arm,filter-ranges : <start length> Starting address and length of window to
+  filter. Addresses in the filter window are directed to the M1 port. Other
+  addresses will go to the M0 port.
+
+Example:
+
+L2: cache-controller {
+        compatible = "arm,pl310-cache";
+        reg = <0xfff12000 0x1000>;
+        arm,data-latency = <1 1 1>;
+        arm,tag-latency = <2 2 2>;
+        arm,filter-latency = <0x80000000 0x8000000>;
+        cache-unified;
+        cache-level = <2>;
+};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-qup.txt b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
new file mode 100644
index 0000000..60de396
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
@@ -0,0 +1,37 @@
+Qualcomm I2C controller
+
+Required properties:
+
+ - reg : Offset and length of the register region(s) for the device
+	 For GSBI based controller, GSBI and QUP regions are expected
+	 For BLSP based controller, QUP region offset is expected
+ - reg-names : Register region name(s) referenced in reg above
+	 BLSP based controller expects QUP region name ("qup_phys_addr")
+	 GSBI controller expects QUP region name and GSBI region name
+	 ("gsbi_qup_i2c_addr")
+ - compatible : should be "qcom,i2c-qup"
+ - cell-index : I2C bus number used for this controller
+ - interrupts : QUP core interrupt(s). Core may have 1 error interrupt and flags
+	 for input/output service, or 3 separate interrupts for the 3 services
+ - interrupt-names: QUP core interrupt name(s) referenced in interrupts above
+	 Expected interrupt resource name(s) are: "qup_err_irq", "qup_in_irq",
+	 and "qup_out_irq"
+ - qcom,i2c-bus-freq : desired I2C bus clock frequency is Hz
+
+Optional property:
+ - qcom,i2c-src-freq : Frequency of the source clocking this bus in Hz.
+		      Divider value is set based on soruce-frequency and
+		      desired I2C bus frequency. If this value is not
+		      provided, the source clock is assumed to be running
+		      at 19.2 MHz.
+Example:
+	i2c@f9966000 {
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0xf9966000 0x1000>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 104 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+	};
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index 084050e..0c1762d 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -21,6 +21,7 @@
 	- qcom,sdcc-nonremovable - specifies whether the card in slot is
 				hot pluggable or hard wired.
 	- qcom,sdcc-disable_cmd23 - disable sending CMD23 to card when controller can't support it.
+	- qcom,sdcc-hs200 - enable eMMC4.5 HS200 bus speed mode
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
new file mode 100644
index 0000000..9cf57fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -0,0 +1,29 @@
+Fixed Voltage regulators
+
+Required properties:
+- compatible: Must be "regulator-fixed";
+
+Optional properties:
+- gpio: gpio to use for enable control
+- startup-delay-us: startup time in microseconds
+- enable-active-high: Polarity of GPIO is Active high
+If this property is missing, the default assumed is Active low.
+
+Any property defined as part of the core regulator
+binding, defined in regulator.txt, can also be used.
+However a fixed voltage regulator is expected to have the
+regulator-min-microvolt and regulator-max-microvolt
+to be the same.
+
+Example:
+
+	abc: fixedregulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-supply";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&gpio1 16 0>;
+		startup-delay-us = <70000>;
+		enable-active-high;
+		regulator-boot-on
+	};
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
new file mode 100644
index 0000000..82bef20
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -0,0 +1,54 @@
+Voltage/Current Regulators
+
+Optional properties:
+- regulator-name: A string used as a descriptive name for regulator outputs
+- regulator-min-microvolt: smallest voltage consumers may set
+- regulator-max-microvolt: largest voltage consumers may set
+- regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops
+- regulator-min-microamp: smallest current consumers may set
+- regulator-max-microamp: largest current consumers may set
+- regulator-always-on: boolean, regulator should never be disabled
+- regulator-boot-on: bootloader/firmware enabled regulator
+- <name>-supply: phandle to the parent supply/regulator node
+
+Example:
+
+	xyzreg: regulator@0 {
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <2500000>;
+		regulator-always-on;
+		vin-supply = <&vin>;
+	};
+
+Regulator Consumers:
+Consumer nodes can reference one or more of its supplies/
+regulators using the below bindings.
+
+- <name>-supply: phandle to the regulator node
+
+These are the same bindings that a regulator in the above
+example used to reference its own supply, in which case
+its just seen as a special case of a regulator being a
+consumer itself.
+
+Example of a consumer device node (mmc) referencing two
+regulators (twl-reg1 and twl-reg2),
+
+	twl-reg1: regulator@0 {
+		...
+		...
+		...
+	};
+
+	twl-reg2: regulator@1 {
+		...
+		...
+		...
+	};
+
+	mmc: mmc@0x0 {
+		...
+		...
+		vmmc-supply = <&twl-reg1>;
+		vmmcaux-supply = <&twl-reg2>;
+	};
diff --git a/Documentation/devicetree/bindings/resource-names.txt b/Documentation/devicetree/bindings/resource-names.txt
new file mode 100644
index 0000000..e280fef
--- /dev/null
+++ b/Documentation/devicetree/bindings/resource-names.txt
@@ -0,0 +1,54 @@
+Some properties contain an ordered list of 1 or more datum which are
+normally accessed by index.  However, some devices will have multiple
+values which are more naturally accessed by name.  Device nodes can
+include a supplemental property for assigning names to each of the list
+items.  The names property consists of a list of strings in the same
+order as the data in the resource property.
+
+The following supplemental names properties are defined.
+
+Resource Property	Supplemental Names Property
+-----------------	---------------------------
+reg			reg-names
+clocks			clock-names
+interrupts		interrupt-names
+
+Usage:
+
+The -names property must be used in conjunction with the normal resource
+property. If not it will be ignored.
+
+Examples:
+
+l4-abe {
+	compatible = "simple-bus";
+	#address-cells = <2>;
+	#size-cells = <1>;
+	ranges = <0 0 0x48000000 0x00001000>, /* MPU path */
+		 <1 0 0x49000000 0x00001000>; /* L3 path */
+	mcasp {
+		compatible = "ti,mcasp";
+		reg = <0 0x10 0x10>, <0 0x20 0x10>,
+		      <1 0x10 0x10>, <1 0x20 0x10>;
+		reg-names = "mpu", "dat",
+			    "dma", "dma_dat";
+		interrupts = <11>, <12>;
+		interrupt-names = "rx", "tx";
+	};
+
+	timer {
+		compatible = "ti,timer";
+		reg = <0 0x40 0x10>, <1 0x40 0x10>;
+		reg-names = "mpu", "dma";
+	};
+};
+
+
+usb {
+	compatible = "ti,usb-host";
+	reg = <0x4a064000 0x800>, <0x4a064800 0x200>,
+	      <0x4a064c00 0x200>;
+	reg-names = "config", "ohci", "ehci";
+	interrupts = <14>, <15>;
+	interrupt-names = "ohci", "ehci";
+};
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
new file mode 100644
index 0000000..cf727d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -0,0 +1,38 @@
+Qualcomm SLIMBUS controller
+
+Required properties:
+
+ - reg : Offset and length of the register region(s) for the device
+ - reg-names : Register region name(s) referenced in reg above
+	 Required register resource entries are:
+	 "slimbus_physical": Physical adderss of controller register blocks
+	 "slimbus_bam_physical": Physical address of Bus Access Module (BAM)
+				 for this controller
+ - compatible : should be "qcom,slim-msm"
+ - cell-index : SLIMBUS number used for this controller
+ - interrupts : Interrupt numbers used by this controller
+ - interrupt-names : Required interrupt resource entries are:
+	"slimbus_irq" : Interrupt for SLIMBUS core
+	"slimbus_bam_irq" : Interrupt for controller core's BAM
+
+Optional property:
+ - reg entry for slew rate : If slew rate control register is provided, this
+	 entry should be used.
+ - reg-name for slew rate: "slimbus_slew_reg"
+ - qcom,min-clk-gear : Minimum clock gear at which this controller can be run
+		 (range: 1-10)
+		 Default value will be 1 if this entry is not specified
+ - qcom,max-clk-gear: Maximum clock gear at which this controller can be run
+		 (range: 1-10)
+		 Default value will be 10 if this entry is not specified
+Example:
+	slim@fe12f000 {
+		cell-index = <1>;
+		compatible = "qcom,slim-msm";
+		reg = <0xfe12f000 0x35000>,
+		      <0xfe104000 0x20000>;
+		reg-names = "slimbus_physical", "slimbus_bam_physical";
+		interrupts = <0 163 0 0 164 0>;
+		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+		qcom,min-clk-gear = <10>;
+	};
diff --git a/Documentation/devicetree/bindings/spmi/msm-qpnp-gpio.txt b/Documentation/devicetree/bindings/spmi/msm-qpnp-gpio.txt
new file mode 100644
index 0000000..f07d3c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/msm-qpnp-gpio.txt
@@ -0,0 +1,142 @@
+* msm-qpnp-gpio
+
+msm-qpnp-gpio is a GPIO chip driver for the MSM SPMI implementation.
+It creates a spmi_device for every spmi-dev-container block of device_nodes.
+These device_nodes contained within specify the PMIC GPIO number associated
+with each GPIO chip. The driver will map these to Linux GPIO numbers.
+
+[PMIC GPIO Device Declarations]
+
+-Root Node-
+
+Required properties :
+ - spmi-dev-container : Used to specify the following child nodes as part of the
+   same SPMI device.
+ - gpio-controller : Specify as gpio-contoller. All child nodes will belong to this
+   gpio_chip.
+ - #gpio-cells: We encode a PMIC GPIO number and a 32-bit flag field to
+   specify the gpio configuration. This must be set to '2'.
+ - #address-cells: Specify one address field. This must be set to '1'.
+ - #size-cells: Specify one size-cell. This must be set to '1'.
+ - compatible = "qcom,qpnp-gpio" : Specify driver matching for this driver.
+
+-Child Nodes-
+
+Required properties :
+ - reg : Specify the spmi offset and size for this gpio device.
+ - qcom,qpnp-gpio-num : Specify the PMIC GPIO number for this gpio device.
+
+Optional properties :
+ - qcom,qpnp-gpio-cfg : Specify the PMIC gpio configuration.
+   The format of this configuration is specified in a tuple of 9 entries.
+   These entries should be specified in the same order as the entries listed
+   in this following discription.
+
+   @direction:		indicates whether the gpio should be input, output, or
+			both.
+			QPNP_GPIO_DIR_OUT  = 1,
+			QPNP_GPIO_DIR_IN   = 2,
+			QPNP_GPIO_DIR_BOTH = 3
+
+   @output_type:	indicates gpio should be configured as CMOS or open
+			drain.
+			QPNP_GPIO_OUT_BUF_OPEN_DRAIN = 1,
+			QPNP_GPIO_OUT_BUF_CMOS = 0
+
+   @output_value:	The gpio output value of the gpio line - 0 or 1
+   @pull:		Indicates whether a pull up or pull down should be
+			applied. If a pullup is required the current strength
+			needs to be specified. Current values of 30uA, 1.5uA,
+			31.5uA, 1.5uA with 30uA boost are supported.
+			QPNP_GPIO_PULL_UP_30	 = 0,
+			QPNP_GPIO_PULL_UP_1P5	 = 1,
+			QPNP_GPIO_PULL_UP_31P5	 = 2,
+			QPNP_GPIO_PULL_UP_1P5_30 = 3,
+			QPNP_GPIO_PULL_DN	 = 4,
+			QPNP_GPIO_PULL_NO	 = 5
+
+  @vin_sel:		specifies the voltage level when the output is set to 1.
+			For an input gpio specifies the voltage level at which
+			the input is interpreted as a logical 1.
+			QPNP_GPIO_VIN0 = 0,
+			QPNP_GPIO_VIN1 = 1,
+			QPNP_GPIO_VIN2 = 2,
+			QPNP_GPIO_VIN3 = 3,
+			QPNP_GPIO_VIN4 = 4,
+			QPNP_GPIO_VIN5 = 5,
+			QPNP_GPIO_VIN6 = 6,
+			QPNP_GPIO_VIN7 = 7
+
+  @out_strength:	the amount of current supplied for an output gpio.
+			QPNP_GPIO_OUT_STRENGTH_HIGH = 1,
+			QPNP_GPIO_OUT_STRENGTH_MED  = 2,
+			QPNP_GPIO_OUT_STRENGTH_LOW  = 3
+
+  @source_sel:		choose alternate function for the gpio. Certain gpios
+			can be paired (shorted) with each other. Some gpio pin
+			can act as alternate functions.
+			QPNP_GPIO_FUNC_NORMAL   = 0,
+			QPNP_GPIO_FUNC_PAIRED   = 1
+			QPNP_GPIO_FUNC_1	= 2,
+			QPNP_GPIO_FUNC_3	= 3,
+			QPNP_GPIO_DTEST1	= 4,
+			QPNP_GPIO_DTEST2	= 5,
+			QPNP_GPIO_DTEST3	= 6,
+			QPNP_GPIO_DTEST4	= 7
+
+  @inv_int_pol:		Invert polarity before feeding the line to the interrupt
+			module in pmic. This feature will almost be never used
+			since the pm8xxx interrupt block can detect both edges
+			and both levels.
+  @master_en:		1 = Enable features within the GPIO block based on
+			configurations.
+			0 = Completely disable the GPIO block and let the pin
+			float with high impedance regardless of other settings.
+
+[PMIC GPIO clients]
+
+Required properties :
+ - gpios : Contains 3 fields of the form <&gpio_controller pmic_gpio_num flags>
+
+[Example]
+
+qpnp: qcom,spmi@fc4c0000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		qcom,pm8941@0 {
+			spmi-slave-container;
+			reg = <0x0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			pm8941_gpios: gpios {
+				spmi-dev-container;
+				compatible = "qcom,qpnp-gpio";
+				gpio-controller;
+				#gpio-cells = <2>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				qcom,pm8941_gpio1@0xc000 {
+					reg = <0xc000 0x100>;
+					qcom,qpnp-gpio-num = <62>;
+				};
+
+				qcom,pm8941_gpio2@0xc100 {
+					reg = <0xc100 0x100>;
+					qcom,qpnp-gpio-num = <20>;
+					qcom,qpnp-gpio-cfg = <0x1 0x1 0x1 0x2 0x3 0x2 0x0 0x0 0x1>;
+				};
+			};
+
+			qcom,testgpio@1000 {
+				compatible = "qcom,qpnp-testgpio";
+				reg = <0x1000 0x1000>;
+				gpios = <&pm8941_gpios 62 0x0 &pm8941_gpios 20 0x1>;
+			};
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/spmi/msm-spmi.txt b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
index fa91514..d50037f 100644
--- a/Documentation/devicetree/bindings/spmi/msm-spmi.txt
+++ b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
@@ -1,13 +1,28 @@
 * SPMI
 
-The spmi Device Tree support interprets up to two levels of Device Tree
+The SPMI Device Tree support interprets up to three levels of Device Tree
 topology. The first level is required and specifies only a slave address.
 The second level is optional and allows for the specification of different
-offsets within the same 16-bit address space underneath a particular SPMI
-slave ID. Within the second level, any number of address ranges can be
-associated with a particular device within that 16-bit range.
+device nodes within the same 16-bit address space underneath a particular
+SPMI slave ID. Within the second level, any number of address ranges can be
+associated with a particular device within that 16-bit range. An additional
+flag allows for the possiblity to specify that all device nodes should
+have their resources dedicated to only one spmi_device. This flag can
+be specified at the second level, or an optional third level. By default
+without this flag, one spmi_device is created for each device_node.
 
-First level
+[Root Node]
+
+Recommended properties :
+ - interrupt-controller : Used to specify the root node as the
+   interrupt controller for SPMI devices.
+ - #interrupt-cells : The number of cells used to express one interrupt.
+
+Notes :
+ - It is considered an error to include either spmi-container-dev or
+ spmi-slave-dev in the Root Node.
+
+[First Level Nodes]
 
 Required properites :
 
@@ -22,51 +37,124 @@
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
-Second level
+[Second Level Nodes]
 
 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 that includes device nodes associated with the
+   same slave_id.
  - 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.
 
 Recommended properties :
 
- - interrupts : <a b c> where a is the slave ID, b is is the peripheral ID,
+ - interrupts : <a b c> where a is the slave ID, b is the peripheral ID,
    c is the device interrupt number (0-7). Each device supports any arbitrary
    number of interrupts.
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
-Example:
+Optional properties :
+
+ - spmi-dev-container: This specifies that all the device nodes specified for
+   this slave_id should have their resources coalesced into only one
+   spmi_device.
+
+[Third Level Nodes]
+
+Required properties :
+
+  - spmi-dev-container: This specifies that all the device nodes specified for
+   this slave_id should have their resources coalesced into only one
+   spmi_device.
+  - 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.
+
+Recommended properties :
+
+ - interrupts : <a b c> where a is the slave ID, b is the peripheral ID,
+   c is the device interrupt number (0-7). Each device supports any arbitrary
+   number of interrupts.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+Notes :
+ - It is considered an error to include spmi-slave-dev at this level.
+
+[Example]
 
 / {
-	qcom,spmi@fc4c0000 {
+	qpnp: qcom,spmi@fc4c0000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		interrupt-parent = <&qpnpint>;
-		pmic8941@d {
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		testint@f {
+			interrupt-parent = <&qpnp>;
+			compatible = "qcom,qpnp-testint";
+			reg = <0xf>;
+			interrupts = <0x3 0x15 0x0 0x3 0x15 0x02 0x1 0x47 0x0>;
+
+		};
+
+		pm8941@0 {
+			spmi-slave-container;
+			reg = <0x0>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-			reg = <0xd>;
-			spmi-dev-container;
 
-			coincell@2800 {
-				compatible = "qcom,qpnp-coincell";
-				reg = <0x2800 0x4000>;
-				interrupts = <0xd 0x28 0x6  0xd 0x28 0x3>;
+			pm8941_gpios: gpios {
+				spmi-dev-container;
+				compatible = "qcom,qpnp-gpio";
+				gpio-controller;
+				#gpio-cells = <1>;
+				#address-cells = <1>;
+				#size-cells = <1>;
 
+				pm8941_gpio1@0xc000 {
+					compatible = "qcom,qpnp-gpio";
+					reg = <0xc000 0x100>;
+					qcom,qpnp_gpio = <1>;
+					interrupt-parent = <&qpnp>;
+					interrupts = <0x3 0x15 0x02 0x1 0x47 0x0>;
+				};
+
+				pm8941_gpio2@0xc100 {
+					compatible = "qcom,qpnp-gpio";
+					reg = <0xc100 0x100>;
+					qcom,qpnp_gpio = <2>;
+					interrupt-parent = <&qpnp>;
+					interrupts = <0x3 0x15 0x0>;
+				};
 			};
-			pon@800 {
-				compatible = "qcom,qpnp-pon";
-				reg = <0x800 0x4000>;
+
+			testgpio@0x1000 {
+				compatible = "qcom,qpnp-testgpio";
+				reg = <0x1000 0x1000>;
+				qpnp-gpios = <&pm8941_gpios 0x0>;
 			};
 		};
-		customer_dev@2 {
-			compatible = "qcom,qpnp-pon";
+		pm8841@2 {
+			spmi-slave-container;
 			reg = <0x2>;
-			interrupts = <0x2 0x08 0x1  0x2 0x8 0x3>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			spmi-dev-container;
+			compatible = "qcom,qpnp-gpio";
+
+			pm8841_gpio1@0xc000 {
+				reg = <0xc000 0x100>;
+				qcom,qpnp_gpio = <1>;
+			};
+
+			pm8841_gpio2@0xc100 {
+				reg = <0xc100 0x100>;
+				qcom,qpnp_gpio = <2>;
+			};
 		};
+
 	};
 };
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/hwspinlock.txt b/Documentation/hwspinlock.txt
index 7dcd1a4..6996681 100644
--- a/Documentation/hwspinlock.txt
+++ b/Documentation/hwspinlock.txt
@@ -39,23 +39,20 @@
      in case an unused hwspinlock isn't available. Users of this
      API will usually want to communicate the lock's id to the remote core
      before it can be used to achieve synchronization.
-     Can be called from an atomic context (this function will not sleep) but
-     not from within interrupt context.
+     Should be called from a process context (might sleep).
 
   struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
    - assign a specific hwspinlock id and return its address, or NULL
      if that hwspinlock is already in use. Usually board code will
      be calling this function in order to reserve specific hwspinlock
      ids for predefined purposes.
-     Can be called from an atomic context (this function will not sleep) but
-     not from within interrupt context.
+     Should be called from a process context (might sleep).
 
   int hwspin_lock_free(struct hwspinlock *hwlock);
    - free a previously-assigned hwspinlock; returns 0 on success, or an
      appropriate error code on failure (e.g. -EINVAL if the hwspinlock
      is already free).
-     Can be called from an atomic context (this function will not sleep) but
-     not from within interrupt context.
+     Should be called from a process context (might sleep).
 
   int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);
    - lock a previously-assigned hwspinlock with a timeout limit (specified in
@@ -232,15 +229,14 @@
 
   int hwspin_lock_register(struct hwspinlock *hwlock);
    - to be called from the underlying platform-specific implementation, in
-     order to register a new hwspinlock instance. Can be called from an atomic
-     context (this function will not sleep) but not from within interrupt
-     context. Returns 0 on success, or appropriate error code on failure.
+     order to register a new hwspinlock instance. Should be called from
+     a process context (this function might sleep).
+     Returns 0 on success, or appropriate error code on failure.
 
   struct hwspinlock *hwspin_lock_unregister(unsigned int id);
    - to be called from the underlying vendor-specific implementation, in order
      to unregister an existing (and unused) hwspinlock instance.
-     Can be called from an atomic context (will not sleep) but not from
-     within interrupt context.
+     Should be called from a process context (this function might sleep).
      Returns the address of hwspinlock on success, or NULL on error (e.g.
      if the hwspinlock is sill in use).
 
diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index 93dd7a7..a9ba672 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -4,3 +4,5 @@
         - info on SD and MMC device attributes
 mmc-dev-parts.txt
         - info on SD and MMC device partitions
+mmc-async-req.txt
+        - info on mmc asynchronous requests
diff --git a/Documentation/mmc/mmc-async-req.txt b/Documentation/mmc/mmc-async-req.txt
new file mode 100644
index 0000000..ae1907b
--- /dev/null
+++ b/Documentation/mmc/mmc-async-req.txt
@@ -0,0 +1,87 @@
+Rationale
+=========
+
+How significant is the cache maintenance overhead?
+It depends. Fast eMMC and multiple cache levels with speculative cache
+pre-fetch makes the cache overhead relatively significant. If the DMA
+preparations for the next request are done in parallel with the current
+transfer, the DMA preparation overhead would not affect the MMC performance.
+The intention of non-blocking (asynchronous) MMC requests is to minimize the
+time between when an MMC request ends and another MMC request begins.
+Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
+dma_unmap_sg are processing. Using non-blocking MMC requests makes it
+possible to prepare the caches for next job in parallel with an active
+MMC request.
+
+MMC block driver
+================
+
+The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
+The increase in throughput is proportional to the time it takes to
+prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
+a request and how fast the memory is. The faster the MMC/SD is the
+more significant the prepare request time becomes. Roughly the expected
+performance gain is 5% for large writes and 10% on large reads on a L2 cache
+platform. In power save mode, when clocks run on a lower frequency, the DMA
+preparation may cost even more. As long as these slower preparations are run
+in parallel with the transfer performance won't be affected.
+
+Details on measurements from IOZone and mmc_test
+================================================
+
+https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
+
+MMC core API extension
+======================
+
+There is one new public function mmc_start_req().
+It starts a new MMC command request for a host. The function isn't
+truly non-blocking. If there is an ongoing async request it waits
+for completion of that request and starts the new one and returns. It
+doesn't wait for the new request to complete. If there is no ongoing
+request it starts the new request and returns immediately.
+
+MMC host extensions
+===================
+
+There are two optional members in the mmc_host_ops -- pre_req() and
+post_req() -- that the host driver may implement in order to move work
+to before and after the actual mmc_host_ops.request() function is called.
+In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
+descriptor, and post_req() runs the dma_unmap_sg().
+
+Optimize for the first request
+==============================
+
+The first request in a series of requests can't be prepared in parallel
+with the previous transfer, since there is no previous request.
+The argument is_first_req in pre_req() indicates that there is no previous
+request. The host driver may optimize for this scenario to minimize
+the performance loss. A way to optimize for this is to split the current
+request in two chunks, prepare the first chunk and start the request,
+and finally prepare the second chunk and start the transfer.
+
+Pseudocode to handle is_first_req scenario with minimal prepare overhead:
+
+if (is_first_req && req->size > threshold)
+   /* start MMC transfer for the complete transfer size */
+   mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
+
+   /*
+    * Begin to prepare DMA while cmd is being processed by MMC.
+    * The first chunk of the request should take the same time
+    * to prepare as the "MMC process command time".
+    * If prepare time exceeds MMC cmd time
+    * the transfer is delayed, guesstimate max 4k as first chunk size.
+    */
+    prepare_1st_chunk_for_dma(req);
+    /* flush pending desc to the DMAC (dmaengine.h) */
+    dma_issue_pending(req->dma_desc);
+
+    prepare_2nd_chunk_for_dma(req);
+    /*
+     * The second issue_pending should be called before MMC runs out
+     * of the first chunk. If the MMC runs out of the first data chunk
+     * before this call, the transfer is delayed.
+     */
+    dma_issue_pending(req->dma_desc);
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 22852b3..a6b3430 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -709,6 +709,16 @@
 Similarly, if the power.use_autosuspend field isn't set then the autosuspend
 helper functions will behave just like the non-autosuspend counterparts.
 
+Under some circumstances a driver or subsystem may want to prevent a device
+from autosuspending immediately, even though the usage counter is zero and the
+autosuspend delay time has expired.  If the ->runtime_suspend() callback
+returns -EAGAIN or -EBUSY, and if the next autosuspend delay expiration time is
+in the future (as it normally would be if the callback invoked
+pm_runtime_mark_last_busy()), the PM core will automatically reschedule the
+autosuspend.  The ->runtime_suspend() callback can't do this rescheduling
+itself because no suspend requests of any kind are accepted while the device is
+suspending (i.e., while the callback is running).
+
 The implementation is well suited for asynchronous use in interrupt contexts.
 However such use inevitably involves races, because the PM core can't
 synchronize ->runtime_suspend() callbacks with the arrival of I/O requests.
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index e213f45..21fd05c 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -24,10 +24,10 @@
 Procedure for submitting patches to the -stable tree:
 
  - Send the patch, after verifying that it follows the above rules, to
-   stable@kernel.org.  You must note the upstream commit ID in the changelog
-   of your submission.
+   stable@vger.kernel.org.  You must note the upstream commit ID in the
+   changelog of your submission.
  - To have the patch automatically included in the stable tree, add the tag
-     Cc: stable@kernel.org
+     Cc: stable@vger.kernel.org
    in the sign-off area. Once the patch is merged it will be applied to
    the stable tree without anything else needing to be done by the author
    or subsystem maintainer.
@@ -35,10 +35,10 @@
    cherry-picked than this can be specified in the following format in
    the sign-off area:
 
-     Cc: <stable@kernel.org> # .32.x: a1f84a3: sched: Check for idle
-     Cc: <stable@kernel.org> # .32.x: 1b9508f: sched: Rate-limit newidle
-     Cc: <stable@kernel.org> # .32.x: fd21073: sched: Fix affinity logic
-     Cc: <stable@kernel.org> # .32.x
+     Cc: <stable@vger.kernel.org> # .32.x: a1f84a3: sched: Check for idle
+     Cc: <stable@vger.kernel.org> # .32.x: 1b9508f: sched: Rate-limit newidle
+     Cc: <stable@vger.kernel.org> # .32.x: fd21073: sched: Fix affinity logic
+     Cc: <stable@vger.kernel.org> # .32.x
     Signed-off-by: Ingo Molnar <mingo@elte.hu>
 
    The tag sequence has the meaning of:
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/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index a4efa04..5335fa8 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -47,10 +47,11 @@
 
 2. Find which bus connects to the desired device
 
-Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
-the device. Usually you do it by looking for the vendor string. If you have
-many similar devices, unplug one and compare two /proc/bus/usb/devices outputs.
-The T-line will have a bus number. Example:
+Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds
+to the device. Usually you do it by looking for the vendor string. If you have
+many similar devices, unplug one and compare the two
+/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number.
+Example:
 
 T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
 D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
@@ -58,7 +59,10 @@
 S:  Manufacturer=ATEN
 S:  Product=UC100KM V2.00
 
-Bus=03 means it's bus 3.
+"Bus=03" means it's bus 3. Alternatively, you can look at the output from
+"lsusb" and get the bus number from the appropriate line. Example:
+
+Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00
 
 3. Start 'cat'
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 187282d..de85391 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1221,7 +1221,7 @@
 F:	drivers/block/aoe/
 
 ATHEROS ATH GENERIC UTILITIES
-M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
+M:	"Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
 L:	linux-wireless@vger.kernel.org
 S:	Supported
 F:	drivers/net/wireless/ath/*
@@ -1229,7 +1229,7 @@
 ATHEROS ATH5K WIRELESS DRIVER
 M:	Jiri Slaby <jirislaby@gmail.com>
 M:	Nick Kossifidis <mickflemm@gmail.com>
-M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
+M:	"Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
 M:	Bob Copeland <me@bobcopeland.com>
 L:	linux-wireless@vger.kernel.org
 L:	ath5k-devel@lists.ath5k.org
@@ -1238,10 +1238,10 @@
 F:	drivers/net/wireless/ath/ath5k/
 
 ATHEROS ATH9K WIRELESS DRIVER
-M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
-M:	Jouni Malinen <jmalinen@atheros.com>
-M:	Vasanthakumar Thiagarajan <vasanth@atheros.com>
-M:	Senthil Balasubramanian <senthilkumar@atheros.com>
+M:	"Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
+M:	Jouni Malinen <jouni@qca.qualcomm.com>
+M:	Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
+M:	Senthil Balasubramanian <senthilb@qca.qualcomm.com>
 L:	linux-wireless@vger.kernel.org
 L:	ath9k-devel@lists.ath9k.org
 W:	http://wireless.kernel.org/en/users/Drivers/ath9k
@@ -1269,7 +1269,7 @@
 ATLX ETHERNET DRIVERS
 M:	Jay Cliburn <jcliburn@gmail.com>
 M:	Chris Snook <chris.snook@gmail.com>
-M:	Jie Yang <jie.yang@atheros.com>
+M:	Jie Yang <yangjie@qca.qualcomm.com>
 L:	netdev@vger.kernel.org
 W:	http://sourceforge.net/projects/atl1
 W:	http://atl1.sourceforge.net
@@ -6039,7 +6039,7 @@
 
 STABLE BRANCH
 M:	Greg Kroah-Hartman <greg@kroah.com>
-L:	stable@kernel.org
+L:	stable@vger.kernel.org
 S:	Maintained
 
 STAGING SUBSYSTEM
diff --git a/Makefile b/Makefile
index 535dfae..393d745 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 3
 PATCHLEVEL = 0
-SUBLEVEL = 8
+SUBLEVEL = 21
 EXTRAVERSION =
 NAME = Sneaky Weasel
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0a7fe5f..308f984 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
@@ -645,6 +645,7 @@
 	select GENERIC_TIME
 	select GENERIC_ALLOCATOR
 	select HAVE_SCHED_CLOCK
+	select HAVE_CLK_PREPARE
 	help
 	  Support for Qualcomm MSM/QSD based systems.  This runs on the
 	  apps processor of the MSM/QSD and depends on a shared memory
@@ -1362,6 +1363,18 @@
 	  relevant cache maintenance functions and sets a specific bit
 	  in the diagnostic control register of the SCU.
 
+config PL310_ERRATA_769419
+	bool "PL310 errata: no automatic Store Buffer drain"
+	depends on CACHE_L2X0
+	help
+	  On revisions of the PL310 prior to r3p2, the Store Buffer does
+	  not automatically drain. This can cause normal, non-cacheable
+	  writes to be retained when the memory system is idle, leading
+	  to suboptimal I/O performance for drivers using coherent DMA.
+	  This option adds a write barrier to the cpu_idle loop so that,
+	  on systems with an outer cache, the store buffer is drained
+	  explicitly.
+
 endmenu
 
 menu "Kernel Features"
@@ -1416,6 +1429,7 @@
 
 config ARM_ARCH_TIMER
 	bool "Architected timer support"
+	depends on CPU_V7
 	select TICK_ONESHOT
 	help
 	  This option enables support for the ARM architected timer
@@ -1620,19 +1634,18 @@
 
 config ARCH_MEMORY_PROBE
 	def_bool n
-	depends on MEMORY_HOTPLUG
 
 config ARCH_MEMORY_REMOVE
 	def_bool n
-	depends on MEMORY_HOTPLUG
 
 config ARCH_POPULATES_NODE_MAP
 	def_bool n
-	depends on MEMORY_HOTPLUG
+
+config ENABLE_DMM
+	def_bool n
 
 config FIX_MOVABLE_ZONE
 	def_bool n
-	depends on MEMORY_HOTPLUG
 
 config DONT_MAP_HOLE_AFTER_MEMBANK0
 	def_bool n
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
new file mode 100644
index 0000000..bb53ff8
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -0,0 +1,60 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msmcopper.dtsi"
+
+/ {
+	model = "Qualcomm MSM Copper RUMI";
+	compatible = "qcom,msmcopper-rumi", "qcom,msmcopper";
+
+	timer {
+		clock-frequency = <5000000>;
+	};
+
+	serial@f991f000 {
+		status = "disable";
+	};
+
+	usb@f9a55000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f980b000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f984b000 {
+		status = "disable";
+	};
+
+	qcom,sps@f998000 {
+		status = "disable";
+	};
+
+	spi@f9924000 {
+		status = "disable";
+	};
+
+	slim@fe12f000 {
+		status = "disable";
+	};
+
+	qcom,spmi@fc4c0000 {
+		status = "disable";
+	};
+
+	i2c@f9966000 {
+		status = "disable";
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-sim.dts b/arch/arm/boot/dts/msmcopper-sim.dts
new file mode 100644
index 0000000..ab6b8ba
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-sim.dts
@@ -0,0 +1,20 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msmcopper.dtsi"
+
+/ {
+	model = "Qualcomm MSM Copper Simulator";
+	compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
+};
diff --git a/arch/arm/boot/dts/msmcopper.dts b/arch/arm/boot/dts/msmcopper.dts
deleted file mode 100644
index 725971d..0000000
--- a/arch/arm/boot/dts/msmcopper.dts
+++ /dev/null
@@ -1,186 +0,0 @@
-/dts-v1/;
-
-/include/ "skeleton.dtsi"
-
-/ {
-	model = "Qualcomm MSM Copper";
-	compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
-	interrupt-parent = <&intc>;
-
-	intc: interrupt-controller@F9000000 {
-		compatible = "qcom,msm-qgic2";
-		interrupt-controller;
-		#interrupt-cells = <3>;
-		reg = <0xF9000000 0x1000>,
-		      <0xF9002000 0x1000>;
-	};
-
-	msmgpio: gpio@fd400000 {
-		compatible = "qcom,msm-gpio";
-		interrupt-controller;
-		#interrupt-cells = <2>;
-		reg = <0xfd400000 0x4000>;
-	};
-
-	timer {
-		compatible = "qcom,msm-qtimer";
-		interrupts = <1 2 0>;
-	};
-
-	serial@f991f000 {
-		compatible = "qcom,msm-lsuart-v14";
-		reg = <0xf991f000 0x1000>;
-		interrupts = <0 109 0>;
-	};
-
-	usb@f9a55000 {
-		compatible = "qcom,hsusb-otg";
-		reg = <0xf9a55000 0x400>;
-		interrupts = <0 134 0>;
-
-		qcom,hsusb-otg-phy-type = <2>;
-		qcom,hsusb-otg-mode = <1>;
-		qcom,hsusb-otg-otg-control = <1>;
-	};
-
-	qcom,sdcc@f980b000 {
-		cell-index = <1>;
-		compatible = "qcom,msm-sdcc";
-		reg = <0xf980b000 0x1000>;
-		interrupts = <0 123 0>;
-
-		qcom,sdcc-clk-rates = <400000 24000000 48000000>;
-		qcom,sdcc-sup-voltages = <3300 3300>;
-		qcom,sdcc-bus-width = <8>;
-		qcom,sdcc-nonremovable;
-		qcom,sdcc-disable_cmd23;
-	};
-
-	qcom,sdcc@f984b000 {
-		cell-index = <3>;
-		compatible = "qcom,msm-sdcc";
-		reg = <0xf984b000 0x1000>;
-		interrupts = <0 127 0>;
-
-		qcom,sdcc-clk-rates = <400000 24000000 48000000>;
-		qcom,sdcc-sup-voltages = <3300 3300>;
-		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-disable_cmd23;
-	};
-
-	qcom,sps@f9980000 {
-		compatible = "qcom,msm_sps";
-		reg = <0xf9984000 0x15000>,
-		      <0xf9999000 0xb000>;
-		interrupts = <0 94 0>;
-
-		qcom,bam-dma-res-pipes = <6>;
-	};
-
-	spi@f9924000 {
-		compatible = "qcom,spi-qup-v2";
-		reg = <0xf9924000 0x1000>;
-		interrupts = <96>;
-		spi-max-frequency = <24000000>;
-	};
-
-	qcom,spmi@fc4c0000 {
-		cell-index = <0>;
-		compatible = "qcom,spmi-pmic-arb";
-		reg = <0xfc4cf000 0x1000>,
-		      <0Xfc4cb000 0x1000>;
-		/* 190,ee0_krait_hlos_spmi_periph_irq */
-		/* 187,channel_0_krait_hlos_trans_done_irq */
-		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 */
-	};
-};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
new file mode 100644
index 0000000..314748c
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -0,0 +1,233 @@
+/* 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/ "skeleton.dtsi"
+
+/ {
+	model = "Qualcomm MSM Copper";
+	compatible = "qcom,msmcopper";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@F9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xF9000000 0x1000>,
+		      <0xF9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd400000 {
+		compatible = "qcom,msm-gpio";
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd400000 0x4000>;
+	};
+
+	timer {
+		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		interrupts = <1 2 0>;
+		clock-frequency = <19200000>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+	};
+
+	serial@f995e000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf995e000 0x1000>;
+		interrupts = <0 114 0>;
+	};
+
+	usb@f9a55000 {
+		compatible = "qcom,hsusb-otg";
+		reg = <0xf9a55000 0x400>;
+		interrupts = <0 134 0>;
+
+		qcom,hsusb-otg-phy-type = <2>;
+		qcom,hsusb-otg-mode = <1>;
+		qcom,hsusb-otg-otg-control = <1>;
+	};
+
+	qcom,sdcc@f980b000 {
+		cell-index = <1>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf980b000 0x1000>;
+		interrupts = <0 123 0>;
+
+		qcom,sdcc-clk-rates = <400000 24000000 48000000 96000000 192000000>;
+		qcom,sdcc-sup-voltages = <3300 3300>;
+		qcom,sdcc-bus-width = <8>;
+		qcom,sdcc-hs200;
+		qcom,sdcc-nonremovable;
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f984b000 {
+		cell-index = <3>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf984b000 0x1000>;
+		interrupts = <0 127 0>;
+
+		qcom,sdcc-clk-rates = <400000 24000000 48000000>;
+		qcom,sdcc-sup-voltages = <3300 3300>;
+		qcom,sdcc-bus-width = <4>;
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sps@f9980000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>;
+		interrupts = <0 94 0>;
+
+		qcom,bam-dma-res-pipes = <6>;
+	};
+
+	spi@f9924000 {
+		compatible = "qcom,spi-qup-v2";
+		reg = <0xf9924000 0x1000>;
+		interrupts = <0 96 0>;
+		spi-max-frequency = <24000000>;
+	};
+
+	slim@fe12f000 {
+		cell-index = <1>;
+		compatible = "qcom,slim-msm";
+		reg = <0xfe12f000 0x35000>,
+		      <0xfe104000 0x20000>;
+		reg-names = "slimbus_physical", "slimbus_bam_physical";
+		interrupts = <0 163 0 0 164 0>;
+		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+		qcom,min-clk-gear = <10>;
+	};
+
+	qcom,spmi@fc4c0000 {
+		cell-index = <0>;
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>;
+		/* 190,ee0_krait_hlos_spmi_periph_irq */
+		/* 187,channel_0_krait_hlos_trans_done_irq */
+		interrupts = <0 190 0 0 187 0>;
+		qcom,pmic-arb-ee = <0>;
+		qcom,pmic-arb-channel = <0>;
+		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 */
+	};
+
+	i2c@f9966000 {
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0Xf9966000 0x1000>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 104 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+	};
+
+	qcom,acpuclk@0xf900000 {
+		compatible = "qcom,acpuclk-copper";
+	};
+};
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 64877d1..b6570c7 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -6,6 +6,10 @@
 config GIC_NON_BANKED
 	bool
 
+config GIC_SECURE
+	bool
+	depends on ARM_GIC
+
 config ARM_VIC
 	bool
 
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index bb4d971..4e43cb2 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -156,7 +156,7 @@
 	return d->hwirq;
 }
 
-#ifdef CONFIG_CPU_V7
+#if defined(CONFIG_CPU_V7) && defined(CONFIG_GIC_SECURE)
 static const inline bool is_cpu_secure(void)
 {
 	unsigned int dscr;
diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig
index 227a477..d95763d 100644
--- a/arch/arm/configs/ezx_defconfig
+++ b/arch/arm/configs/ezx_defconfig
@@ -287,7 +287,7 @@
 # CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_PXA27X=y
+CONFIG_USB_PXA27X=y
 CONFIG_USB_ETH=m
 # CONFIG_USB_ETH_RNDIS is not set
 CONFIG_MMC=y
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 3d4b37d..1d0584e 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -8,6 +8,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
 # CONFIG_PERF_EVENTS is not set
@@ -34,7 +35,7 @@
 # CONFIG_MSM_HW3D is not set
 # CONFIG_QSD_AUDIO is not set
 # CONFIG_SURF_FFA_GPIO_KEYPAD is not set
-CONFIG_MSM_JTAG=y
+CONFIG_MSM_WATCHDOG=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_VMSPLIT_2G=y
@@ -114,7 +115,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..b3e5b87 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -8,6 +8,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
@@ -33,6 +34,7 @@
 # CONFIG_MSM_HW3D is not set
 # CONFIG_QSD_AUDIO is not set
 # CONFIG_SURF_FFA_GPIO_KEYPAD is not set
+CONFIG_MSM_WATCHDOG=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_VMSPLIT_2G=y
@@ -112,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/imote2_defconfig b/arch/arm/configs/imote2_defconfig
index 176ec22..fd996bb 100644
--- a/arch/arm/configs/imote2_defconfig
+++ b/arch/arm/configs/imote2_defconfig
@@ -263,7 +263,7 @@
 # CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_PXA27X=y
+CONFIG_USB_PXA27X=y
 CONFIG_USB_ETH=m
 # CONFIG_USB_ETH_RNDIS is not set
 CONFIG_MMC=y
diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig
index a88e64d..443675d 100644
--- a/arch/arm/configs/magician_defconfig
+++ b/arch/arm/configs/magician_defconfig
@@ -132,7 +132,7 @@
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
-CONFIG_USB_GADGET_PXA27X=y
+CONFIG_USB_PXA27X=y
 CONFIG_USB_ETH=m
 # CONFIG_USB_ETH_RNDIS is not set
 CONFIG_USB_GADGETFS=m
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 8a505cc..64cba23 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
@@ -90,21 +94,36 @@
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS=y
+CONFIG_SLIMBUS_MSM_CTRL=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
 # CONFIG_HWMON is not set
 # CONFIG_MFD_SUPPORT is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
 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
+CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
diff --git a/arch/arm/configs/msm7627-perf_defconfig b/arch/arm/configs/msm7627-perf_defconfig
deleted file mode 100644
index ea5c7c9..0000000
--- a/arch/arm/configs/msm7627-perf_defconfig
+++ /dev/null
@@ -1,306 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-perf"
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_ASHMEM=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X27=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM7X00A_USE_DG_TIMER=y
-# CONFIG_MSM_FIQ_SUPPORT is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_MSM_HW3D is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_VFP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_WAKELOCK=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_LOG=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_LOG=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_CLS_U32=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_BT_MSM_SLEEP=y
-CONFIG_MSM_BT_POWER=y
-# CONFIG_WIRELESS_EXT_SYSFS is not set
-CONFIG_RFKILL=y
-# CONFIG_RFKILL_PM is not set
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_MISC_DEVICES=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_LIBRA_SDIOIF=m
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM_LEGACY=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_KEYCHORD=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-# CONFIG_HWMON is not set
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_VIDEO_DEV=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP30=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM_SOC=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA12_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA12"
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627_defconfig b/arch/arm/configs/msm7627_defconfig
deleted file mode 100644
index 0841f7e..0000000
--- a/arch/arm/configs/msm7627_defconfig
+++ /dev/null
@@ -1,311 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_ASHMEM=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X27=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM7X00A_USE_DG_TIMER=y
-# CONFIG_MSM_FIQ_SUPPORT is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_MSM_HW3D is not set
-CONFIG_STRICT_MEMORY_RWX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_VFP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_WAKELOCK=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_LOG=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_LOG=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_CLS_U32=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_BT_MSM_SLEEP=y
-CONFIG_MSM_BT_POWER=y
-# CONFIG_WIRELESS_EXT_SYSFS is not set
-CONFIG_RFKILL=y
-# CONFIG_RFKILL_PM is not set
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_MISC_DEVICES=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_LIBRA_SDIOIF=m
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM_LEGACY=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_KEYCHORD=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-# CONFIG_HWMON is not set
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP30=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM_SOC=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA12_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA12"
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_DETECT_HUNG_TASK=y
-CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LIST=y
-CONFIG_LATENCYTOP=y
-CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index dd8cb16..5b55f99 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
@@ -49,6 +50,7 @@
 CONFIG_BT_MSM_PINTEST=y
 CONFIG_MSM_RPC_VIBRATOR=y
 CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -56,6 +58,7 @@
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0xC800000
 CONFIG_CP_ACCESS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
@@ -166,7 +169,7 @@
 CONFIG_BT_HCIUART_IBS=y
 CONFIG_BT_MSM_SLEEP=y
 CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=y
+CONFIG_CFG80211=m
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
@@ -205,6 +208,7 @@
 CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y
+CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=y
@@ -228,20 +232,22 @@
 # CONFIG_HWMON is not set
 CONFIG_MARIMBA_CORE=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
-# CONFIG_MT9T013 is not set
-# CONFIG_MT9D112 is not set
-CONFIG_OV5640=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_OV5647=y
+CONFIG_AD5046_ACT=y
 CONFIG_WEBCAM_OV7692_QRD=y
 CONFIG_WEBCAM_OV9726=y
-# CONFIG_MT9P012 is not set
-# CONFIG_MT9P012_KM is not set
 CONFIG_MT9E013=y
-# CONFIG_S5K3E2FX is not set
 CONFIG_S5K4E1=y
+CONFIG_DW9712_ACT=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
-CONFIG_IMX072=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
 CONFIG_RADIO_TAVARUA=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
@@ -250,6 +256,7 @@
 CONFIG_FB_MSM_TRIPLE_BUFFER=y
 CONFIG_FB_MSM_MDP30=y
 CONFIG_FB_MSM_MDP303=y
+CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL=y
 CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -283,7 +290,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_MSM_72K=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
@@ -326,18 +333,15 @@
 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
-CONFIG_EARLY_PRINTK=y
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 199b91f..7f9c54d 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,11 +46,11 @@
 # 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
 CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -57,6 +58,7 @@
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0xC800000
 CONFIG_CP_ACCESS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
@@ -167,7 +169,7 @@
 CONFIG_BT_HCIUART_IBS=y
 CONFIG_BT_MSM_SLEEP=y
 CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=y
+CONFIG_CFG80211=m
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
@@ -206,6 +208,7 @@
 CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y
+CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=y
@@ -230,19 +233,22 @@
 # CONFIG_HWMON is not set
 CONFIG_MARIMBA_CORE=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
-# CONFIG_MT9T013 is not set
-# CONFIG_MT9D112 is not set
-CONFIG_OV5640=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_OV5647=y
+CONFIG_AD5046_ACT=y
 CONFIG_WEBCAM_OV7692_QRD=y
 CONFIG_WEBCAM_OV9726=y
-# CONFIG_MT9P012 is not set
-# CONFIG_MT9P012_KM is not set
 CONFIG_MT9E013=y
-# CONFIG_S5K3E2FX is not set
 CONFIG_S5K4E1=y
+CONFIG_DW9712_ACT=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
-CONFIG_IMX072=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
 CONFIG_RADIO_TAVARUA=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
@@ -251,6 +257,7 @@
 CONFIG_FB_MSM_TRIPLE_BUFFER=y
 CONFIG_FB_MSM_MDP30=y
 CONFIG_FB_MSM_MDP303=y
+CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL=y
 CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -284,7 +291,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_MSM_72K=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
@@ -326,12 +333,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
@@ -341,14 +347,10 @@
 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
-CONFIG_EARLY_PRINTK=y
 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..3ee4132 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -40,12 +40,13 @@
 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
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x1A000000
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
@@ -223,7 +224,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
@@ -293,6 +293,9 @@
 CONFIG_SND_SOC=y
 CONFIG_SND_MSM7KV2_SOC=y
 CONFIG_SND_MVS_SOC=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
@@ -316,7 +319,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_MSM_72K=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
@@ -329,6 +332,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index b4babeb..1e037ea 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -40,13 +40,14 @@
 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
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x1A000000
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
@@ -224,7 +225,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
@@ -318,7 +318,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_MSM_72K=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
@@ -331,6 +331,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
@@ -371,7 +372,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 +380,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..8c2e3a6 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -65,12 +65,12 @@
 CONFIG_MSM_PIL_MODEM=y
 CONFIG_MSM_PIL_QDSP6V3=y
 CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 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
@@ -235,7 +235,7 @@
 CONFIG_PMIC8XXX_VIBRATOR=y
 CONFIG_PMIC8XXX_UPL=y
 CONFIG_PMIC8058_XOADC=y
-CONFIG_TZCOM=y
+CONFIG_QSEECOM=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -272,7 +272,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
@@ -376,7 +374,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_MSM_72K=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
@@ -388,6 +386,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 1f511bb..0e83888 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -64,6 +64,7 @@
 CONFIG_MSM_PIL_MODEM=y
 CONFIG_MSM_PIL_QDSP6V3=y
 CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -233,7 +234,7 @@
 CONFIG_PMIC8XXX_VIBRATOR=y
 CONFIG_PMIC8XXX_UPL=y
 CONFIG_PMIC8058_XOADC=y
-CONFIG_TZCOM=y
+CONFIG_QSEECOM=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -271,7 +272,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 +299,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 +323,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
@@ -376,7 +375,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_MSM_72K=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
@@ -388,6 +387,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f1b1fa5..1bd3c56 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -9,7 +9,6 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_SCHED=y
-# CONFIG_FAIR_GROUP_SCHED is not set
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
@@ -53,6 +52,7 @@
 CONFIG_MACH_APQ8064_CDP=y
 CONFIG_MACH_APQ8064_MTP=y
 CONFIG_MACH_APQ8064_LIQUID=y
+CONFIG_MACH_MPQ8064_CDP=y
 CONFIG_MACH_MPQ8064_HRD=y
 CONFIG_MACH_MPQ8064_DTV=y
 # CONFIG_MSM_STACKED_MEMORY is not set
@@ -69,11 +69,13 @@
 CONFIG_MSM_PIL_QDSP6V4=y
 CONFIG_MSM_PIL_RIVA=y
 CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
 CONFIG_MSM_PIL_GSS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_MODEM_8960=y
 CONFIG_MSM_LPASS_8960=y
 CONFIG_MSM_WCNSS_SSR_8960=y
+CONFIG_MSM_GSS_SSR_8064=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -84,6 +86,9 @@
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_QDSS=y
 CONFIG_MSM_SLEEP_STATS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_DCVS=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -191,8 +196,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 +234,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
@@ -290,9 +297,11 @@
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
 CONFIG_ISL9519_CHARGER=y
+CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
 CONFIG_PM8921_BMS=y
 CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_SENSORS_EPM_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_THERMAL_PM8XXX=y
@@ -301,24 +310,28 @@
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 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_IMX091=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -335,9 +348,9 @@
 CONFIG_FB_MSM_OVERLAY=y
 CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
 CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
 CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
-CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_SOUND=y
@@ -351,7 +364,6 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
@@ -374,12 +386,13 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_CI13XXX_MSM=y
+CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y
 CONFIG_MMC=y
@@ -389,6 +402,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
 CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index e58b94b..69806d0 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -8,7 +8,6 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_SCHED=y
-# CONFIG_FAIR_GROUP_SCHED is not set
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
@@ -52,6 +51,7 @@
 CONFIG_MACH_APQ8064_CDP=y
 CONFIG_MACH_APQ8064_MTP=y
 CONFIG_MACH_APQ8064_LIQUID=y
+CONFIG_MACH_MPQ8064_CDP=y
 CONFIG_MACH_MPQ8064_HRD=y
 CONFIG_MACH_MPQ8064_DTV=y
 # CONFIG_MSM_STACKED_MEMORY is not set
@@ -68,11 +68,13 @@
 CONFIG_MSM_PIL_QDSP6V4=y
 CONFIG_MSM_PIL_RIVA=y
 CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
 CONFIG_MSM_PIL_GSS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_MODEM_8960=y
 CONFIG_MSM_LPASS_8960=y
 CONFIG_MSM_WCNSS_SSR_8960=y
+CONFIG_MSM_GSS_SSR_8064=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -86,6 +88,13 @@
 CONFIG_MSM_SLEEP_STATS=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_DCVS=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -193,8 +202,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 +240,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
@@ -292,9 +303,11 @@
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
 CONFIG_ISL9519_CHARGER=y
+CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
 CONFIG_PM8921_BMS=y
 CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_SENSORS_EPM_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_THERMAL_PM8XXX=y
@@ -303,24 +316,28 @@
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 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_IMX091=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -353,7 +370,6 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
@@ -376,12 +392,13 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_CI13XXX_MSM=y
+CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y
 CONFIG_MMC=y
@@ -391,6 +408,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
 CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 7ba17e6..70cba0f 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
@@ -190,7 +191,6 @@
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
-CONFIG_SLIMBUS=y
 CONFIG_SLIMBUS_MSM_CTRL=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
@@ -199,9 +199,17 @@
 CONFIG_SENSORS_PM8XXX_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
+CONFIG_THERMAL_PM8XXX=y
 CONFIG_MFD_PM8018_CORE=y
+CONFIG_WCD9310_CODEC=y
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MDM9615=y
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -223,7 +231,8 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_CI13XXX_MSM=y
+CONFIG_USB_CI13XXX_MSM=m
+CONFIG_USB_CI13XXX_MSM_HSIC=m
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
@@ -234,6 +243,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/zeus_defconfig b/arch/arm/configs/zeus_defconfig
index 59577ad..547a3c1 100644
--- a/arch/arm/configs/zeus_defconfig
+++ b/arch/arm/configs/zeus_defconfig
@@ -140,7 +140,7 @@
 CONFIG_USB_SERIAL_GENERIC=y
 CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_GADGET=m
-CONFIG_USB_GADGET_PXA27X=y
+CONFIG_USB_PXA27X=y
 CONFIG_USB_ETH=m
 CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index e82217f..2098288 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -1,8 +1,25 @@
 #ifndef __ASMARM_ARCH_TIMER_H
 #define __ASMARM_ARCH_TIMER_H
 
-struct resource;
+#include <linux/ioport.h>
 
-int arch_timer_register(struct resource *res, int res_nr);
+struct arch_timer {
+	struct resource	res[2];
+};
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+int arch_timer_register(struct arch_timer *);
+int arch_timer_of_register(void);
+#else
+static inline int arch_timer_register(struct arch_timer *at)
+{
+	return -ENXIO;
+}
+
+static inline int arch_timer_of_register(void)
+{
+	return -ENXIO;
+}
+#endif
 
 #endif
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/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 49106e1..fad6d09 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -47,6 +47,15 @@
 #define L2X0_CLEAN_INV_WAY		0x7FC
 #define L2X0_LOCKDOWN_WAY_D		0x900
 #define L2X0_LOCKDOWN_WAY_I		0x904
+/*
+ * The lockdown registers repeat 8 times for L310, the L210 has only one
+ * D and one I lockdown register at 0x0900 and 0x0904.
+ */
+#define L2X0_LOCKDOWN_WAY_D_BASE	0x900
+#define L2X0_LOCKDOWN_WAY_I_BASE	0x904
+#define L2X0_LOCKDOWN_STRIDE		0x08
+#define L2X0_ADDR_FILTER_START		0xC00
+#define L2X0_ADDR_FILTER_END		0xC04
 #define L2X0_TEST_OPERATION		0xF00
 #define L2X0_LINE_DATA			0xF10
 #define L2X0_LINE_TAG			0xF30
@@ -64,6 +73,14 @@
 #define L2X0_CACHE_ID_PART_L310		(3 << 6)
 
 #define L2X0_AUX_CTRL_MASK			0xc0000fff
+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT	0
+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK	0x7
+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT	3
+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK	(0x7 << 3)
+#define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT		6
+#define L2X0_AUX_CTRL_TAG_LATENCY_MASK		(0x7 << 6)
+#define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT	9
+#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK	(0x7 << 9)
 #define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT	16
 #define L2X0_AUX_CTRL_WAY_SIZE_SHIFT		17
 #define L2X0_AUX_CTRL_WAY_SIZE_MASK		(0x7 << 17)
@@ -75,13 +92,18 @@
 #define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT		30
 #define L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT	20
 
-#define REV_PL310_R2P0				4
+#define L2X0_LATENCY_CTRL_SETUP_SHIFT	0
+#define L2X0_LATENCY_CTRL_RD_SHIFT	4
+#define L2X0_LATENCY_CTRL_WR_SHIFT	8
+
+#define L2X0_ADDR_FILTER_EN		1
 
 #ifndef __ASSEMBLY__
 extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
 extern void l2x0_suspend(void);
 extern void l2x0_resume(int collapsed);
 extern void l2x0_cache_sync(void);
+extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask);
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 5bb5139..5668e75 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -50,8 +50,11 @@
 void gic_enable_ppi(unsigned int);
 bool gic_is_spi_pending(unsigned int irq);
 void gic_clear_spi_pending(unsigned int irq);
+#ifdef CONFIG_ARM_GIC
 void gic_set_irq_secure(unsigned int irq);
-
+#else
+static inline void gic_set_irq_secure(unsigned int irq) { }
+#endif
 static inline void gic_init(unsigned int nr, int start,
 			    void __iomem *dist , void __iomem *cpu)
 {
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index f5e1cec..551da73 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -14,6 +14,11 @@
 
 struct clock_event_device;
 
+struct local_timer_ops {
+	int  (*setup)(struct clock_event_device *);
+	void (*stop)(struct clock_event_device *);
+};
+
 /*
  * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
  */
@@ -41,6 +46,11 @@
  */
 int local_timer_setup(struct clock_event_device *);
 
+/*
+ * Register a local timer driver
+ */
+int local_timer_register(struct local_timer_ops *);
+
 #else
 
 static inline int local_timer_setup(struct clock_event_device *evt)
@@ -51,6 +61,11 @@
 static inline void local_timer_stop(struct clock_event_device *evt)
 {
 }
+
+static inline int local_timer_register(struct local_timer_ops *ops)
+{
+	return -ENXIO;
+}
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 4dccb04..31c5f5f 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -92,7 +92,6 @@
 #define xchg(ptr,x) \
 	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
-extern asmlinkage void __backtrace(void);
 extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
 
 struct mm_struct;
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 5070470..8c5b581 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -18,19 +18,21 @@
 #include <linux/jiffies.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
+#include <linux/of_irq.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 
 #include <asm/cputype.h>
+#include <asm/localtimer.h>
+#include <asm/arch_timer.h>
 #include <asm/sched_clock.h>
-#include <asm/hardware/gic.h>
 
 static unsigned long arch_timer_rate;
 static int arch_timer_ppi;
 static int arch_timer_ppi2;
 static DEFINE_CLOCK_DATA(cd);
 
-static struct clock_event_device __percpu *arch_timer_evt;
+static struct clock_event_device __percpu **arch_timer_evt;
 
 /*
  * Architected system timer support.
@@ -38,6 +40,7 @@
 
 #define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
 #define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
+#define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
 
 #define ARCH_TIMER_REG_CTRL		0
 #define ARCH_TIMER_REG_FREQ		1
@@ -84,10 +87,10 @@
 	unsigned long ctrl;
 
 	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
-	if (ctrl & 0x4) {
+	if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
 		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
 		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-		evt = per_cpu_ptr(arch_timer_evt, smp_processor_id());
+		evt = *__this_cpu_ptr(arch_timer_evt);
 		evt->event_handler(evt);
 		return IRQ_HANDLED;
 	}
@@ -95,7 +98,7 @@
 	return IRQ_NONE;
 }
 
-static void arch_timer_stop(void)
+static void arch_timer_disable(void)
 {
 	unsigned long ctrl;
 
@@ -110,7 +113,7 @@
 	switch (mode) {
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
-		arch_timer_stop();
+		arch_timer_disable();
 		break;
 	default:
 		break;
@@ -132,12 +135,14 @@
 	return 0;
 }
 
-static void __cpuinit arch_timer_setup(void *data)
+static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
 {
-	struct clock_event_device *clk = data;
+	/* setup clock event only once for CPU 0 */
+	if (!smp_processor_id() && clk->irq == arch_timer_ppi)
+		return 0;
 
 	/* Be safe... */
-	arch_timer_stop();
+	arch_timer_disable();
 
 	clk->features = CLOCK_EVT_FEAT_ONESHOT;
 	clk->name = "arch_sys_timer";
@@ -145,14 +150,17 @@
 	clk->set_mode = arch_timer_set_mode;
 	clk->set_next_event = arch_timer_set_next_event;
 	clk->irq = arch_timer_ppi;
-	clk->cpumask = cpumask_of(smp_processor_id());
 
 	clockevents_config_and_register(clk, arch_timer_rate,
 					0xf, 0x7fffffff);
 
-	enable_percpu_irq(arch_timer_ppi, 0);
-	if (arch_timer_ppi2 > 0)
+	*__this_cpu_ptr(arch_timer_evt) = clk;
+
+	enable_percpu_irq(clk->irq, 0);
+	if (arch_timer_ppi2)
 		enable_percpu_irq(arch_timer_ppi2, 0);
+
+	return 0;
 }
 
 /* Is the optional system timer available? */
@@ -181,7 +189,7 @@
 
 		arch_timer_rate = freq;
 		pr_info("Architected local timer running at %lu.%02luMHz.\n",
-			arch_timer_rate / 1000000, (arch_timer_rate % 100000) / 100);
+			freq / 1000000, (freq / 10000) % 100);
 	}
 
 	return 0;
@@ -193,7 +201,7 @@
 
 	asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
 
-	return ((u64) cvalh << 32) | cvall;
+	return ((cycle_t) cvalh << 32) | cvall;
 }
 
 static inline cycle_t arch_counter_get_cntvct(void)
@@ -202,7 +210,7 @@
 
 	asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
 
-	return ((u64) cvalh << 32) | cvall;
+	return ((cycle_t) cvalh << 32) | cvall;
 }
 
 static cycle_t arch_counter_read(struct clocksource *cs)
@@ -250,61 +258,33 @@
 	update_sched_clock(&cd, arch_counter_get_cntvct32(), (u32)~0);
 }
 
-static void __cpuinit arch_timer_teardown(void *data)
+static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
 {
-	struct clock_event_device *clk = data;
 	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
 		 clk->irq, smp_processor_id());
-	disable_percpu_irq(arch_timer_ppi);
-	if (arch_timer_ppi2 > 0)
+	disable_percpu_irq(clk->irq);
+	if (arch_timer_ppi2)
 		disable_percpu_irq(arch_timer_ppi2);
 	arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 }
 
-static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
-					   unsigned long action, void *data)
-{
-	int cpu = (int)data;
-	struct clock_event_device *clk = per_cpu_ptr(arch_timer_evt, cpu);
-
-	switch(action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		smp_call_function_single(cpu, arch_timer_setup, clk, 1);
-		break;
-
-	case CPU_DOWN_PREPARE:
-	case CPU_DOWN_PREPARE_FROZEN:
-		smp_call_function_single(cpu, arch_timer_teardown, clk, 1);
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata arch_timer_cpu_nb = {
-	.notifier_call = arch_timer_cpu_notify,
+static struct local_timer_ops arch_timer_ops __cpuinitdata = {
+	.setup	= arch_timer_setup,
+	.stop	= arch_timer_stop,
 };
 
-int __init arch_timer_register(struct resource *res, int res_nr)
+static int __init arch_timer_common_register(void)
 {
 	int err;
 
-	if (!res_nr || res[0].start < 0 || !(res[0].flags & IORESOURCE_IRQ))
-		return -EINVAL;
-
 	err = arch_timer_available();
 	if (err)
 		return err;
 
-	arch_timer_evt = alloc_percpu(struct clock_event_device);
+	arch_timer_evt = alloc_percpu(struct clock_event_device *);
 	if (!arch_timer_evt)
 		return -ENOMEM;
 
-	arch_timer_ppi = res[0].start;
-	if (res_nr > 1 && (res[1].flags & IORESOURCE_IRQ))
-		arch_timer_ppi2 = res[1].start;
-
 	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
 
 	init_sched_clock(&cd, arch_timer_update_sched_clock, 32,
@@ -315,25 +295,89 @@
 #endif
 
 	err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
-				"arch_sys_timer", arch_timer_evt);
+				 "arch_timer", arch_timer_evt);
 	if (err) {
-		pr_err("%s: can't register interrupt %d (%d)\n",
-		       "arch_sys_timer", arch_timer_ppi, err);
-		return err;
+		pr_err("arch_timer: can't register interrupt %d (%d)\n",
+		       arch_timer_ppi, err);
+		goto out_free;
 	}
 
-	if (arch_timer_ppi2 > 0) {
+	if (arch_timer_ppi2) {
 		err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
-					"arch_sys_timer", arch_timer_evt);
-		if (err)
-			pr_warn("%s: can't register interrupt %d (%d)\n",
-				"arch_sys_timer", arch_timer_ppi2, err);
+					 "arch_timer", arch_timer_evt);
+		if (err) {
+			pr_err("arch_timer: can't register interrupt %d (%d)\n",
+			       arch_timer_ppi2, err);
+			arch_timer_ppi2 = 0;
+			goto out_free_irq;
+		}
 	}
 
-	/* Immediately configure the timer on the boot CPU */
-	arch_timer_setup(per_cpu_ptr(arch_timer_evt, smp_processor_id()));
-
-	register_cpu_notifier(&arch_timer_cpu_nb);
+	err = local_timer_register(&arch_timer_ops);
+	if (err)
+		goto out_free_irq;
+	percpu_timer_setup();
 
 	return 0;
+
+out_free_irq:
+	free_percpu_irq(arch_timer_ppi, arch_timer_evt);
+	if (arch_timer_ppi2)
+		free_percpu_irq(arch_timer_ppi2, arch_timer_evt);
+
+out_free:
+	free_percpu(arch_timer_evt);
+
+	return err;
 }
+
+int __init arch_timer_register(struct arch_timer *at)
+{
+	if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ))
+		return -EINVAL;
+
+	arch_timer_ppi = at->res[0].start;
+
+	if (at->res[1].start > 0 && (at->res[1].flags & IORESOURCE_IRQ))
+		arch_timer_ppi2 = at->res[1].start;
+
+	return arch_timer_common_register();
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+	{ .compatible	= "arm,armv7-timer",	},
+	{},
+};
+
+int __init arch_timer_of_register(void)
+{
+	struct device_node *np;
+	u32 freq;
+	int ret;
+
+	np = of_find_matching_node(NULL, arch_timer_of_match);
+	if (!np) {
+		pr_err("arch_timer: can't find DT node\n");
+		return -ENODEV;
+	}
+
+	/* Try to determine the frequency from the device tree or CNTFRQ */
+	if (!of_property_read_u32(np, "clock-frequency", &freq))
+		arch_timer_rate = freq;
+
+	ret = irq_of_parse_and_map(np, 0);
+	if (ret <= 0) {
+		pr_err("arch_timer: interrupt not specified in timer node\n");
+		return -ENODEV;
+	}
+	arch_timer_ppi = ret;
+	ret = irq_of_parse_and_map(np, 1);
+	if (ret > 0)
+		arch_timer_ppi2 = ret;
+	pr_info("arch_timer: found %s irqs %d %d\n",
+		np->name, arch_timer_ppi, arch_timer_ppi2);
+
+	return arch_timer_common_register();
+}
+#endif
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 263eaaf..c035a96 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -49,9 +49,6 @@
 
 extern void fpundefinstr(void);
 
-
-EXPORT_SYMBOL(__backtrace);
-
 	/* networking */
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_from_user);
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index b0c57a9..38f099a 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -349,7 +349,7 @@
  */
 __enable_mmu:
 #if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
-      orr     r0, r0, #CR_A
+	orr	r0, r0, #CR_A
 #else
 	bic	r0, r0, #CR_A
 #endif
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..09cc127 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/kernel/process.c b/arch/arm/kernel/process.c
index 4ee00c8..bd99bbb 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -226,8 +226,8 @@
 
 	/* endless idle loop with no priority at all */
 	while (1) {
-		tick_nohz_stop_sched_tick(1);
 		idle_notifier_call_chain(IDLE_START);
+		tick_nohz_stop_sched_tick(1);
 		while (!need_resched()) {
 #ifdef CONFIG_HOTPLUG_CPU
 			if (cpu_is_offline(smp_processor_id()))
@@ -235,6 +235,9 @@
 #endif
 
 			local_irq_disable();
+#ifdef CONFIG_PL310_ERRATA_769419
+			wmb();
+#endif
 			if (hlt_counter) {
 				local_irq_enable();
 				cpu_relax();
@@ -434,7 +437,7 @@
 	printk("\n");
 	printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm);
 	__show_regs(regs);
-	__backtrace();
+	dump_stack();
 }
 
 ATOMIC_NOTIFIER_HEAD(thread_notify_head);
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 9726006..172ae01 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -719,10 +719,13 @@
 {
 	int ret;
 	struct thread_info *thread = task_thread_info(target);
-	struct vfp_hard_struct new_vfp = thread->vfpstate.hard;
+	struct vfp_hard_struct new_vfp;
 	const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
 	const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);
 
+	vfp_sync_hwstate(thread);
+	new_vfp = thread->vfpstate.hard;
+
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 				  &new_vfp.fpregs,
 				  user_fpregs_offset,
@@ -743,9 +746,8 @@
 	if (ret)
 		return ret;
 
-	vfp_sync_hwstate(thread);
-	thread->vfpstate.hard = new_vfp;
 	vfp_flush_hwstate(thread);
+	thread->vfpstate.hard = new_vfp;
 
 	return 0;
 }
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 0340224..9e617bd 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -227,6 +227,8 @@
 	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
 		return -EINVAL;
 
+	vfp_flush_hwstate(thread);
+
 	/*
 	 * Copy the floating point registers. There can be unused
 	 * registers see asm/hwcap.h for details.
@@ -251,9 +253,6 @@
 	__get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
 	__get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
 
-	if (!err)
-		vfp_flush_hwstate(thread);
-
 	return err ? -EFAULT : 0;
 }
 
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ea64ba6..4471d90 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -498,6 +498,33 @@
 	clockevents_register_device(evt);
 }
 
+static struct local_timer_ops *lt_ops;
+
+#ifdef CONFIG_LOCAL_TIMERS
+int local_timer_register(struct local_timer_ops *ops)
+{
+	if (lt_ops)
+		return -EBUSY;
+
+	lt_ops = ops;
+	return 0;
+}
+#endif
+
+int __cpuinit __attribute__ ((weak)) local_timer_setup(struct clock_event_device *clk)
+{
+	if (lt_ops)
+		return lt_ops->setup(clk);
+
+	return -ENXIO;
+}
+
+void __attribute__ ((weak)) local_timer_stop(struct clock_event_device *clk)
+{
+	if (lt_ops)
+		lt_ops->stop(clk);
+}
+
 void __cpuinit percpu_timer_setup(void)
 {
 	unsigned int cpu = smp_processor_id();
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index cb7dd40..dbf1e6e 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -33,7 +33,7 @@
 /*
  * Enable the SCU
  */
-void __init scu_enable(void __iomem *scu_base)
+void scu_enable(void __iomem *scu_base)
 {
 	u32 scu_ctrl;
 
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index a673297..cd07b58 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -22,15 +22,10 @@
 #define mask	r7
 #define offset	r8
 
-ENTRY(__backtrace)
-		mov	r1, #0x10
-		mov	r0, fp
-
 ENTRY(c_backtrace)
 
 #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
 		mov	pc, lr
-ENDPROC(__backtrace)
 ENDPROC(c_backtrace)
 #else
 		stmfd	sp!, {r4 - r8, lr}	@ Save an extra register so we have a location...
@@ -107,7 +102,6 @@
 		mov	r1, frame
 		bl	printk
 no_frame:	ldmfd	sp!, {r4 - r8, pc}
-ENDPROC(__backtrace)
 ENDPROC(c_backtrace)
 		
 		.pushsection __ex_table,"a"
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 7d606b0..eeb9478 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -237,9 +237,9 @@
 	CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
 	CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
 	CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
-	CLKDEV_CON_DEV_ID("t3_clk", "atmel_tcb.1", &tc3_clk),
-	CLKDEV_CON_DEV_ID("t4_clk", "atmel_tcb.1", &tc4_clk),
-	CLKDEV_CON_DEV_ID("t5_clk", "atmel_tcb.1", &tc5_clk),
+	CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
+	CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+	CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
 	CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
 };
 
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index e83cc86..f893617 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -748,7 +748,7 @@
 	.num_serializer	= ARRAY_SIZE(da850_iis_serializer_direction),
 	.tdm_slots	= 2,
 	.serial_dir	= da850_iis_serializer_direction,
-	.asp_chan_q	= EVENTQ_1,
+	.asp_chan_q	= EVENTQ_0,
 	.version	= MCASP_VERSION_2,
 	.txnumevt	= 1,
 	.rxnumevt	= 1,
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index f6ac9ba..3cdd237 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -563,7 +563,7 @@
 	int val;
 	u32 value;
 
-	if (!vpif_vsclkdis_reg || !cpld_client)
+	if (!vpif_vidclkctl_reg || !cpld_client)
 		return -ENXIO;
 
 	val = i2c_smbus_read_byte(cpld_client);
@@ -571,7 +571,7 @@
 		return val;
 
 	spin_lock_irqsave(&vpif_reg_lock, flags);
-	value = __raw_readl(vpif_vsclkdis_reg);
+	value = __raw_readl(vpif_vidclkctl_reg);
 	if (mux_mode) {
 		val &= VPIF_INPUT_TWO_CHANNEL;
 		value |= VIDCH1CLK;
@@ -579,7 +579,7 @@
 		val |= VPIF_INPUT_ONE_CHANNEL;
 		value &= ~VIDCH1CLK;
 	}
-	__raw_writel(value, vpif_vsclkdis_reg);
+	__raw_writel(value, vpif_vidclkctl_reg);
 	spin_unlock_irqrestore(&vpif_reg_lock, flags);
 
 	err = i2c_smbus_write_byte(cpld_client, val);
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 18fbcf6..27db4a5 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -154,14 +154,15 @@
 	select ARCH_POPULATES_NODE_MAP
 	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_HAS_HOLES_MEMORYMODEL
-	select MEMORY_HOTPLUG
-	select MEMORY_HOTREMOVE
-	select ARCH_ENABLE_MEMORY_HOTPLUG
-	select ARCH_ENABLE_MEMORY_HOTREMOVE
-	select MIGRATION
-	select ARCH_MEMORY_PROBE
-	select ARCH_MEMORY_REMOVE
-	select FIX_MOVABLE_ZONE
+	select ENABLE_DMM
+	select MEMORY_HOTPLUG if ENABLE_DMM
+	select MEMORY_HOTREMOVE if ENABLE_DMM
+	select ARCH_ENABLE_MEMORY_HOTPLUG if ENABLE_DMM
+	select ARCH_ENABLE_MEMORY_HOTREMOVE if ENABLE_DMM
+	select MIGRATION if ENABLE_DMM
+	select ARCH_MEMORY_PROBE if ENABLE_DMM
+	select ARCH_MEMORY_REMOVE if ENABLE_DMM
+	select FIX_MOVABLE_ZONE if ENABLE_DMM
 	select CLEANCACHE
 	select QCACHE
 	select MSM_MULTIMEDIA_USE_ION
@@ -193,14 +194,15 @@
 	select ARCH_POPULATES_NODE_MAP
 	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_HAS_HOLES_MEMORYMODEL
-	select MEMORY_HOTPLUG
-	select MEMORY_HOTREMOVE
-	select ARCH_ENABLE_MEMORY_HOTPLUG
-	select ARCH_ENABLE_MEMORY_HOTREMOVE
-	select MIGRATION
-	select ARCH_MEMORY_PROBE
-	select ARCH_MEMORY_REMOVE
-	select FIX_MOVABLE_ZONE
+	select ENABLE_DMM
+	select MEMORY_HOTPLUG if ENABLE_DMM
+	select MEMORY_HOTREMOVE if ENABLE_DMM
+	select ARCH_ENABLE_MEMORY_HOTPLUG if ENABLE_DMM
+	select ARCH_ENABLE_MEMORY_HOTREMOVE if ENABLE_DMM
+	select MIGRATION if ENABLE_DMM
+	select ARCH_MEMORY_PROBE if ENABLE_DMM
+	select ARCH_MEMORY_REMOVE if ENABLE_DMM
+	select FIX_MOVABLE_ZONE if ENABLE_DMM
 	select MSM_ULTRASOUND
 	select MULTI_IRQ_HANDLER
 	select MSM_PM8X60 if PM
@@ -222,6 +224,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"
@@ -247,6 +250,7 @@
 config ARCH_MSM9615
 	bool "MSM9615"
 	select ARM_GIC
+	select GIC_SECURE
 	select ARCH_MSM_CORTEX_A5
 	select CPU_V7
 	select MSM_V2_TLMM
@@ -259,6 +263,10 @@
 	select MULTI_IRQ_HANDLER
 	select MSM_PM8X60 if PM
 	select MSM_XO
+	select MSM_MULTIMEDIA_USE_ION
+	select MSM_QDSP6_APR
+	select MSM_AUDIO_QDSP6 if SND_SOC
+	select FIQ
 
 config ARCH_MSM8625
 	bool "MSM8625"
@@ -268,6 +276,7 @@
 	select ARM_GIC
 	select ARCH_MSM_CORTEXMP
 	select MULTI_IRQ_HANDLER
+	select ARM_TICKET_LOCKS
 endmenu
 
 choice
@@ -310,11 +319,13 @@
 config  ARCH_MSM_SCORPIONMP
 	select ARCH_MSM_SCORPION
 	select MSM_SMP
+	select HAVE_ARCH_HAS_CURRENT_TIMER
 	bool
 
 config  ARCH_MSM_KRAITMP
 	select ARCH_MSM_KRAIT
 	select MSM_SMP
+	select HAVE_ARCH_HAS_CURRENT_TIMER
 	bool
 
 config  ARCH_MSM_CORTEXMP
@@ -477,6 +488,30 @@
 	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_MSM8625_QRD7
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 QRD7"
+	help
+	  Support for the Qualcomm MSM8625 Reference Design.
+
 config MACH_MSM7X30_SURF
        depends on ARCH_MSM7X30
        depends on !MSM_STACKED_MEMORY
@@ -747,6 +782,12 @@
 	help
 	  Support for the Qualcomm APQ8064 LIQUID device.
 
+config MACH_MPQ8064_CDP
+	depends on ARCH_APQ8064
+	bool "MPQ8064 CDP"
+	help
+	  Support for the Qualcomm MPQ8064 CDP device.
+
 config MACH_MPQ8064_HRD
 	depends on ARCH_APQ8064
 	bool "MPQ8064 HRD"
@@ -785,7 +826,7 @@
 	default "0x80200000" if ARCH_APQ8064
 	default "0x80200000" if ARCH_MSM8960
 	default "0x80200000" if ARCH_MSM8930
-	default "0x80200000" if ARCH_MSMCOPPER
+	default "0x20200000" if ARCH_MSMCOPPER
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x00200000" if !MSM_STACKED_MEMORY
 	default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
@@ -854,27 +895,38 @@
 	  Say Y here if you want the debug print routines to direct
 	  their output to the serial port on MSM 8930 devices.
 
+config MSM_DEBUG_UART_PHYS
+	hex
+	default 0xA9A00000 if (ARCH_MSM7X27 || ARCH_QSD8X50) && DEBUG_MSM_UART1
+	default 0xACA00000 if ARCH_MSM7X30 && DEBUG_MSM_UART1
+	default 0x94000000 if ARCH_FSM9XXX && DEBUG_MSM_UART1
+	default 0xA9B00000 if (ARCH_MSM7X27 || ARCH_QSD8X50) && DEBUG_MSM_UART2
+	default 0xACB00000 if ARCH_MSM7X30 && DEBUG_MSM_UART2
+	default 0x94100000 if ARCH_FSM9XXX && DEBUG_MSM_UART2
+	default 0xA9C00000 if (ARCH_MSM7X27 || ARCH_QSD8X50) && DEBUG_MSM_UART3
+	default 0xACC00000 if ARCH_MSM7X30 && DEBUG_MSM_UART3
+
 choice
 	prompt "Debug UART"
 	depends on DEBUG_LL
 
 	config DEBUG_MSM_UART1
 		bool "Kernel low-level debugging messages via MSM UART1"
-		depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
+		depends on ARCH_MSM7X27 || ARCH_MSM7X30 || ARCH_QSD8X50 || ARCH_FSM9XXX
 		help
 		  Say Y here if you want the debug print routines to direct
 		  their output to the first serial port on MSM devices.
 
 	config DEBUG_MSM_UART2
 		bool "Kernel low-level debugging messages via MSM UART2"
-		depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
+		depends on ARCH_MSM7X27 || ARCH_MSM7X30 || ARCH_QSD8X50 || ARCH_FSM9XXX
 		help
 		  Say Y here if you want the debug print routines to direct
 		  their output to the second serial port on MSM devices.
 
 	config DEBUG_MSM_UART3
 		bool "Kernel low-level debugging messages via MSM UART3"
-		depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
+		depends on ARCH_MSM7X27 || ARCH_MSM7X30 || ARCH_QSD8X50
 		help
 		  Say Y here if you want the debug print routines to direct
 		  their output to the third serial port on MSM devices.
@@ -1727,6 +1779,15 @@
 	  used to decrypt data and perform secure operations on the behalf of
 	  the kernel.
 
+config MSM_PIL_DSPS
+	tristate "DSPS Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down ARM7 DSPS processors.
+
+	  DSPS is a sensors offloading processor used for applications such
+	  as rotation detection, temperature, etc.
+
 config MSM_PIL_GSS
 	tristate "GSS (Coretx A5) Boot Support"
 	depends on MSM_PIL
@@ -1779,6 +1840,14 @@
 	 monitors WCNSS hardware watchdog interrupt lines and plugs WCNSS
 	 into the subsystem restart framework.
 
+config MSM_GSS_SSR_8064
+	bool "MSM 8064 GSS restart driver"
+	depends on (ARCH_APQ8064)
+	help
+	 This option enables the gps subsystem restart driver for APQ8064, which monitors
+	 gss hardware watchdog interrupt lines and plugs into the subsystem
+	 restart and PIL drivers.
+
 config SCORPION_Uni_45nm_BUG
 	bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
 	depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
@@ -1905,7 +1974,7 @@
 
 config MSM_WATCHDOG
 	bool "MSM Watchdog Support"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615 || ARCH_FSM9XXX
 	help
 		This enables the watchdog as is present on 8x60. Currently we use
 		core 0's watchdog, and reset the entire SoC if it times out. It does
@@ -1955,6 +2024,10 @@
 config MSM_SLEEP_STATS_DEVICE
 	bool "Enable exporting of MSM sleep device stats to userspace"
 
+config MSM_RUN_QUEUE_STATS
+	bool "Enable collection and exporting of MSM Run Queue stats to userspace"
+	default y
+
 config MSM_STANDALONE_POWER_COLLAPSE
        bool "Enable standalone power collapse"
        default n
@@ -2082,11 +2155,95 @@
 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
 	  separately. This will guarantee that the last acesses for each cpu
 	  will be logged but there will be fewer entries per cpu
 
+config MSM_CACHE_ERP
+	bool "Cache / CPU error reporting"
+	depends on ARCH_MSM_KRAIT
+	help
+	  Say 'Y' here to enable reporting of cache and TLB errors to the kernel
+	  log. Enabling this feature can be used as a system debugging technique
+	  if cache corruption is suspected. Cache error statistics will also be
+	  reported in /proc/cpu/msm_cache_erp.
+
+	  For production builds, you should probably say 'N' here.
+
+config MSM_L1_ERR_PANIC
+	bool "Panic on L1 cache / TLB errors"
+	depends on MSM_CACHE_ERP
+	help
+	  To cause the kernel to panic whenever an L1 cache or TLB error is
+	  detected, say 'Y' here. This may be useful as a debugging technique if
+	  general system instability is suspected.
+
+	  For production builds, you should probably say 'N' here.
+
+
+config MSM_L2_ERP_PORT_PANIC
+	bool "Panic on L2 master port errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Master port errors can occur when a memory request is not properly
+	  handled by the destination slave. Enable this option to catch drivers
+	  which attempt to access bad areas of the address space, or access
+	  hardware registers in an improper state (such as certain clocks not
+	  being on). This option may help with debugging, though production
+	  builds should probably say 'N' here.
+
+config MSM_L2_ERP_1BIT_PANIC
+	bool "Panic on recoverable L2 soft errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Enable this option to cause a kernel panic whenever the L2 cache
+	  encounters a single-bit (correctable) soft error. This option should
+	  only be enabled when doing low-level debugging where cache corruption
+	  is suspected.
+
+	  For production builds, you should definitely say 'N' here.
+
+config MSM_L2_ERP_2BIT_PANIC
+	bool "Panic on unrecoverable L2 soft errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Enable this option to cause a kernel panic whenever the L2 cache
+	  encounters a double-bit (non-correctable) soft error. Debug builds
+	  will likely benefit from having this option enabled to catch cache
+	  problems as soon as possible.
+
+	  For production builds, it may be acceptable to say 'N' here, since
+	  an uncorrectable error might not necessarily cause further problems.
+
+config MSM_DCVS
+	bool "Use MSM DCVS for CPU/GPU Frequency control"
+	depends on MSM_SCM
+	help
+	  Enable support for MSM DCVS to control all CPU and GPU core frequencies.
+	  The DCVS manager allows idle driver to feed the idle information to the
+	  algorithm and the algorithm returns a frequency for the core which is
+	  passed to the frequency change driver.
+
+config HAVE_ARCH_HAS_CURRENT_TIMER
+	bool
+
+config MSM_CACHE_DUMP
+	bool "Cache dumping support"
+	help
+	  Add infrastructure to dump the L1 and L2 caches to an allocated buffer.
+	  This allows for analysis of the caches in case cache corruption is
+	  suspected.
+
+config MSM_CACHE_DUMP_ON_PANIC
+	bool "Dump caches on panic"
+	depends on MSM_CACHE_DUMP
+	help
+	  By default, the caches are flushed on panic. This means that trying to
+	  look at them in a RAM dump will give useless data. Select this if you
+	  want to dump the L1 and L2 caches on panic before any flush occurs.
+	  If unsure, say N
 
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 8347a25..2609aca 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 $< $@
@@ -67,15 +67,12 @@
 obj-$(CONFIG_MSM_SECURE_IO) += scm-io.o
 obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
 obj-$(CONFIG_MSM_PIL) += scm-pas.o
-ifdef CONFIG_MSM_PIL
-obj-$(CONFIG_ARCH_MSM8X60) += peripheral-reset.o
-obj-$(CONFIG_ARCH_MSM8960) += peripheral-reset-8960.o
-endif
 obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
 obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
 obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
 obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
 obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o
+obj-$(CONFIG_MSM_PIL_DSPS) += pil-dsps.o
 obj-$(CONFIG_MSM_PIL_GSS) += pil-gss.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
@@ -192,6 +189,7 @@
 obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
 obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
 obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
+obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
 
 ifdef CONFIG_CPU_IDLE
 	obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
@@ -206,6 +204,7 @@
 obj-$(CONFIG_ARCH_FSM9XXX) += restart-fsm9xxx.o xo-fsm9xxx.o
 
 obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog.o
+obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog_asm.o
 obj-$(CONFIG_MACH_MSM8X60_RUMI3) += board-msm8x60.o
 obj-$(CONFIG_MACH_MSM8X60_SIM) += board-msm8x60.o
 obj-$(CONFIG_MACH_MSM8X60_SURF) += board-msm8x60.o
@@ -221,14 +220,19 @@
 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
-obj-$(CONFIG_ARCH_MSM8625) += devices-msm7x27a.o clock-pcom-lookup.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 board-msm7627a-io.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 mpm-8625.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_MACH_MSM8625_QRD7) +=  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
@@ -241,7 +245,7 @@
 obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
 obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
 board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
-board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o
+board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o board-8930-gpu.o
 board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o board-8064-display.o board-8064-gpu.o
 obj-$(CONFIG_MACH_MSM8960_SIM) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-8960-all.o board-8960-regulator.o
@@ -251,12 +255,13 @@
 obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator.o
 obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator.o
 obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator.o
-obj-$(CONFIG_ARCH_MSM8960) += bms-batterydata.o
+obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
 obj-$(CONFIG_MACH_APQ8064_SIM) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_RUMI3) += board-8064-all.o board-8064-regulator.o
-obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o
+obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
 obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
-obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -307,8 +312,10 @@
 endif
 endif
 
-obj-$(CONFIG_MSM_SLEEP_STATS) += msm_rq_stats.o idle_stats.o
+obj-$(CONFIG_MSM_SLEEP_STATS) += idle_stats.o
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
+obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o
+obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
 obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o
 obj-$(CONFIG_BT_MSM_PINTEST)  += btpintest.o
 obj-$(CONFIG_MSM_FAKE_BATTERY) += fish_battery.o
@@ -325,3 +332,5 @@
 
 obj-$(CONFIG_ARCH_MSM8960) += mdm2.o mdm_common.o
 obj-$(CONFIG_MSM_RTB) += msm_rtb.o
+obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o
+obj-$(CONFIG_MSM_CACHE_DUMP) += msm_cache_dump.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 7ac2d9f..58c630e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -46,7 +46,7 @@
    zreladdr-$(CONFIG_ARCH_APQ8064)	:= 0x80208000
 
 # MSMCOPPER
-   zreladdr-$(CONFIG_ARCH_MSMCOPPER)	:= 0x80208000
+   zreladdr-$(CONFIG_ARCH_MSMCOPPER)	:= 0x20208000
 
 # MSM9615
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 7ad3f65..35e8eba 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -27,11 +27,11 @@
 #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>
 #include <mach/socinfo.h>
+#include <asm/mach-types.h>
+#include <asm/cpu.h>
 
 #include "smd_private.h"
 #include "acpuclock.h"
@@ -39,36 +39,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 +78,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 +88,12 @@
 	unsigned int	ahbclk_div;
 	int		vdd;
 	unsigned int	axiclk_khz;
-	unsigned long	lpj; /* loops_per_jiffy */
+	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;
 
@@ -187,7 +167,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -217,7 +197,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -232,7 +212,7 @@
 	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
 	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
 	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -241,13 +221,41 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
+/* 8625 PLL4 @ 1209MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1209[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 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, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 200000 },
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 8625 PLL4 @ 1209MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1209[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 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, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 200000 },
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 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 */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -261,7 +269,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -291,7 +299,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1, 61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2, 61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -300,13 +308,13 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27aa PLL4 @ 1008MHz with CDMA capable modem */
+/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_1008[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
 	{ 0, 65536, ACPU_PLL_1, 1, 8,  8192, 3, 1, 49152 },
 	{ 1, 98304, ACPU_PLL_1, 1, 5,  12288, 3, 2, 49152 },
 	{ 1, 196608, ACPU_PLL_1, 1, 2, 24576, 3, 3, 98304 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -315,13 +323,13 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x25a PLL2 @ 1200MHz with GSM capable modem */
+/* 7625a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -329,26 +337,16 @@
 	{ 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;
 };
 
@@ -365,6 +363,8 @@
 	PLL_CONFIG(960, 589, 1200, 800),
 	PLL_CONFIG(960, 737, 1200, 1008),
 	PLL_CONFIG(960, 589, 1200, 1008),
+	PLL_CONFIG(960, 245, 1200, 1209),
+	PLL_CONFIG(960, 196, 1200, 1209),
 	{ 0, 0, 0, 0, 0 }
 };
 
@@ -405,59 +405,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 +523,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 +598,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);
@@ -663,7 +610,15 @@
 		acpuclk_set_div(cur_s);
 		drv_state.current_speed = cur_s;
 		/* Re-adjust lpj for the new clock speed. */
+#ifdef CONFIG_SMP
+		for_each_possible_cpu(cpu) {
+			per_cpu(cpu_data, cpu).loops_per_jiffy =
+							cur_s->lpj;
+		}
+#endif
+		/* Adjust the global one */
 		loops_per_jiffy = cur_s->lpj;
+
 		mb();
 		udelay(50);
 	}
@@ -684,12 +639,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 +693,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 +729,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,15 +802,24 @@
 	return found_khz;
 }
 
-/* Initalize the lpj field in the acpu_freq_tbl. */
 static void __init lpj_init(void)
 {
-	int i;
+	int i = 0, cpu;
 	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);
+	unsigned long loops;
+
+	for_each_possible_cpu(cpu) {
+#ifdef CONFIG_SMP
+		loops = per_cpu(cpu_data, cpu).loops_per_jiffy;
+#else
+		loops = loops_per_jiffy;
+#endif
+		for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
+			acpu_freq_tbl[i].lpj = cpufreq_scale(
+				loops,
+				base_clk->a11clk_khz,
+				acpu_freq_tbl[i].a11clk_khz);
+		}
 	}
 }
 
@@ -945,33 +894,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,9 +910,8 @@
 	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();
@@ -1018,3 +939,9 @@
 	.max_speed_delta_khz = 504000,
 	.init = acpuclk_7627_init,
 };
+
+struct acpuclk_soc_data acpuclk_8625_soc_data __initdata = {
+	/* TODO: Need to update speed delta from H/w Team */
+	.max_speed_delta_khz = 604800,
+	.init = acpuclk_7627_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 7ee4e5b..29b0065 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
@@ -34,8 +34,8 @@
 #include "acpuclock.h"
 #include "spm.h"
 
-#define SCSS_CLK_CTL_ADDR	(MSM_ACC_BASE + 0x04)
-#define SCSS_CLK_SEL_ADDR	(MSM_ACC_BASE + 0x08)
+#define SCSS_CLK_CTL_ADDR	(MSM_ACC0_BASE + 0x04)
+#define SCSS_CLK_SEL_ADDR	(MSM_ACC0_BASE + 0x08)
 
 #define PLL2_L_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x33C)
 #define PLL2_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x340)
@@ -461,6 +461,14 @@
 	BUG_ON(IS_ERR(acpuclk_sources[PLL_2]));
 	acpuclk_sources[PLL_3] = clk_get_sys("acpu", "pll3_clk");
 	BUG_ON(IS_ERR(acpuclk_sources[PLL_3]));
+	/*
+	 * Prepare all the PLLs because we enable/disable them
+	 * from atomic context and can't always ensure they're
+	 * all prepared in non-atomic context.
+	 */
+	BUG_ON(clk_prepare(acpuclk_sources[PLL_1]));
+	BUG_ON(clk_prepare(acpuclk_sources[PLL_2]));
+	BUG_ON(clk_prepare(acpuclk_sources[PLL_3]));
 }
 
 static struct acpuclk_data acpuclk_7x30_data = {
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 99c3d78..051e165 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -36,6 +36,7 @@
 #include <mach/rpm-regulator.h>
 
 #include "acpuclock.h"
+#include "pm.h"
 
 /*
  * Source IDs.
@@ -67,9 +68,6 @@
 
 #define STBY_KHZ		1
 
-#define HFPLL_NOMINAL_VDD	1050000
-#define HFPLL_LOW_VDD_8960	 850000
-#define HFPLL_LOW_VDD		 945000
 #define HFPLL_LOW_VDD_PLL_L_MAX	0x28
 
 #define SECCLKAGD		BIT(4)
@@ -77,6 +75,12 @@
 /* PTE EFUSE register. */
 #define QFPROM_PTE_EFUSE_ADDR	(MSM_QFPROM_BASE + 0x00C0)
 
+/* Corner type vreg VDD values */
+#define LVL_NONE	RPM_VREG_CORNER_NONE
+#define LVL_LOW	RPM_VREG_CORNER_LOW
+#define LVL_NOM	RPM_VREG_CORNER_NOMINAL
+#define LVL_HIGH	RPM_VREG_CORNER_HIGH
+
 enum scalables {
 	CPU0 = 0,
 	CPU1,
@@ -95,6 +99,12 @@
 	NUM_VREG
 };
 
+enum hfpll_vdd_levels {
+	HFPLL_VDD_NONE,
+	HFPLL_VDD_LOW,
+	HFPLL_VDD_NOM
+};
+
 struct vreg {
 	const char name[15];
 	const unsigned int max_vdd;
@@ -133,7 +143,25 @@
 	struct core_speed *current_speed;
 	struct l2_level *l2_vote;
 	struct vreg vreg[NUM_VREG];
-	bool first_set_call;
+	unsigned int *hfpll_vdd_tbl;
+};
+
+static unsigned int hfpll_vdd_tbl_8960[] = {
+	[HFPLL_VDD_NONE] = 0,
+	[HFPLL_VDD_LOW]  = 850000,
+	[HFPLL_VDD_NOM]  = 1050000
+};
+
+static unsigned int hfpll_vdd_tbl_8064[] = {
+	[HFPLL_VDD_NONE] = 0,
+	[HFPLL_VDD_LOW]  = 945000,
+	[HFPLL_VDD_NOM]  = 1050000
+};
+
+static unsigned int hfpll_vdd_dig_tbl_8930[] = {
+	[HFPLL_VDD_NONE] = LVL_NONE,
+	[HFPLL_VDD_LOW]  = LVL_LOW,
+	[HFPLL_VDD_NOM]  = LVL_NOM
 };
 
 static struct scalable scalable_8960[] = {
@@ -175,6 +203,7 @@
 		},
 	[L2] = {
 			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.hfpll_vdd_tbl = hfpll_vdd_tbl_8960,
 			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
 			.l2cpmr_iaddr = L2CPMR_IADDR,
 			.vreg[VREG_HFPLL_A] = { "hfpll_l2_s8", 2100000,
@@ -194,7 +223,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 +238,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 +253,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 +268,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 },
@@ -252,6 +281,7 @@
 		},
 	[L2] = {
 			.hfpll_base   = MSM_HFPLL_BASE    + 0x300,
+			.hfpll_vdd_tbl = hfpll_vdd_tbl_8064,
 			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
 			.l2cpmr_iaddr = L2CPMR_IADDR,
 			.vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
@@ -269,9 +299,10 @@
 			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
 					     RPM_VREG_VOTER1,
 					     RPM_VREG_ID_PM8038_L24 },
-			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+			.vreg[VREG_DIG]  = { "krait0_dig", LVL_HIGH,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8038_S1 },
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
 			.vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
 					     RPM_VREG_VOTER1,
 					     RPM_VREG_ID_PM8038_L23 },
@@ -284,15 +315,17 @@
 			.vreg[VREG_MEM]  = { "krait1_mem", 1150000,
 					     RPM_VREG_VOTER2,
 					     RPM_VREG_ID_PM8038_L24 },
-			.vreg[VREG_DIG]  = { "krait1_dig", 1150000,
+			.vreg[VREG_DIG]  = { "krait1_dig", LVL_HIGH,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8038_S1 },
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
 			.vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
 					     RPM_VREG_VOTER2,
 					     RPM_VREG_ID_PM8038_L23 },
 		},
 	[L2] = {
 			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.hfpll_vdd_tbl = hfpll_vdd_dig_tbl_8930,
 			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
 			.l2cpmr_iaddr = L2CPMR_IADDR,
 			.vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
@@ -311,9 +344,10 @@
 			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
 					     RPM_VREG_VOTER1,
 					     RPM_VREG_ID_PM8038_L24 },
-			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+			.vreg[VREG_DIG]  = { "krait0_dig", LVL_HIGH,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8038_S1 },
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
 			.vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
 					     RPM_VREG_VOTER1,
 					     RPM_VREG_ID_PM8038_L23 },
@@ -326,9 +360,10 @@
 			.vreg[VREG_MEM]  = { "krait1_mem", 1150000,
 					     RPM_VREG_VOTER2,
 					     RPM_VREG_ID_PM8038_L24 },
-			.vreg[VREG_DIG]  = { "krait1_dig", 1150000,
+			.vreg[VREG_DIG]  = { "krait1_dig", LVL_HIGH,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8038_S1 },
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
 			.vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
 					     RPM_VREG_VOTER2,
 					     RPM_VREG_ID_PM8038_L23 },
@@ -343,10 +378,11 @@
 		},
 };
 
-static struct scalable *scalable;
 static struct l2_level *l2_freq_tbl;
 static struct acpu_level *acpu_freq_tbl;
 static int l2_freq_tbl_size;
+static struct scalable *scalable;
+#define SCALABLE_TO_CPU(sc) ((sc) - scalable)
 
 /* Instantaneous bandwidth requests in MB/s. */
 #define BW_MBPS(_bw) \
@@ -375,6 +411,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 +583,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 } }
 };
 
@@ -594,23 +632,23 @@
 #undef L2
 #define L2(x) (&l2_freq_tbl_8930[(x)])
 static struct l2_level l2_freq_tbl_8930[] = {
-	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
-	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
-	[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 },
-	[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, 2 },
-	[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, 4 },
-	[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 },
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 },  LVL_NOM, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 },  LVL_NOM, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 },  LVL_NOM, 1050000, 2 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 },  LVL_NOM, 1050000, 2 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 },  LVL_NOM, 1050000, 2 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 },  LVL_NOM, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 },  LVL_NOM, 1050000, 4 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A },  LVL_NOM, 1050000, 4 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
+	[13] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
+	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
+	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
+	[16] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
 };
 
 /* TODO: Update core voltages when data is available. */
@@ -639,19 +677,19 @@
 #undef L2
 #define L2(x) (&l2_freq_tbl_8627[(x)])
 static struct l2_level l2_freq_tbl_8627[] = {
-	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
-	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
-	[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, 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, 3 },
-	[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, 4 },
-	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 4 },
-	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 4 },
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 },  LVL_NOM, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 },  LVL_NOM, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 },  LVL_NOM, 1050000, 1 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 },  LVL_NOM, 1050000, 1 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 },  LVL_NOM, 1050000, 2 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 },  LVL_NOM, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 },  LVL_NOM, 1050000, 2 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A },  LVL_NOM, 1050000, 3 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 3 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 3 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 4 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 4 },
 };
 
 /* TODO: Update core voltages when data is available. */
@@ -876,28 +914,37 @@
 		set_pri_clk_src(sc, tgt_s->pri_src_sel);
 	} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
 		/*
-		 * If responding to CPU_DEAD we must be running on another
-		 * CPU.  Therefore, we can't access the downed CPU's CP15
-		 * clock MUX registers from here and can't change clock sources.
-		 * Just turn off the PLL- since the CPU is down already, halting
-		 * its clock should be safe.
+		 * If responding to CPU_DEAD we must be running on another CPU.
+		 * Therefore, we can't access the downed CPU's clock MUX CP15
+		 * registers from here and can't change clock sources. If the
+		 * CPU is collapsed, however, it is still safe to turn off the
+		 * PLL without switching the MUX away from it.
 		 */
 		if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
 			set_sec_clk_src(sc, tgt_s->sec_src_sel);
 			set_pri_clk_src(sc, tgt_s->pri_src_sel);
+			hfpll_disable(sc, 0);
+		} else if (reason == SETRATE_HOTPLUG
+			   && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
+			hfpll_disable(sc, 0);
 		}
-		hfpll_disable(sc, 0);
 	} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
-		hfpll_set_rate(sc, tgt_s);
-		hfpll_enable(sc, 0);
 		/*
 		 * If responding to CPU_UP_PREPARE, we can't change CP15
 		 * registers for the CPU that's coming up since we're not
 		 * running on that CPU.  That's okay though, since the MUX
 		 * source was not changed on the way down, either.
 		 */
-		if (reason != SETRATE_HOTPLUG || sc == &scalable[L2])
+		if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
+			hfpll_set_rate(sc, tgt_s);
+			hfpll_enable(sc, 0);
 			set_pri_clk_src(sc, tgt_s->pri_src_sel);
+		} else if (reason == SETRATE_HOTPLUG
+			   && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
+			/* PLL was disabled during hot-unplug. Re-enable it. */
+			hfpll_set_rate(sc, tgt_s);
+			hfpll_enable(sc, 0);
+		}
 	} else {
 		if (reason != SETRATE_HOTPLUG || sc == &scalable[L2])
 			set_sec_clk_src(sc, tgt_s->sec_src_sel);
@@ -1027,33 +1074,18 @@
 	unsigned int pll_vdd_dig;
 
 	if (tgt->l2_level->speed.src != HFPLL)
-		pll_vdd_dig = 0;
+		pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NONE];
 	else if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
-		pll_vdd_dig = HFPLL_NOMINAL_VDD;
-	else {
-		if (cpu_is_msm8960())
-			pll_vdd_dig = HFPLL_LOW_VDD_8960;
-		else
-			pll_vdd_dig = HFPLL_LOW_VDD;
-	}
+		pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NOM];
+	else
+		pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_LOW];
+
 	return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
 }
 
 static unsigned int calculate_vdd_core(struct acpu_level *tgt)
 {
-	unsigned int pll_vdd_core;
-
-	if (tgt->speed.src != HFPLL)
-		pll_vdd_core = 0;
-	else if (tgt->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
-		pll_vdd_core = HFPLL_NOMINAL_VDD;
-	else {
-		if (cpu_is_msm8960())
-			pll_vdd_core = HFPLL_LOW_VDD_8960;
-		else
-			pll_vdd_core = HFPLL_LOW_VDD;
-	}
-	return max(tgt->vdd_core, pll_vdd_core);
+	return tgt->vdd_core;
 }
 
 /* Set the CPU's clock rate and adjust the L2 rate, if appropriate. */
@@ -1078,7 +1110,7 @@
 	strt_acpu_s = scalable[cpu].current_speed;
 
 	/* Return early if rate didn't change. */
-	if (rate == strt_acpu_s->khz && scalable[cpu].first_set_call == false)
+	if (rate == strt_acpu_s->khz)
 		goto out;
 
 	/* Find target frequency. */
@@ -1132,7 +1164,6 @@
 	/* Drop VDD levels if we can. */
 	decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
 
-	scalable[cpu].first_set_call = false;
 	pr_debug("ACPU%d speed change complete\n", cpu);
 
 out:
@@ -1163,13 +1194,41 @@
 }
 
 /* Voltage regulator initialization. */
-static void __init regulator_init(int set_vdd)
+static void __init regulator_init(struct acpu_level *lvl)
 {
 	int cpu, ret;
 	struct scalable *sc;
+	unsigned int vdd_mem, vdd_dig, vdd_core;
+
+	vdd_mem = calculate_vdd_mem(lvl);
+	vdd_dig = calculate_vdd_dig(lvl);
 
 	for_each_possible_cpu(cpu) {
 		sc = &scalable[cpu];
+
+		/* Set initial vdd_mem vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (ret) {
+			pr_err("%s initialization failed (%d)\n",
+				sc->vreg[VREG_MEM].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_MEM].cur_vdd  = vdd_mem;
+
+		/* Set initial vdd_dig vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (ret) {
+			pr_err("%s initialization failed (%d)\n",
+				sc->vreg[VREG_DIG].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_DIG].cur_vdd  = vdd_dig;
+
+		/* Setup Krait CPU regulators and initial core voltage. */
 		sc->vreg[VREG_CORE].reg = regulator_get(NULL,
 					  sc->vreg[VREG_CORE].name);
 		if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
@@ -1178,18 +1237,21 @@
 			       PTR_ERR(sc->vreg[VREG_CORE].reg));
 			BUG();
 		}
-
-		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg,
-					    set_vdd,
+		vdd_core = calculate_vdd_core(lvl);
+		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
 					    sc->vreg[VREG_CORE].max_vdd);
-		if (ret)
-			pr_err("regulator_set_voltage(%s) failed"
-			       " (%d)\n", sc->vreg[VREG_CORE].name, ret);
-
+		if (ret) {
+			pr_err("%s initialization failed (%d)\n",
+				sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
 		ret = regulator_enable(sc->vreg[VREG_CORE].reg);
-		if (ret)
+		if (ret) {
 			pr_err("regulator_enable(%s) failed (%d)\n",
 			       sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
 	}
 }
 
@@ -1216,12 +1278,6 @@
 	set_sec_clk_src(sc, tgt_s->sec_src_sel);
 	set_pri_clk_src(sc, tgt_s->pri_src_sel);
 	sc->current_speed = tgt_s;
-
-	/*
-	 * Set this flag so that the first call to acpuclk_8960_set_rate() can
-	 * drop voltages and set initial bus bandwidth requests.
-	 */
-	sc->first_set_call = true;
 }
 
 static void __init per_cpu_init(void *data)
@@ -1449,7 +1505,7 @@
 {
 	struct acpu_level *max_acpu_level = select_freq_plan();
 
-	regulator_init(max_acpu_level->vdd_core);
+	regulator_init(max_acpu_level);
 	bus_init(max_acpu_level->l2_level->bw_level);
 
 	init_clock_sources(&scalable[L2], &max_acpu_level->l2_level->speed);
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 7339a4c..787483b 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -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
@@ -40,13 +40,12 @@
 #define COMPLEX_SLEW		7
 
 /* PLL calibration limits.
- * The PLL hardware is capable of 384MHz to 1536MHz. The L_VALs
- * used for calibration should respect these limits. */
+ * The PLL hardware has a minimum frequency of 384MHz.
+ * Calibration should respect this limit. */
 #define L_VAL_SCPLL_CAL_MIN	0x08 /* =  432 MHz with 27MHz source */
-#define L_VAL_SCPLL_CAL_MAX	0x1C /* = 1512 MHz with 27MHz source */
 
-#define MAX_VDD_SC		1250000 /* uV */
-#define MAX_VDD_MEM		1250000 /* uV */
+#define MAX_VDD_SC		1325000 /* uV */
+#define MAX_VDD_MEM		1325000 /* uV */
 #define MAX_VDD_DIG		1200000 /* uV */
 #define MAX_AXI			 310500 /* KHz */
 #define SCPLL_LOW_VDD_FMAX	 594000 /* KHz */
@@ -72,7 +71,7 @@
 #define SCPLL_STATUS_OFFSET		0x10
 #define SCPLL_CFG_OFFSET		0x1C
 #define SCPLL_FSM_CTL_EXT_OFFSET	0x24
-#define SCPLL_LUT_A_HW_MAX		(0x38 + ((L_VAL_SCPLL_CAL_MAX / 4) * 4))
+#define SCPLL_LUT_OFFSET(l_val)		(0x38 + (((l_val) / 4) * 4))
 
 /* Clock registers. */
 #define SPSS0_CLK_CTL_ADDR		(MSM_ACC0_BASE + 0x04)
@@ -218,6 +217,72 @@
 };
 
 /* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_slowest[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   825000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   850000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   850000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   875000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   875000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   900000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   900000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   925000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   975000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   975000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1000000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1025000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1025000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1050000, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1075000, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1100000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1125000, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1150000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1175000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1200000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1225000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1250000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1275000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1300000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1325000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_slower[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   825000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   850000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   850000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   875000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   875000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   900000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   900000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   925000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   975000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   975000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1000000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1025000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1025000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1050000, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1075000, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1100000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1125000, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1150000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1150000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1200000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1225000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1250000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1275000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1300000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
 static struct clkctl_acpu_speed acpu_freq_tbl_slow[] = {
   { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
   /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
@@ -244,6 +309,9 @@
   { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1175000, 0x03006000},
   { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1200000, 0x03006000},
   { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1225000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1225000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1225000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1250000, 0x03006000},
   { {0, 0}, 0 },
 };
 
@@ -274,6 +342,9 @@
   { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1150000, 0x03006000},
   { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1150000, 0x03006000},
   { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1200000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1200000, 0x03006000},
   { {0, 0}, 0 },
 };
 
@@ -304,6 +375,9 @@
   { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1100000, 0x03006000},
   { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1100000, 0x03006000},
   { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1125000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1125000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1125000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1150000, 0x03006000},
   { {0, 0}, 0 },
 };
 
@@ -669,34 +743,29 @@
 	return rc;
 }
 
-static void __init scpll_init(int sc_pll)
+static void __init scpll_init(int pll, unsigned int max_l_val)
 {
 	uint32_t regval;
 
-	pr_debug("Initializing SCPLL%d\n", sc_pll);
+	pr_debug("Initializing SCPLL%d\n", pll);
 
 	/* Clear calibration LUT registers containing max frequency entry.
 	 * LUT registers are only writeable in debug mode. */
-	writel_relaxed(SCPLL_DEBUG_FULL,
-		       sc_pll_base[sc_pll] + SCPLL_DEBUG_OFFSET);
-	writel_relaxed(0x0, sc_pll_base[sc_pll] + SCPLL_LUT_A_HW_MAX);
-	writel_relaxed(SCPLL_DEBUG_NONE,
-		       sc_pll_base[sc_pll] + SCPLL_DEBUG_OFFSET);
+	writel_relaxed(SCPLL_DEBUG_FULL, sc_pll_base[pll] + SCPLL_DEBUG_OFFSET);
+	writel_relaxed(0x0, sc_pll_base[pll] + SCPLL_LUT_OFFSET(max_l_val));
+	writel_relaxed(SCPLL_DEBUG_NONE, sc_pll_base[pll] + SCPLL_DEBUG_OFFSET);
 
 	/* Power-up SCPLL into standby mode. */
-	writel_relaxed(SCPLL_STANDBY, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
+	writel_relaxed(SCPLL_STANDBY, sc_pll_base[pll] + SCPLL_CTL_OFFSET);
 	mb();
 	udelay(10);
 
-	/* Calibrate the SCPLL to the maximum range supported by the h/w. We
-	 * might not use the full range of calibrated frequencies, but this
-	 * simplifies changes required for future increases in max CPU freq.
-	 */
-	regval = (L_VAL_SCPLL_CAL_MAX << 24) | (L_VAL_SCPLL_CAL_MIN << 16);
-	writel_relaxed(regval, sc_pll_base[sc_pll] + SCPLL_CAL_OFFSET);
+	/* Calibrate the SCPLL for the frequency range needed. */
+	regval = (max_l_val << 24) | (L_VAL_SCPLL_CAL_MIN << 16);
+	writel_relaxed(regval, sc_pll_base[pll] + SCPLL_CAL_OFFSET);
 
 	/* Start calibration */
-	writel_relaxed(SCPLL_FULL_CAL, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
+	writel_relaxed(SCPLL_FULL_CAL, sc_pll_base[pll] + SCPLL_CTL_OFFSET);
 
 	/* Wait for proof that calibration has started before checking the
 	 * 'calibration done' bit in the status register. Waiting for the
@@ -704,15 +773,15 @@
 	 * This is required since the 'calibration done' bit takes time to
 	 * transition from 'done' to 'not done' when starting a calibration.
 	 */
-	while (readl_relaxed(sc_pll_base[sc_pll] + SCPLL_LUT_A_HW_MAX) == 0)
+	while (!readl_relaxed(sc_pll_base[pll] + SCPLL_LUT_OFFSET(max_l_val)))
 		cpu_relax();
 
 	/* Wait for calibration to complete. */
-	while (readl_relaxed(sc_pll_base[sc_pll] + SCPLL_STATUS_OFFSET) & 0x2)
+	while (readl_relaxed(sc_pll_base[pll] + SCPLL_STATUS_OFFSET) & 0x2)
 		cpu_relax();
 
 	/* Power-down SCPLL. */
-	scpll_disable(sc_pll);
+	scpll_disable(pll);
 }
 
 /* Force ACPU core and L2 cache clocks to rates that don't require SCPLLs. */
@@ -859,7 +928,7 @@
 	.notifier_call = acpuclock_cpu_callback,
 };
 
-static unsigned int __init select_freq_plan(void)
+static __init struct clkctl_acpu_speed *select_freq_plan(void)
 {
 	uint32_t pte_efuse, speed_bin, pvs, max_khz;
 	struct clkctl_acpu_speed *f;
@@ -870,12 +939,41 @@
 	if (speed_bin == 0xF)
 		speed_bin = (pte_efuse >> 4) & 0xF;
 
-	if (speed_bin == 0x1) {
-		max_khz = 1512000;
-		pvs = (pte_efuse >> 10) & 0x7;
-		if (pvs == 0x7)
-			pvs = (pte_efuse >> 13) & 0x7;
+	pvs = (pte_efuse >> 10) & 0x7;
+	if (pvs == 0x7)
+		pvs = (pte_efuse >> 13) & 0x7;
 
+	if (speed_bin == 0x2) {
+		max_khz = 1674000;
+		switch (pvs) {
+		case 0x7:
+		case 0x5:
+			acpu_freq_tbl = acpu_freq_tbl_slowest;
+			pr_info("ACPU PVS: Slowest\n");
+			break;
+		case 0x4:
+			acpu_freq_tbl = acpu_freq_tbl_slower;
+			pr_info("ACPU PVS: Slower\n");
+			break;
+		case 0x0:
+			acpu_freq_tbl = acpu_freq_tbl_slow;
+			pr_info("ACPU PVS: Slow\n");
+			break;
+		case 0x1:
+			acpu_freq_tbl = acpu_freq_tbl_nom;
+			pr_info("ACPU PVS: Nominal\n");
+			break;
+		case 0x3:
+			acpu_freq_tbl = acpu_freq_tbl_fast;
+			pr_info("ACPU PVS: Fast\n");
+			break;
+		default:
+			acpu_freq_tbl = acpu_freq_tbl_slowest;
+			pr_warn("ACPU PVS: Unknown. Defaulting to slowest.\n");
+			break;
+		}
+	} else if (speed_bin == 0x1) {
+		max_khz = 1512000;
 		switch (pvs) {
 		case 0x0:
 		case 0x7:
@@ -910,7 +1008,7 @@
 	f--;
 	pr_info("Max ACPU freq: %u KHz\n", f->acpuclk_khz);
 
-	return f->acpuclk_khz;
+	return f;
 }
 
 static struct acpuclk_data acpuclk_8x60_data = {
@@ -922,25 +1020,25 @@
 
 static int __init acpuclk_8x60_init(struct acpuclk_soc_data *soc_data)
 {
-	unsigned int max_cpu_khz;
+	struct clkctl_acpu_speed *max_freq;
 	int cpu;
 
 	mutex_init(&drv_state.lock);
 	spin_lock_init(&drv_state.l2_lock);
 
 	/* Configure hardware. */
-	max_cpu_khz = select_freq_plan();
+	max_freq = select_freq_plan();
 	unselect_scplls();
 	scpll_set_refs();
 	for_each_possible_cpu(cpu)
-		scpll_init(cpu);
-	scpll_init(L2);
+		scpll_init(cpu, max_freq->l_val);
+	scpll_init(L2, max_freq->l2_level->l_val);
 	regulator_init();
 	bus_init();
 
 	/* Improve boot time by ramping up CPUs immediately. */
 	for_each_online_cpu(cpu)
-		acpuclk_8x60_set_rate(cpu, max_cpu_khz, SETRATE_INIT);
+		acpuclk_8x60_set_rate(cpu, max_freq->acpuclk_khz, SETRATE_INIT);
 
 	acpuclk_register(&acpuclk_8x60_data);
 	cpufreq_table_init();
diff --git a/arch/arm/mach-msm/acpuclock-copper.c b/arch/arm/mach-msm/acpuclock-copper.c
new file mode 100644
index 0000000..1a02c06
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-copper.c
@@ -0,0 +1,210 @@
+/*
+ * 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/platform_device.h>
+#include <linux/of.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include <mach/socinfo.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* Corner type vreg VDD values */
+#define LVL_NONE	RPM_VREG_CORNER_NONE
+#define LVL_LOW		RPM_VREG_CORNER_LOW
+#define LVL_NOM		RPM_VREG_CORNER_NOMINAL
+#define LVL_HIGH	RPM_VREG_CORNER_HIGH
+
+static struct hfpll_data hfpll_data_cpu = {
+	.mode_offset = 0x00,
+	.l_offset = 0x04,
+	.m_offset = 0x08,
+	.n_offset = 0x0C,
+	.config_offset = 0x14,
+	/* TODO: Verify magic number for copper when available. */
+	.config_val = 0x7845C665,
+	.low_vdd_l_max = 52,
+	.vdd[HFPLL_VDD_NONE] = 0,
+	.vdd[HFPLL_VDD_LOW]  = 810000,
+	.vdd[HFPLL_VDD_NOM]  = 900000,
+};
+
+static struct hfpll_data hfpll_data_l2 = {
+	.mode_offset = 0x00,
+	.l_offset = 0x04,
+	.m_offset = 0x08,
+	.n_offset = 0x0C,
+	.config_offset = 0x14,
+	/* TODO: Verify magic number for copper when available. */
+	.config_val = 0x7845C665,
+	.low_vdd_l_max = 52,
+	.vdd[HFPLL_VDD_NONE] = LVL_NONE,
+	.vdd[HFPLL_VDD_LOW]  = LVL_LOW,
+	.vdd[HFPLL_VDD_NOM]  = LVL_NOM,
+};
+
+static struct scalable scalable[] = {
+	[CPU0] = {
+		.hfpll_phys_base = 0xF908A000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x4501,
+		.vreg[VREG_CORE] = { "krait0",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait0_mem", 1050000, 0,
+				     RPM_VREG_VOTER1,
+				     RPM_VREG_ID_PM8941_S1 },
+		.vreg[VREG_DIG]  = { "krait0_dig", 1050000, 0,
+				     RPM_VREG_VOTER1,
+				     RPM_VREG_ID_PM8941_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER1,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[CPU1] = {
+		.hfpll_phys_base = 0xF909A000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x5501,
+		.vreg[VREG_CORE] = { "krait1",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait1_mem", 1050000, 0,
+				     RPM_VREG_VOTER2,
+				     RPM_VREG_ID_PM8941_S1 },
+		.vreg[VREG_DIG]  = { "krait1_dig", 1050000, 0,
+				     RPM_VREG_VOTER2,
+				     RPM_VREG_ID_PM8941_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER2,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[CPU2] = {
+		.hfpll_phys_base = 0xF90AA000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x6501,
+		.vreg[VREG_CORE] = { "krait2",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait2_mem", 1050000, 0,
+				     RPM_VREG_VOTER4,
+				     RPM_VREG_ID_PM8921_S1 },
+		.vreg[VREG_DIG]  = { "krait2_dig", 1050000, 0,
+				     RPM_VREG_VOTER4,
+				     RPM_VREG_ID_PM8921_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER4,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[CPU3] = {
+		.hfpll_phys_base = 0xF90BA000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x7501,
+		.vreg[VREG_CORE] = { "krait3",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait3_mem", 1050000, 0,
+				     RPM_VREG_VOTER5,
+				     RPM_VREG_ID_PM8941_S1 },
+		.vreg[VREG_DIG]  = { "krait3_dig", 1050000, 0,
+				     RPM_VREG_VOTER5,
+				     RPM_VREG_ID_PM8941_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER5,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[L2] = {
+		.hfpll_phys_base = 0xF9016000,
+		.hfpll_data = &hfpll_data_l2,
+		.l2cpmr_iaddr = 0x0500,
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER6,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+};
+
+static struct msm_bus_paths bw_level_tbl[] = {
+	[0] =  BW_MBPS(400), /* At least  50 MHz on bus. */
+	[1] =  BW_MBPS(800), /* At least 100 MHz on bus. */
+	[2] = BW_MBPS(1334), /* At least 167 MHz on bus. */
+	[3] = BW_MBPS(2666), /* At least 200 MHz on bus. */
+	[4] = BW_MBPS(3200), /* At least 333 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data = {
+	.usecase = bw_level_tbl,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl),
+	.active_only = 1,
+	.name = "acpuclk-copper",
+};
+
+#define L2(x) (&l2_freq_tbl[(x)])
+static struct l2_level l2_freq_tbl[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0,   0 }, LVL_NOM, 1050000, 0 },
+	[1]  = { {  300000, PLL_0, 0, 2,   0 }, LVL_NOM, 1050000, 2 },
+	[2]  = { {  384000, HFPLL, 2, 0,  40 }, LVL_NOM, 1050000, 2 },
+	[3]  = { {  460800, HFPLL, 2, 0,  48 }, LVL_NOM, 1050000, 2 },
+	[4]  = { {  537600, HFPLL, 1, 0,  28 }, LVL_NOM, 1050000, 2 },
+	[5]  = { {  576000, HFPLL, 1, 0,  30 }, LVL_NOM, 1050000, 3 },
+	[6]  = { {  652800, HFPLL, 1, 0,  34 }, LVL_NOM, 1050000, 3 },
+	[7]  = { {  729600, HFPLL, 1, 0,  38 }, LVL_NOM, 1050000, 3 },
+	[8]  = { {  806400, HFPLL, 1, 0,  42 }, LVL_NOM, 1050000, 3 },
+	[9]  = { {  883200, HFPLL, 1, 0,  46 }, LVL_NOM, 1050000, 4 },
+	[10] = { {  960000, HFPLL, 1, 0,  50 }, LVL_NOM, 1050000, 4 },
+	[11] = { { 1036800, HFPLL, 1, 0,  54 }, LVL_NOM, 1050000, 4 },
+};
+
+static struct acpu_level acpu_freq_tbl[] = {
+	{ 0, {STBY_KHZ, QSB,   0, 0,   0 }, L2(0),  1050000 },
+	{ 1, {  300000, PLL_0, 0, 2,   0 }, L2(1),  1050000 },
+	{ 1, {  384000, HFPLL, 2, 0,  40 }, L2(2),  1050000 },
+	{ 1, {  460800, HFPLL, 2, 0,  48 }, L2(3),  1050000 },
+	{ 1, {  537600, HFPLL, 1, 0,  28 }, L2(4),  1050000 },
+	{ 1, {  576000, HFPLL, 1, 0,  30 }, L2(5),  1050000 },
+	{ 1, {  652800, HFPLL, 1, 0,  34 }, L2(6),  1050000 },
+	{ 1, {  729600, HFPLL, 1, 0,  38 }, L2(7),  1050000 },
+	{ 1, {  806400, HFPLL, 1, 0,  42 }, L2(8),  1050000 },
+	{ 1, {  883200, HFPLL, 1, 0,  46 }, L2(9),  1050000 },
+	{ 1, {  960000, HFPLL, 1, 0,  50 }, L2(10), 1050000 },
+	{ 1, { 1036800, HFPLL, 1, 0,  54 }, L2(11), 1050000 },
+	{ 0, { 0 } }
+};
+
+static struct acpuclk_krait_params acpuclk_copper_params = {
+	.scalable = scalable,
+	.pvs_acpu_freq_tbl[PVS_SLOW] = acpu_freq_tbl,
+	.pvs_acpu_freq_tbl[PVS_NOMINAL] = acpu_freq_tbl,
+	.pvs_acpu_freq_tbl[PVS_FAST] = acpu_freq_tbl,
+	.l2_freq_tbl = l2_freq_tbl,
+	.l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl),
+	.bus_scale_data = &bus_scale_data,
+	.qfprom_phys_base = 0xFC4A8000,
+};
+
+static int __init acpuclk_copper_probe(struct platform_device *pdev)
+{
+	return acpuclk_krait_init(&pdev->dev, &acpuclk_copper_params);
+}
+
+static struct of_device_id acpuclk_copper_match_table[] = {
+	{ .compatible = "qcom,acpuclk-copper" },
+	{}
+};
+
+static struct platform_driver acpuclk_copper_driver = {
+	.driver = {
+		.name = "acpuclk-copper",
+		.of_match_table = acpuclk_copper_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init acpuclk_8960_init(void)
+{
+	return platform_driver_probe(&acpuclk_copper_driver,
+				     acpuclk_copper_probe);
+}
+device_initcall(acpuclk_8960_init);
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
new file mode 100644
index 0000000..5682ac3
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -0,0 +1,784 @@
+/*
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/mach-types.h>
+#include <asm/cpu.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* MUX source selects. */
+#define PRI_SRC_SEL_SEC_SRC	0
+#define PRI_SRC_SEL_HFPLL	1
+#define PRI_SRC_SEL_HFPLL_DIV2	2
+#define SEC_SRC_SEL_QSB		0
+#define SEC_SRC_SEL_L2PLL	1
+#define SEC_SRC_SEL_AUX		2
+
+/* PTE EFUSE register offset. */
+#define PTE_EFUSE		0xC0
+
+static DEFINE_MUTEX(driver_lock);
+static DEFINE_SPINLOCK(l2_lock);
+
+static struct drv_data {
+	const struct acpu_level *acpu_freq_tbl;
+	const struct l2_level *l2_freq_tbl;
+	struct scalable *scalable;
+	u32 bus_perf_client;
+	struct device *dev;
+} drv;
+
+static unsigned long acpuclk_krait_get_rate(int cpu)
+{
+	return drv.scalable[cpu].cur_speed->khz;
+}
+
+/* Select a source on the primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+{
+	u32 regval;
+
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~0x3;
+	regval |= (pri_src_sel & 0x3);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+
+/* Select a source on the secondary MUX. */
+static void set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
+{
+	u32 regval;
+
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~(0x3 << 2);
+	regval |= ((sec_src_sel & 0x3) << 2);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+
+/* Enable an already-configured HFPLL. */
+static void hfpll_enable(struct scalable *sc, bool skip_regulators)
+{
+	int rc;
+
+	if (!skip_regulators) {
+		/* Enable regulators required by the HFPLL. */
+		if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+				sc->vreg[VREG_HFPLL_A].cur_vdd,
+				sc->vreg[VREG_HFPLL_A].max_vdd, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_A].name, rc);
+		}
+		if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
+				sc->vreg[VREG_HFPLL_B].cur_vdd,
+				sc->vreg[VREG_HFPLL_B].max_vdd, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_B].name, rc);
+		}
+	}
+
+	/* Disable PLL bypass mode. */
+	writel_relaxed(0x2, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	writel_relaxed(0x6, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+	/* Wait for PLL to lock. */
+	mb();
+	udelay(60);
+
+	/* Enable PLL output. */
+	writel_relaxed(0x7, sc->hfpll_base + sc->hfpll_data->mode_offset);
+}
+
+/* Disable a HFPLL for power-savings or while it's being reprogrammed. */
+static void hfpll_disable(struct scalable *sc, bool skip_regulators)
+{
+	int rc;
+
+	/*
+	 * Disable the PLL output, disable test mode, enable the bypass mode,
+	 * and assert the reset.
+	 */
+	writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+	if (!skip_regulators) {
+		/* Remove voltage votes required by the HFPLL. */
+		if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
+				0, 0, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_B].name, rc);
+		}
+		if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+				0, 0, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_A].name, rc);
+		}
+	}
+}
+
+/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
+static void hfpll_set_rate(struct scalable *sc, const struct core_speed *tgt_s)
+{
+	writel_relaxed(tgt_s->pll_l_val,
+		sc->hfpll_base + sc->hfpll_data->l_offset);
+}
+
+/* Return the L2 speed that should be applied. */
+static const struct l2_level *compute_l2_level(struct scalable *sc,
+					       const struct l2_level *vote_l)
+{
+	const struct l2_level *new_l;
+	int cpu;
+
+	/* Find max L2 speed vote. */
+	sc->l2_vote = vote_l;
+	new_l = drv.l2_freq_tbl;
+	for_each_present_cpu(cpu)
+		new_l = max(new_l, drv.scalable[cpu].l2_vote);
+
+	return new_l;
+}
+
+/* Update the bus bandwidth request. */
+static void set_bus_bw(unsigned int bw)
+{
+	int ret;
+
+	/* Update bandwidth if request has changed. This may sleep. */
+	ret = msm_bus_scale_client_update_request(drv.bus_perf_client, bw);
+	if (ret)
+		dev_err(drv.dev, "bandwidth request failed (%d)\n", ret);
+}
+
+/* Set the CPU or L2 clock speed. */
+static void set_speed(struct scalable *sc, const struct core_speed *tgt_s)
+{
+	const struct core_speed *strt_s = sc->cur_speed;
+
+	if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
+		/*
+		 * Move to an always-on source running at a frequency
+		 * that does not require an elevated CPU voltage.
+		 */
+		set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+		set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+
+		/* Re-program HFPLL. */
+		hfpll_disable(sc, 1);
+		hfpll_set_rate(sc, tgt_s);
+		hfpll_enable(sc, 1);
+
+		/* Move to HFPLL. */
+		set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
+		set_sec_clk_src(sc, tgt_s->sec_src_sel);
+		set_pri_clk_src(sc, tgt_s->pri_src_sel);
+		hfpll_disable(sc, 0);
+	} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
+		hfpll_set_rate(sc, tgt_s);
+		hfpll_enable(sc, 0);
+		set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	} else {
+		set_sec_clk_src(sc, tgt_s->sec_src_sel);
+	}
+
+	sc->cur_speed = tgt_s;
+}
+
+/* Apply any per-cpu voltage increases. */
+static int increase_vdd(int cpu, int vdd_core, int vdd_mem, int vdd_dig,
+			enum setrate_reason reason)
+{
+	struct scalable *sc = &drv.scalable[cpu];
+	int rc = 0;
+
+	/*
+	 * Increase vdd_mem active-set before vdd_dig.
+	 * vdd_mem should be >= vdd_dig.
+	 */
+	if (vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (rc) {
+			dev_err(drv.dev,
+				"vdd_mem (cpu%d) increase failed (%d)\n",
+				cpu, rc);
+			return rc;
+		}
+		 sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+	}
+
+	/* Increase vdd_dig active-set vote. */
+	if (vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (rc) {
+			dev_err(drv.dev,
+				"vdd_dig (cpu%d) increase failed (%d)\n",
+				cpu, rc);
+			return rc;
+		}
+		sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+	}
+
+	/*
+	 * Update per-CPU core voltage. Don't do this for the hotplug path for
+	 * which it should already be correct. Attempting to set it is bad
+	 * because we don't know what CPU we are running on at this point, but
+	 * the CPU regulator API requires we call it from the affected CPU.
+	 */
+	if (vdd_core > sc->vreg[VREG_CORE].cur_vdd
+			&& reason != SETRATE_HOTPLUG) {
+		rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					   sc->vreg[VREG_CORE].max_vdd);
+		if (rc) {
+			dev_err(drv.dev,
+				"vdd_core (cpu%d) increase failed (%d)\n",
+				cpu, rc);
+			return rc;
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+	}
+
+	return rc;
+}
+
+/* Apply any per-cpu voltage decreases. */
+static void decrease_vdd(int cpu, int vdd_core, int vdd_mem, int vdd_dig,
+			enum setrate_reason reason)
+{
+	struct scalable *sc = &drv.scalable[cpu];
+	int ret;
+
+	/*
+	 * Update per-CPU core voltage. This must be called on the CPU
+	 * that's being affected. Don't do this in the hotplug remove path,
+	 * where the rail is off and we're executing on the other CPU.
+	 */
+	if (vdd_core < sc->vreg[VREG_CORE].cur_vdd
+			&& reason != SETRATE_HOTPLUG) {
+		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					    sc->vreg[VREG_CORE].max_vdd);
+		if (ret) {
+			dev_err(drv.dev,
+				"vdd_core (cpu%d) decrease failed (%d)\n",
+				cpu, ret);
+			return;
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+	}
+
+	/* Decrease vdd_dig active-set vote. */
+	if (vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev,
+				"vdd_dig (cpu%d) decrease failed (%d)\n",
+				cpu, ret);
+			return;
+		}
+		sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+	}
+
+	/*
+	 * Decrease vdd_mem active-set after vdd_dig.
+	 * vdd_mem should be >= vdd_dig.
+	 */
+	if (vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev,
+				"vdd_mem (cpu%d) decrease failed (%d)\n",
+				cpu, ret);
+			return;
+		}
+		 sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+	}
+}
+
+static int calculate_vdd_mem(const struct acpu_level *tgt)
+{
+	return tgt->l2_level->vdd_mem;
+}
+
+static int calculate_vdd_dig(const struct acpu_level *tgt)
+{
+	int pll_vdd_dig;
+	const int *hfpll_vdd = drv.scalable[L2].hfpll_data->vdd;
+	const u32 low_vdd_l_max = drv.scalable[L2].hfpll_data->low_vdd_l_max;
+
+	if (tgt->l2_level->speed.src != HFPLL)
+		pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NONE];
+	else if (tgt->l2_level->speed.pll_l_val > low_vdd_l_max)
+		pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NOM];
+	else
+		pll_vdd_dig = hfpll_vdd[HFPLL_VDD_LOW];
+
+	return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
+}
+
+static int calculate_vdd_core(const struct acpu_level *tgt)
+{
+	return tgt->vdd_core;
+}
+
+/* Set the CPU's clock rate and adjust the L2 rate, voltage and BW requests. */
+static int acpuclk_krait_set_rate(int cpu, unsigned long rate,
+				  enum setrate_reason reason)
+{
+	const struct core_speed *strt_acpu_s, *tgt_acpu_s;
+	const struct l2_level *tgt_l2_l;
+	const struct acpu_level *tgt;
+	int vdd_mem, vdd_dig, vdd_core;
+	unsigned long flags;
+	int rc = 0;
+
+	if (cpu > num_possible_cpus()) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_lock(&driver_lock);
+
+	strt_acpu_s = drv.scalable[cpu].cur_speed;
+
+	/* Return early if rate didn't change. */
+	if (rate == strt_acpu_s->khz)
+		goto out;
+
+	/* Find target frequency. */
+	for (tgt = drv.acpu_freq_tbl; tgt->speed.khz != 0; tgt++) {
+		if (tgt->speed.khz == rate) {
+			tgt_acpu_s = &tgt->speed;
+			break;
+		}
+	}
+	if (tgt->speed.khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Calculate voltage requirements for the current CPU. */
+	vdd_mem  = calculate_vdd_mem(tgt);
+	vdd_dig  = calculate_vdd_dig(tgt);
+	vdd_core = calculate_vdd_core(tgt);
+
+	/* Increase VDD levels if needed. */
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
+		rc = increase_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+		if (rc)
+			goto out;
+	}
+
+	pr_debug("Switching from ACPU%d rate %lu KHz -> %lu KHz\n",
+		 cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
+
+	/* Set the new CPU speed. */
+	set_speed(&drv.scalable[cpu], tgt_acpu_s);
+
+	/*
+	 * Update the L2 vote and apply the rate change. A spinlock is
+	 * necessary to ensure L2 rate is calculated and set atomically
+	 * with the CPU frequency, even if acpuclk_krait_set_rate() is
+	 * called from an atomic context and the driver_lock mutex is not
+	 * acquired.
+	 */
+	spin_lock_irqsave(&l2_lock, flags);
+	tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
+	set_speed(&drv.scalable[L2], &tgt_l2_l->speed);
+	spin_unlock_irqrestore(&l2_lock, flags);
+
+	/* Nothing else to do for power collapse or SWFI. */
+	if (reason == SETRATE_PC || reason == SETRATE_SWFI)
+		goto out;
+
+	/* Update bus bandwith request. */
+	set_bus_bw(tgt_l2_l->bw_level);
+
+	/* Drop VDD levels if we can. */
+	decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+
+	pr_debug("ACPU%d speed change complete\n", cpu);
+
+out:
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_unlock(&driver_lock);
+	return rc;
+}
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __init hfpll_init(struct scalable *sc,
+			      const struct core_speed *tgt_s)
+{
+	pr_debug("Initializing HFPLL%d\n", sc - drv.scalable);
+
+	/* Disable the PLL for re-programming. */
+	hfpll_disable(sc, 1);
+
+	/* Configure PLL parameters for integer mode. */
+	writel_relaxed(sc->hfpll_data->config_val,
+		       sc->hfpll_base + sc->hfpll_data->config_offset);
+	writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->m_offset);
+	writel_relaxed(1, sc->hfpll_base + sc->hfpll_data->n_offset);
+
+	/* Set an initial rate and enable the PLL. */
+	hfpll_set_rate(sc, tgt_s);
+	hfpll_enable(sc, 0);
+}
+
+/* Voltage regulator initialization. */
+static void __init regulator_init(const struct acpu_level *lvl)
+{
+	int cpu, ret;
+	struct scalable *sc;
+	int vdd_mem, vdd_dig, vdd_core;
+
+	vdd_mem = calculate_vdd_mem(lvl);
+	vdd_dig = calculate_vdd_dig(lvl);
+
+	for_each_possible_cpu(cpu) {
+		sc = &drv.scalable[cpu];
+
+		/* Set initial vdd_mem vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev, "%s initialization failed (%d)\n",
+				sc->vreg[VREG_MEM].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_MEM].cur_vdd  = vdd_mem;
+
+		/* Set initial vdd_dig vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev, "%s initialization failed (%d)\n",
+				sc->vreg[VREG_DIG].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_DIG].cur_vdd  = vdd_dig;
+
+		/* Setup Krait CPU regulators and initial core voltage. */
+		sc->vreg[VREG_CORE].reg = regulator_get(NULL,
+					  sc->vreg[VREG_CORE].name);
+		if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
+			dev_err(drv.dev, "regulator_get(%s) failed (%ld)\n",
+				sc->vreg[VREG_CORE].name,
+				PTR_ERR(sc->vreg[VREG_CORE].reg));
+			BUG();
+		}
+		vdd_core = calculate_vdd_core(lvl);
+		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					    sc->vreg[VREG_CORE].max_vdd);
+		if (ret) {
+			dev_err(drv.dev, "regulator_set_voltage(%s) (%d)\n",
+				sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+		ret = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
+						 sc->vreg[VREG_CORE].peak_ua);
+		if (ret < 0) {
+			dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed"
+				" (%d)\n", sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+		ret = regulator_enable(sc->vreg[VREG_CORE].reg);
+		if (ret) {
+			dev_err(drv.dev, "regulator_enable(%s) failed (%d)\n",
+				sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+	}
+}
+
+/* Set initial rate for a given core. */
+static void __init init_clock_sources(struct scalable *sc,
+				      const struct core_speed *tgt_s)
+{
+	u32 regval;
+
+	/* Program AUX source input to the secondary MUX. */
+	if (sc->aux_clk_sel_addr)
+		writel_relaxed(sc->aux_clk_sel, sc->aux_clk_sel_addr);
+
+	/* Switch away from the HFPLL while it's re-initialized. */
+	set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+	set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+	hfpll_init(sc, tgt_s);
+
+	/* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~(0x3 << 6);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* Switch to the target clock source. */
+	set_sec_clk_src(sc, tgt_s->sec_src_sel);
+	set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	sc->cur_speed = tgt_s;
+}
+
+static void __init per_cpu_init(int cpu, const struct acpu_level *max_level)
+{
+	drv.scalable[cpu].hfpll_base =
+		ioremap(drv.scalable[cpu].hfpll_phys_base, SZ_32);
+	BUG_ON(!drv.scalable[cpu].hfpll_base);
+
+	init_clock_sources(&drv.scalable[cpu], &max_level->speed);
+	drv.scalable[cpu].l2_vote = max_level->l2_level;
+}
+
+/* Register with bus driver. */
+static void __init bus_init(struct msm_bus_scale_pdata *bus_scale_data,
+			    unsigned int init_bw)
+{
+	int ret;
+
+	drv.bus_perf_client = msm_bus_scale_register_client(bus_scale_data);
+	if (!drv.bus_perf_client) {
+		dev_err(drv.dev, "unable to register bus client\n");
+		BUG();
+	}
+
+	ret = msm_bus_scale_client_update_request(drv.bus_perf_client, init_bw);
+	if (ret)
+		dev_err(drv.dev, "initial bandwidth req failed (%d)\n", ret);
+}
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[NR_CPUS][35];
+
+static void __init cpufreq_table_init(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		int i, freq_cnt = 0;
+		/* Construct the freq_table tables from acpu_freq_tbl. */
+		for (i = 0; drv.acpu_freq_tbl[i].speed.khz != 0
+				&& freq_cnt < ARRAY_SIZE(*freq_table); i++) {
+			if (drv.acpu_freq_tbl[i].use_for_scaling) {
+				freq_table[cpu][freq_cnt].index = freq_cnt;
+				freq_table[cpu][freq_cnt].frequency
+					= drv.acpu_freq_tbl[i].speed.khz;
+				freq_cnt++;
+			}
+		}
+		/* freq_table not big enough to store all usable freqs. */
+		BUG_ON(drv.acpu_freq_tbl[i].speed.khz != 0);
+
+		freq_table[cpu][freq_cnt].index = freq_cnt;
+		freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+		dev_info(drv.dev, "CPU%d: %d frequencies supported\n",
+			cpu, freq_cnt);
+
+		/* Register table with CPUFreq. */
+		cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+	}
+}
+#else
+static void __init cpufreq_table_init(void) {}
+#endif
+
+#define HOT_UNPLUG_KHZ STBY_KHZ
+static int __cpuinit acpuclk_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	static int prev_khz[NR_CPUS];
+	int rc, cpu = (int)hcpu;
+	struct scalable *sc = &drv.scalable[cpu];
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_DEAD:
+		prev_khz[cpu] = acpuclk_krait_get_rate(cpu);
+		/* Fall through. */
+	case CPU_UP_CANCELED:
+		acpuclk_krait_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+		regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg, 0);
+		break;
+	case CPU_UP_PREPARE:
+		if (WARN_ON(!prev_khz[cpu]))
+			return NOTIFY_BAD;
+		rc = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
+						sc->vreg[VREG_CORE].peak_ua);
+		if (rc < 0)
+			return NOTIFY_BAD;
+		acpuclk_krait_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata acpuclk_cpu_notifier = {
+	.notifier_call = acpuclk_cpu_callback,
+};
+
+static const struct acpu_level __init *select_freq_plan(
+		const struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
+{
+	const struct acpu_level *l, *max_acpu_level = NULL;
+	void __iomem *qfprom_base;
+	u32 pte_efuse, pvs, tbl_idx;
+	char *pvs_names[] = { "Slow", "Nominal", "Fast", "Unknown" };
+
+	qfprom_base = ioremap(qfprom_phys, SZ_256);
+	/* Select frequency tables. */
+	if (qfprom_base) {
+		pte_efuse = readl_relaxed(qfprom_base + PTE_EFUSE);
+		pvs = (pte_efuse >> 10) & 0x7;
+		iounmap(qfprom_base);
+		if (pvs == 0x7)
+			pvs = (pte_efuse >> 13) & 0x7;
+
+		switch (pvs) {
+		case 0x0:
+		case 0x7:
+			tbl_idx = PVS_SLOW;
+			break;
+		case 0x1:
+			tbl_idx = PVS_NOMINAL;
+			break;
+		case 0x3:
+			tbl_idx = PVS_FAST;
+			break;
+		default:
+			tbl_idx = PVS_UNKNOWN;
+			break;
+		}
+	} else {
+		tbl_idx = PVS_UNKNOWN;
+		dev_err(drv.dev, "Unable to map QFPROM base\n");
+	}
+	dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
+	if (tbl_idx == PVS_UNKNOWN) {
+		tbl_idx = PVS_SLOW;
+		dev_warn(drv.dev, "ACPU PVS: Defaulting to %s\n",
+			 pvs_names[tbl_idx]);
+	}
+	drv.acpu_freq_tbl = pvs_tbl[tbl_idx];
+
+	/* Find the max supported scaling frequency. */
+	for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
+		if (l->use_for_scaling)
+			max_acpu_level = l;
+	BUG_ON(!max_acpu_level);
+	dev_info(drv.dev, "Max ACPU freq: %lu KHz\n",
+		 max_acpu_level->speed.khz);
+
+	return max_acpu_level;
+}
+
+static struct acpuclk_data acpuclk_krait_data = {
+	.set_rate = acpuclk_krait_set_rate,
+	.get_rate = acpuclk_krait_get_rate,
+	.power_collapse_khz = STBY_KHZ,
+	.wait_for_irq_khz = STBY_KHZ,
+};
+
+int __init acpuclk_krait_init(struct device *dev,
+			      const struct acpuclk_krait_params *params)
+{
+	const struct acpu_level *max_acpu_level;
+	int cpu;
+
+	drv.scalable = params->scalable;
+	drv.l2_freq_tbl = params->l2_freq_tbl;
+	drv.dev = dev;
+
+	drv.scalable[L2].hfpll_base =
+		ioremap(drv.scalable[L2].hfpll_phys_base, SZ_32);
+	BUG_ON(!drv.scalable[L2].hfpll_base);
+
+	max_acpu_level = select_freq_plan(params->pvs_acpu_freq_tbl,
+					  params->qfprom_phys_base);
+	regulator_init(max_acpu_level);
+	bus_init(params->bus_scale_data, max_acpu_level->l2_level->bw_level);
+	init_clock_sources(&drv.scalable[L2], &max_acpu_level->l2_level->speed);
+	for_each_online_cpu(cpu)
+		per_cpu_init(cpu, max_acpu_level);
+
+	cpufreq_table_init();
+
+	acpuclk_register(&acpuclk_krait_data);
+	register_hotcpu_notifier(&acpuclk_cpu_notifier);
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
new file mode 100644
index 0000000..fbf1f5f
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -0,0 +1,222 @@
+/*
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
+#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
+
+#define STBY_KHZ		1
+
+#define BW_MBPS(_bw) \
+	{ \
+		.vectors = (struct msm_bus_vectors[]){ \
+			{\
+				.src = MSM_BUS_MASTER_AMPSS_M0, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+				.ib = (_bw) * 1000000UL, \
+			}, \
+			{ \
+				.src = MSM_BUS_MASTER_AMPSS_M1, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+				.ib = (_bw) * 1000000UL, \
+			}, \
+		}, \
+		.num_paths = 2, \
+	}
+
+/**
+ * src_id - Clock source IDs.
+ */
+enum src_id {
+	PLL_0 = 0,
+	HFPLL,
+	QSB,
+};
+
+/**
+ * enum pvs - IDs to distinguish between CPU frequency tables.
+ */
+enum pvs {
+	PVS_SLOW = 0,
+	PVS_NOMINAL,
+	PVS_FAST,
+	PVS_UNKNOWN,
+	NUM_PVS
+};
+
+/**
+ * enum scalables - IDs of frequency scalable hardware blocks.
+ */
+enum scalables {
+	CPU0 = 0,
+	CPU1,
+	CPU2,
+	CPU3,
+	L2,
+};
+
+
+/**
+ * enum hfpll_vdd_level - IDs of HFPLL voltage levels.
+ */
+enum hfpll_vdd_levels {
+	HFPLL_VDD_NONE,
+	HFPLL_VDD_LOW,
+	HFPLL_VDD_NOM,
+	NUM_HFPLL_VDD
+};
+
+/**
+ * enum vregs - IDs of voltage regulators.
+ */
+enum vregs {
+	VREG_CORE,
+	VREG_MEM,
+	VREG_DIG,
+	VREG_HFPLL_A,
+	VREG_HFPLL_B,
+	NUM_VREG
+};
+
+/**
+ * struct vreg - Voltage regulator data.
+ * @name: Name of requlator.
+ * @max_vdd: Limit the maximum-settable voltage.
+ * @rpm_vreg_id: ID to use with rpm_vreg_*() APIs.
+ * @reg: Regulator handle.
+ * @cur_vdd: Last-set voltage in uV.
+ * @peak_ua: Maximum current draw expected in uA.
+ */
+struct vreg {
+	const char name[15];
+	const int max_vdd;
+	const int peak_ua;
+	const int rpm_vreg_voter;
+	const int rpm_vreg_id;
+	struct regulator *reg;
+	int cur_vdd;
+};
+
+/**
+ * struct core_speed - Clock tree and configuration parameters.
+ * @khz: Clock rate in KHz.
+ * @src: Clock source ID.
+ * @pri_src_sel: Input to select on the primary MUX.
+ * @sec_src_sel: Input to select on the secondary MUX.
+ * @pll_l_val: HFPLL "L" value to be applied when an HFPLL source is selected.
+ */
+struct core_speed {
+	const unsigned long khz;
+	const int src;
+	const u32 pri_src_sel;
+	const u32 sec_src_sel;
+	const u32 pll_l_val;
+};
+
+/**
+ * struct l2_level - L2 clock rate and associated voltage and b/w requirements.
+ * @speed: L2 clock configuration.
+ * @vdd_dig: vdd_dig voltage in uV.
+ * @vdd_mem: vdd_mem voltage in uV.
+ * @bw_level: Bandwidth performance level number.
+ */
+struct l2_level {
+	const struct core_speed speed;
+	const int vdd_dig;
+	const int vdd_mem;
+	const unsigned int bw_level;
+};
+
+/**
+ * struct acpu_level - CPU clock rate and L2 rate and voltage requirements.
+ * @use_for_scaling: Flag indicating whether or not the level should be used.
+ * @speed: CPU clock configuration.
+ * @l2_level: L2 configuration to use.
+ * @vdd_core: CPU core voltage in uV.
+ */
+struct acpu_level {
+	const int use_for_scaling;
+	const struct core_speed speed;
+	const struct l2_level *l2_level;
+	const int vdd_core;
+};
+
+/**
+ * struct hfpll_data - Descriptive data of HFPLL hardware.
+ * @mode_offset: Mode register offset from base address.
+ * @l_offset: "L" value register offset from base address.
+ * @m_offset: "M" value register offset from base address.
+ * @n_offset: "N" value register offset from base address.
+ * @config_offset: Configuration register offset from base address.
+ * @config_val: Value to initialize the @config_offset register to.
+ * @vdd: voltage requirements for each VDD level.
+ */
+struct hfpll_data {
+	const u32 mode_offset;
+	const u32 l_offset;
+	const u32 m_offset;
+	const u32 n_offset;
+	const u32 config_offset;
+	const u32 config_val;
+	const u32 low_vdd_l_max;
+	const int vdd[NUM_HFPLL_VDD];
+};
+
+/**
+ * struct scalable - Register locations and state associated with a scalable HW.
+ * @hfpll_phys_base: Physical base address of HFPLL register.
+ * @hfpll_base: Virtual base address of HFPLL registers.
+ * @aux_clk_sel_addr: Virtual address of auxiliary MUX.
+ * @aux_clk_sel: Auxiliary mux input to select at boot.
+ * @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
+ * @hfpll_data: Descriptive data of HFPLL hardware.
+ * @cur_speed: Pointer to currently-set speed.
+ * @l2_vote: L2 performance level vote associate with the current CPU speed.
+ * @vreg: Array of voltage regulators needed by the scalable.
+ */
+struct scalable {
+	const u32 hfpll_phys_base;
+	void __iomem *hfpll_base;
+	void __iomem *aux_clk_sel_addr;
+	const u32 aux_clk_sel;
+	const u32 l2cpmr_iaddr;
+	const struct hfpll_data *hfpll_data;
+	const struct core_speed *cur_speed;
+	const struct l2_level *l2_vote;
+	struct vreg vreg[NUM_VREG];
+};
+
+/**
+ * struct acpuclk_krait_params - SoC specific driver parameters.
+ * @scalable: Array of scalables.
+ * @pvs_acpu_freq_tbl: Array of CPU frequency tables.
+ * @l2_freq_tbl: L2 frequency table.
+ * @l2_freq_tbl_size: Number of rows in @l2_freq_tbl.
+ * @qfprom_phys_base: Physical base address of QFPROM.
+ * @bus_scale_data: MSM bus driver parameters.
+ */
+struct acpuclk_krait_params {
+	struct scalable *scalable;
+	const struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
+	const struct l2_level *l2_freq_tbl;
+	const size_t l2_freq_tbl_size;
+	const u32 qfprom_phys_base;
+	struct msm_bus_scale_pdata *bus_scale_data;
+};
+
+/**
+ * acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
+ */
+extern int acpuclk_krait_init(struct device *dev,
+			      const struct acpuclk_krait_params *params);
+
+#endif
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index ef6c359..c5f0ee3 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -110,5 +110,6 @@
 extern struct acpuclk_soc_data acpuclk_9615_soc_data;
 extern struct acpuclk_soc_data acpuclk_8930_soc_data;
 extern struct acpuclk_soc_data acpuclk_8064_soc_data;
+extern struct acpuclk_soc_data acpuclk_8625_soc_data;
 
 #endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 0a56dd2..89d7fc9 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -65,6 +65,9 @@
 static uint32_t bam_dmux_write_cpy_bytes;
 static uint32_t bam_dmux_tx_sps_failure_cnt;
 static uint32_t bam_dmux_tx_stall_cnt;
+static atomic_t bam_dmux_ack_out_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_ack_in_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_a2_pwr_cntl_in_cnt = ATOMIC_INIT(0);
 
 #define DBG(x...) do {		                 \
 		if (msm_bam_dmux_debug_enable)  \
@@ -102,6 +105,14 @@
 	bam_dmux_tx_stall_cnt++; \
 } while (0)
 
+#define DBG_INC_ACK_OUT_CNT() \
+	atomic_inc(&bam_dmux_ack_out_cnt)
+
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	atomic_inc(&bam_dmux_a2_pwr_cntl_in_cnt)
+
+#define DBG_INC_ACK_IN_CNT() \
+	atomic_inc(&bam_dmux_ack_in_cnt)
 #else
 #define DBG(x...) do { } while (0)
 #define DBG_INC_READ_CNT(x...) do { } while (0)
@@ -109,6 +120,10 @@
 #define DBG_INC_WRITE_CPY(x...) do { } while (0)
 #define DBG_INC_TX_SPS_FAILURE_CNT() do { } while (0)
 #define DBG_INC_TX_STALL_CNT() do { } while (0)
+#define DBG_INC_ACK_OUT_CNT() do { } while (0)
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	do { } while (0)
+#define DBG_INC_ACK_IN_CNT() do { } while (0)
 #endif
 
 struct bam_ch_info {
@@ -190,6 +205,7 @@
 
 /* A2 power collaspe */
 #define UL_TIMEOUT_DELAY 1000	/* in ms */
+#define ENABLE_DISCONNECT_ACK	0x1
 static void toggle_apps_ack(void);
 static void reconnect_to_bam(void);
 static void disconnect_to_bam(void);
@@ -208,7 +224,7 @@
 static struct delayed_work ul_timeout_work;
 static int ul_packet_written;
 static atomic_t ul_ondemand_vote = ATOMIC_INIT(0);
-static struct clk *dfab_clk;
+static struct clk *dfab_clk, *xo_clk;
 static DEFINE_RWLOCK(ul_wakeup_lock);
 static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
 static int bam_connection_is_active;
@@ -221,8 +237,8 @@
 static struct completion dfab_unvote_completion;
 static DEFINE_SPINLOCK(wakelock_reference_lock);
 static int wakelock_reference_count;
-static struct delayed_work msm9615_bam_init_work;
 static int a2_pc_disabled_wakelock_skipped;
+static int disconnect_ack;
 /* End A2 power collaspe */
 
 /* subsystem restart */
@@ -294,9 +310,10 @@
 	 * W: 1 = Uplink Wait-for-ack
 	 * A: 1 = Uplink ACK received
 	 * #: >=1 On-demand uplink vote
+	 * D: 1 = Disconnect ACK active
 	 */
 	len += scnprintf(buff, sizeof(buff),
-		"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c%d ",
+		"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c%d%c ",
 		(unsigned)t_now, nanosec_rem,
 		a2_pc_disabled ? 'D' : 'd',
 		in_global_reset ? 'R' : 'r',
@@ -306,7 +323,8 @@
 		bam_is_connected ?  'U' : 'u',
 		wait_for_ack ? 'W' : 'w',
 		ul_wakeup_ack_completion.done ? 'A' : 'a',
-		atomic_read(&ul_ondemand_vote)
+		atomic_read(&ul_ondemand_vote),
+		disconnect_ack ? 'D' : 'd'
 		);
 
 	va_start(arg_list, fmt);
@@ -533,6 +551,10 @@
 		bam_dmux_log("%s: opening cid %d PC enabled\n", __func__,
 				rx_hdr->ch_id);
 		handle_bam_mux_cmd_open(rx_hdr);
+		if (rx_hdr->reserved & ENABLE_DISCONNECT_ACK) {
+			bam_dmux_log("%s: activating disconnect ack\n");
+			disconnect_ack = 1;
+		}
 		dev_kfree_skb_any(rx_skb);
 		break;
 	case BAM_MUX_HDR_CMD_OPEN_NO_A2_PC:
@@ -541,8 +563,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);
@@ -1200,14 +1221,20 @@
 			"skb copy bytes:  %u\n"
 			"sps tx failures: %u\n"
 			"sps tx stalls:   %u\n"
-			"rx queue len:    %d\n",
+			"rx queue len:    %d\n"
+			"a2 ack out cnt:  %d\n"
+			"a2 ack in cnt:   %d\n"
+			"a2 pwr cntl in:  %d\n",
 			bam_dmux_read_cnt,
 			bam_dmux_write_cnt,
 			bam_dmux_write_cpy_cnt,
 			bam_dmux_write_cpy_bytes,
 			bam_dmux_tx_sps_failure_cnt,
 			bam_dmux_tx_stall_cnt,
-			bam_rx_pool_len
+			bam_rx_pool_len,
+			atomic_read(&bam_dmux_ack_out_cnt),
+			atomic_read(&bam_dmux_ack_in_cnt),
+			atomic_read(&bam_dmux_a2_pwr_cntl_in_cnt)
 			);
 
 	return i;
@@ -1237,6 +1264,7 @@
 			"\tW: 1 = Uplink Wait-for-ack\n"
 			"\tA: 1 = Uplink ACK received\n"
 			"\t#: >=1 On-demand uplink vote\n"
+			"\tD: 1 = Disconnect ACK active\n"
 				);
 		buff += i;
 	}
@@ -1512,21 +1540,11 @@
 
 static int ssrestart_check(void)
 {
-	/*
-	 * if the restart level is RESET_SOC, SSR is not on
-	 * so the crashed modem will end up crashing the system
-	 * anyways, so use BUG() to report the error
-	 * else prepare for the restart event which should
-	 * happen soon
-	 */
-	DMUX_LOG_KERR("%s: modem timeout\n", __func__);
-	if (get_restart_level() <= RESET_SOC) {
-		BUG();
-		return 0;
-	} else {
-		in_global_reset = 1;
-		return 1;
-	}
+	DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
+	in_global_reset = 1;
+	if (get_restart_level() <= RESET_SOC)
+		DMUX_LOG_KERR("%s: ssrestart not enabled\n", __func__);
+	return 1;
 }
 
 static void ul_wakeup(void)
@@ -1629,10 +1647,9 @@
 	if (polling_mode)
 		rx_switch_to_interrupt_mode();
 
-	queue_rx();
-
 	toggle_apps_ack();
 	complete_all(&bam_connection_completion);
+	queue_rx();
 }
 
 static void disconnect_to_bam(void)
@@ -1673,6 +1690,9 @@
 	bam_rx_pool_len = 0;
 	mutex_unlock(&bam_rx_pool_mutexlock);
 
+	if (disconnect_ack)
+		toggle_apps_ack();
+
 	verify_tx_queue_is_empty(__func__);
 }
 
@@ -1690,6 +1710,9 @@
 	rc = clk_prepare_enable(dfab_clk);
 	if (rc)
 		DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
+	rc = clk_prepare_enable(xo_clk);
+	if (rc)
+		DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n", rc);
 	dfab_is_on = 1;
 	mutex_unlock(&dfab_status_lock);
 }
@@ -1705,6 +1728,7 @@
 		return;
 	}
 	clk_disable_unprepare(dfab_clk);
+	clk_disable_unprepare(xo_clk);
 	dfab_is_on = 0;
 	mutex_unlock(&dfab_status_lock);
 }
@@ -1773,6 +1797,7 @@
 	ul_powerdown_finish();
 	a2_pc_disabled = 0;
 	a2_pc_disabled_wakelock_skipped = 0;
+	disconnect_ack = 0;
 
 	/* Cleanup Channel States */
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
@@ -1945,10 +1970,10 @@
 	}
 
 	bam_mux_initialized = 1;
-	queue_rx();
 	toggle_apps_ack();
 	bam_connection_is_active = 1;
 	complete_all(&bam_connection_completion);
+	queue_rx();
 	return 0;
 
 rx_event_reg_failed:
@@ -2011,6 +2036,7 @@
 		goto register_bam_failed;
 	}
 	a2_device_handle = h;
+	toggle_apps_ack();
 
 	return 0;
 
@@ -2020,7 +2046,7 @@
 	return ret;
 }
 
-static void msm9615_bam_init(struct work_struct *work)
+static void msm9615_bam_init(void)
 {
 	int ret = 0;
 
@@ -2043,11 +2069,13 @@
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
 				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
 	clear_bit = ~clear_bit;
+	DBG_INC_ACK_OUT_CNT();
 }
 
 static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
 {
 	bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
+	DBG_INC_A2_POWER_CONTROL_IN_CNT();
 	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 
@@ -2063,19 +2091,10 @@
 	} else if (new_state & SMSM_A2_POWER_CONTROL) {
 		bam_dmux_log("%s: init\n", __func__);
 		grab_wakelock();
-		if (cpu_is_msm9615()) {
-			/*
-			 * even though a2 has signaled it is ready via the
-			 * SMSM_A2_POWER_CONTROL bit, it has not yet
-			 * enabled the pipes as needed by sps_connect
-			 * in satallite mode.  Add a short delay to give modem
-			 * time to enable the pipes.
-			 */
-			schedule_delayed_work(&msm9615_bam_init_work,
-						msecs_to_jiffies(100));
-		} else {
+		if (cpu_is_msm9615())
+			msm9615_bam_init();
+		else
 			bam_init();
-		}
 	} else {
 		bam_dmux_log("%s: bad state change\n", __func__);
 		pr_err("%s: unsupported state change\n", __func__);
@@ -2086,6 +2105,7 @@
 static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
 						uint32_t new_state)
 {
+	DBG_INC_ACK_IN_CNT();
 	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 	complete_all(&ul_wakeup_ack_completion);
@@ -2099,6 +2119,11 @@
 	if (bam_mux_initialized)
 		return 0;
 
+	xo_clk = clk_get(&pdev->dev, "xo");
+	if (IS_ERR(xo_clk)) {
+		pr_err("%s: did not get xo clock\n", __func__);
+		return PTR_ERR(xo_clk);
+	}
 	dfab_clk = clk_get(&pdev->dev, "bus_clk");
 	if (IS_ERR(dfab_clk)) {
 		pr_err("%s: did not get dfab clock\n", __func__);
@@ -2137,7 +2162,6 @@
 	init_completion(&bam_connection_completion);
 	init_completion(&dfab_unvote_completion);
 	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
-	INIT_DELAYED_WORK(&msm9615_bam_init_work, msm9615_bam_init);
 	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
 
 	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
new file mode 100644
index 0000000..f362a72
--- /dev/null
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -0,0 +1,86 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/pm8xxx/pm8921-bms.h>
+
+static struct single_row_lut desay_5200_fcc_temp = {
+	.x		= {-20, 0, 25, 40},
+	.y		= {5690, 5722, 5722, 5727},
+	.cols	= 4
+};
+
+static struct single_row_lut desay_5200_fcc_sf = {
+	.x		= {0},
+	.y		= {100},
+	.cols	= 1
+};
+
+static struct pc_temp_ocv_lut desay_5200_pc_temp_ocv = {
+	.rows		= 29,
+	.cols		= 4,
+	.temp		= {-20, 0, 25, 40},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
+				50, 45, 40, 35, 30, 25, 20, 15, 10, 9, 8,
+				7, 6, 5, 4, 3, 2, 1, 0
+	},
+	.ocv		= {
+				{4185, 4184, 4181, 4178},
+				{4103, 4117, 4120, 4119},
+				{4044, 4067, 4074, 4073},
+				{3987, 4019, 4031, 4030},
+				{3941, 3974, 3992, 3992},
+				{3902, 3936, 3958, 3957},
+				{3866, 3901, 3926, 3926},
+				{3835, 3870, 3891, 3896},
+				{3811, 3842, 3855, 3858},
+				{3792, 3818, 3827, 3827},
+				{3776, 3795, 3806, 3806},
+				{3762, 3778, 3789, 3790},
+				{3748, 3765, 3777, 3777},
+				{3735, 3752, 3767, 3765},
+				{3720, 3739, 3756, 3754},
+				{3704, 3726, 3743, 3736},
+				{3685, 3712, 3723, 3716},
+				{3664, 3697, 3695, 3689},
+				{3623, 3672, 3669, 3664},
+				{3611, 3666, 3666, 3661},
+				{3597, 3659, 3662, 3658},
+				{3579, 3648, 3657, 3653},
+				{3559, 3630, 3644, 3639},
+				{3532, 3600, 3612, 3606},
+				{3497, 3558, 3565, 3559},
+				{3450, 3500, 3504, 3498},
+				{3380, 3417, 3421, 3416},
+				{3265, 3287, 3296, 3293},
+				{3000, 3000, 3000, 3000}
+	},
+};
+
+static struct sf_lut desay_5200_pc_sf = {
+	.rows		= 1,
+	.cols		= 1,
+	/* row_entries are cycles here */
+	.row_entries		= {0},
+	.percent	= {100},
+	.sf			= {
+				{100}
+	},
+};
+
+struct pm8921_bms_battery_data desay_5200_data = {
+	.fcc			= 5200,
+	.fcc_temp_lut		= &desay_5200_fcc_temp,
+	.fcc_sf_lut		= &desay_5200_fcc_sf,
+	.pc_temp_ocv_lut	= &desay_5200_pc_temp_ocv,
+	.pc_sf_lut		= &desay_5200_pc_sf,
+	.default_rbatt_mohm	= 156,
+};
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 4287153..2960a8b 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.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
@@ -12,22 +12,23 @@
 
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 
-static struct single_row_lut fcc_temp = {
+static struct single_row_lut palladium_1500_fcc_temp = {
 	.x	= {-30, -20, -10, 0, 10, 25, 40, 60},
 	.y	= {1103, 1179, 1284, 1330, 1420, 1511, 1541, 1571},
 	.cols	= 8,
 };
 
-static struct single_row_lut fcc_sf = {
+static struct single_row_lut palladium_1500_fcc_sf = {
 	.x	= {100, 200, 300, 400, 500},
 	.y	= {97, 93, 93, 90, 87},
 	.cols	= 5,
 };
 
-static struct pc_sf_lut pc_sf = {
+static struct sf_lut palladium_1500_pc_sf = {
 	.rows		= 10,
 	.cols		= 5,
-	.cycles		= {100, 200, 300, 400, 500},
+	/* row_entries are chargecycles */
+	.row_entries	= {100, 200, 300, 400, 500},
 	.percent	= {100, 90, 80, 70, 60, 50, 40, 30, 20, 10},
 	.sf		= {
 			{97, 93, 93, 90, 87},
@@ -43,7 +44,37 @@
 	},
 };
 
-static struct pc_temp_ocv_lut  pc_temp_ocv = {
+static struct sf_lut palladium_1500_rbatt_sf = {
+	.rows		= 19,
+	.cols		= 5,
+	/* row_entries are temperature */
+	.row_entries	= {-20, 0, 20, 40, 65},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50,
+				45, 40, 35, 30, 25, 20, 15, 10
+	},
+	.sf		= {
+					{645, 301, 100, 80, 69},
+					{616, 290, 100, 79, 69},
+					{586, 279, 100, 78, 68},
+					{564, 270, 100, 78, 68},
+					{546, 262, 100, 78, 68},
+					{537, 256, 100, 79, 68},
+					{536, 253, 100, 79, 69},
+					{552, 258, 100, 81, 71},
+					{618, 284, 100, 80, 72},
+					{643, 290, 100, 77, 68},
+					{673, 294, 100, 77, 68},
+					{720, 296, 100, 77, 69},
+					{769, 294, 100, 76, 68},
+					{821, 288, 100, 74, 67},
+					{892, 284, 100, 74, 61},
+					{1003, 290, 100, 71, 58},
+					{1192, 307, 100, 70, 58},
+					{1579, 345, 100, 68, 57},
+					{1261, 324, 100, 68, 57},
+	}
+};
+static struct pc_temp_ocv_lut palladium_1500_pc_temp_ocv = {
 	.rows		= 29,
 	.cols		= 8,
 	.temp		= {-30, -20, -10, 0, 10, 25, 40, 60},
@@ -84,10 +115,12 @@
 	},
 };
 
-struct pm8921_bms_battery_data  palladium_1500_data = {
+struct pm8921_bms_battery_data palladium_1500_data = {
 	.fcc			= 1500,
-	.fcc_temp_lut		= &fcc_temp,
-	.fcc_sf_lut		= &fcc_sf,
-	.pc_temp_ocv_lut	= &pc_temp_ocv,
-	.pc_sf_lut		= &pc_sf,
+	.fcc_temp_lut		= &palladium_1500_fcc_temp,
+	.fcc_sf_lut		= &palladium_1500_fcc_sf,
+	.pc_temp_ocv_lut	= &palladium_1500_pc_temp_ocv,
+	.pc_sf_lut		= &palladium_1500_pc_sf,
+	.rbatt_sf_lut		= &palladium_1500_rbatt_sf,
+	.default_rbatt_mohm	= 254,
 };
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 109ed2c..9080e60 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[] = {
 };
 
@@ -332,17 +349,15 @@
 };
 
 static struct camera_vreg_t apq_8064_back_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
 
 static struct camera_vreg_t apq_8064_front_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
@@ -403,15 +418,31 @@
 	.i2c_mux_mode = MODE_L,
 };
 
+static struct i2c_board_info imx074_actuator_i2c_info = {
+	I2C_BOARD_INFO("imx074_act", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+	.board_info     = &imx074_actuator_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 1,
+};
+
 static struct msm_camera_i2c_conf apq8064_front_cam_i2c_conf = {
 	.use_i2c_mux = 1,
 	.mux_dev = &msm8960_device_i2c_mux_gsbi4,
 	.i2c_mux_mode = MODE_L,
 };
 
-#ifdef CONFIG_IMX074
 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_csi_lane_params imx074_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
 };
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
@@ -420,6 +451,7 @@
 	.num_vreg = ARRAY_SIZE(apq_8064_back_cam_vreg),
 	.gpio_conf = &apq8064_back_cam_gpio_conf,
 	.i2c_conf = &apq8064_back_cam_i2c_conf,
+	.csi_lane_params = &imx074_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
@@ -429,20 +461,95 @@
 	.sensor_platform_info = &sensor_board_info_imx074,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &imx074_actuator_info
 };
-#endif
+static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
 
-#ifdef CONFIG_OV2720
+static struct camera_vreg_t apq_8064_imx091_vreg[] = {
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+};
+
+static struct msm_camera_sensor_flash_data flash_imx091 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
+	.mount_angle	= 0,
+	.cam_vreg = apq_8064_imx091_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_imx091_vreg),
+	.gpio_conf = &apq8064_back_cam_gpio_conf,
+	.i2c_conf = &apq8064_back_cam_i2c_conf,
+	.csi_lane_params = &imx091_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
+	.sensor_name	= "imx091",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx091,
+	.sensor_platform_info = &sensor_board_info_imx091,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+};
+
+static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+	.flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_csi_lane_params mt9m114_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x1,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+	.mount_angle = 90,
+	.cam_vreg = apq_8064_mt9m114_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_mt9m114_vreg),
+	.gpio_conf = &apq8064_front_cam_gpio_conf,
+	.i2c_conf = &apq8064_front_cam_i2c_conf,
+	.csi_lane_params = &mt9m114_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+	.sensor_name = "mt9m114",
+	.pdata = &msm_camera_csi_device_data[1],
+	.flash_data = &flash_mt9m114,
+	.sensor_platform_info = &sensor_board_info_mt9m114,
+	.csi_if = 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
+};
+
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
 
+static struct msm_camera_csi_lane_params ov2720_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x3,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
 	.mount_angle	= 0,
 	.cam_vreg = apq_8064_front_cam_vreg,
 	.num_vreg = ARRAY_SIZE(apq_8064_front_cam_vreg),
 	.gpio_conf = &apq8064_front_cam_gpio_conf,
 	.i2c_conf = &apq8064_front_cam_i2c_conf,
+	.csi_lane_params = &ov2720_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
@@ -452,15 +559,19 @@
 	.sensor_platform_info = &sensor_board_info_ov2720,
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
-#endif
-
 
 void __init apq8064_init_cam(void)
 {
 	msm_gpiomux_install(apq8064_cam_common_configs,
 			ARRAY_SIZE(apq8064_cam_common_configs));
 
+	if (machine_is_apq8064_cdp())
+		sensor_board_info_imx074.mount_angle = 0;
+	else if (machine_is_apq8064_liquid())
+		sensor_board_info_imx074.mount_angle = 180;
+
 	platform_device_register(&msm8960_device_i2c_mux_gsbi4);
 	platform_device_register(&msm8960_device_csiphy0);
 	platform_device_register(&msm8960_device_csiphy1);
@@ -473,18 +584,25 @@
 
 #ifdef CONFIG_I2C
 static struct i2c_board_info apq8064_camera_i2c_boardinfo[] = {
-#ifdef CONFIG_IMX074
 	{
 	I2C_BOARD_INFO("imx074", 0x1A),
 	.platform_data = &msm_camera_sensor_imx074_data,
 	},
-#endif
-#ifdef CONFIG_OV2720
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
 	{
 	I2C_BOARD_INFO("ov2720", 0x6C),
 	.platform_data = &msm_camera_sensor_ov2720_data,
 	},
-#endif
+	{
+	I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+	{
+	I2C_BOARD_INFO("imx091", 0x34),
+	.platform_data = &msm_camera_sensor_imx091_data,
+	},
 };
 
 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..19d7a9e 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -23,29 +23,39 @@
 #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"
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 /* prim = 1366 x 768 x 3(bpp) x 3(pages) */
-#define MSM_FB_PRIM_BUF_SIZE roundup(1376 * 768 * 4 * 3, 0x10000)
+#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1080 * 4 * 3, 0x10000)
 #else
 /* prim = 1366 x 768 x 3(bpp) x 2(pages) */
-#define MSM_FB_PRIM_BUF_SIZE roundup(1376 * 768 * 4 * 2, 0x10000)
+#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1080 * 4 * 2, 0x10000)
 #endif
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-/* hdmi = 1920 x 1088 x 2(bpp) x 1(page) */
-#define MSM_FB_EXT_BUF_SIZE 0x3FC000
+#define MSM_FB_EXT_BUF_SIZE \
+		(roundup((1920 * 1088 * 2), 4096) * 1) /* 2 bpp x 1 page */
 #elif defined(CONFIG_FB_MSM_TVOUT)
-/* tvout = 720 x 576 x 2(bpp) x 2(pages) */
-#define MSM_FB_EXT_BUF_SIZE 0x195000
-#else /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
-#define MSM_FB_EXT_BUF_SIZE 0
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+#define MSM_FB_EXT_BUF_SIZE \
+		(roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
+#else
+#define MSM_FB_EXT_BUF_SIZE	0
+#endif
 
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+#define MSM_FB_WFD_BUF_SIZE \
+		(roundup((1280 * 736 * 2), 4096) * 1) /* 2 bpp x 1 page */
+#else
+#define MSM_FB_WFD_BUF_SIZE     0
+#endif
+
+#define MSM_FB_SIZE \
+	roundup(MSM_FB_PRIM_BUF_SIZE + \
+		MSM_FB_EXT_BUF_SIZE + MSM_FB_WFD_BUF_SIZE, 4096)
 
 #ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
 #define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
@@ -66,28 +76,42 @@
 	}
 };
 
-#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"
 #define HDMI_PANEL_NAME "hdmi_msm"
 #define TVOUT_PANEL_NAME "tvout_msm"
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static unsigned char hdmi_is_primary = 1;
+#else
+static unsigned char hdmi_is_primary;
+#endif
+
+unsigned char apq8064_hdmi_as_primary_selected(void)
+{
+	return hdmi_is_primary;
+}
+
+static void set_mdp_clocks_for_wuxga(void);
+
 static int msm_fb_detect_panel(const char *name)
 {
+	u32 version;
 	if (machine_is_apq8064_liquid()) {
-		if (!strncmp(name, LVDS_CHIMEI_PANEL_NAME,
-			strnlen(LVDS_CHIMEI_PANEL_NAME,
-				PANEL_NAME_MAX_LEN)))
-			return 0;
-
-#if !defined(CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT) && \
-	!defined(CONFIG_FB_MSM_MIPI_PANEL_DETECT)
-		if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
-			strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
-				PANEL_NAME_MAX_LEN)))
-			return 0;
-#endif
+		version = socinfo_get_platform_version();
+		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+			(SOCINFO_VERSION_MINOR(version) == 1)) {
+			if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+				return 0;
+		} else {
+			if (!strncmp(name, LVDS_CHIMEI_PANEL_NAME,
+				strnlen(LVDS_CHIMEI_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+				return 0;
+		}
 	} else if (machine_is_apq8064_mtp()) {
 		if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
 			strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
@@ -101,9 +125,13 @@
 	}
 
 	if (!strncmp(name, HDMI_PANEL_NAME,
-		strnlen(HDMI_PANEL_NAME,
-			PANEL_NAME_MAX_LEN)))
+			strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+		if (apq8064_hdmi_as_primary_selected())
+			set_mdp_clocks_for_wuxga();
 		return 0;
+	}
+
 
 	return -ENODEV;
 }
@@ -135,7 +163,6 @@
 
 #define MDP_VSYNC_GPIO 0
 
-#ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors mdp_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -217,8 +244,6 @@
 	.name = "mdp",
 };
 
-#endif
-
 static int mdp_core_clk_rate_table[] = {
 	200000000,
 	200000000,
@@ -231,12 +256,10 @@
 	.mdp_core_clk_rate = 200000000,
 	.mdp_core_clk_table = mdp_core_clk_rate_table,
 	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
-#ifdef CONFIG_MSM_BUS_SCALING
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
-#endif
 	.mdp_rev = MDP_REV_44,
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	.mem_hid = ION_CP_MM_HEAP_ID,
+	.mem_hid = BIT(ION_CP_MM_HEAP_ID),
 #else
 	.mem_hid = MEMTYPE_EBI1,
 #endif
@@ -254,6 +277,65 @@
 #endif
 }
 
+static struct resource hdmi_msm_resources[] = {
+	{
+		.name  = "hdmi_msm_qfprom_addr",
+		.start = 0x00700000,
+		.end   = 0x007060FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_hdmi_addr",
+		.start = 0x04A00000,
+		.end   = 0x04A00FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_irq",
+		.start = HDMI_IRQ,
+		.end   = HDMI_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+
+static struct msm_hdmi_platform_data hdmi_msm_data = {
+	.irq = HDMI_IRQ,
+	.enable_5v = hdmi_enable_5v,
+	.core_power = hdmi_core_power,
+	.cec_power = hdmi_cec_power,
+};
+
+static struct platform_device hdmi_msm_device = {
+	.name = "hdmi_msm",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(hdmi_msm_resources),
+	.resource = hdmi_msm_resources,
+	.dev.platform_data = &hdmi_msm_data,
+};
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct platform_device wfd_panel_device = {
+	.name = "wfd_panel",
+	.id = 0,
+	.dev.platform_data = NULL,
+};
+
+static struct platform_device wfd_device = {
+	.name          = "msm_wfd",
+	.id            = -1,
+};
+#endif
+
+/* HDMI related GPIOs */
+#define HDMI_CEC_VAR_GPIO	69
+#define HDMI_DDC_CLK_GPIO	70
+#define HDMI_DDC_DATA_GPIO	71
+#define HDMI_HPD_GPIO		72
+
 static bool dsi_power_on;
 static int mipi_dsi_panel_power(int on)
 {
@@ -528,8 +610,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
@@ -574,11 +669,272 @@
 	}
 };
 
+static struct msm_bus_vectors dtv_bus_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 566092800 * 2,
+		.ib = 707616000 * 2,
+	},
+};
+
+static struct msm_bus_paths dtv_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(dtv_bus_init_vectors),
+		dtv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dtv_bus_def_vectors),
+		dtv_bus_def_vectors,
+	},
+};
+static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
+	dtv_bus_scale_usecases,
+	ARRAY_SIZE(dtv_bus_scale_usecases),
+	.name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_pdata = {
+	.bus_scale_table = &dtv_bus_scale_pdata,
+};
+
+static int hdmi_enable_5v(int on)
+{
+	/* TBD: PM8921 regulator instead of 8901 */
+	static struct regulator *reg_8921_hdmi_mvs;	/* HDMI_5V */
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_8921_hdmi_mvs) {
+		reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
+			"hdmi_mvs");
+		if (IS_ERR(reg_8921_hdmi_mvs)) {
+			pr_err("could not get reg_8921_hdmi_mvs, rc = %ld\n",
+				PTR_ERR(reg_8921_hdmi_mvs));
+			reg_8921_hdmi_mvs = NULL;
+			return -ENODEV;
+		}
+	}
+
+	if (on) {
+		rc = regulator_enable(reg_8921_hdmi_mvs);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"8921_hdmi_mvs", rc);
+			return rc;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		rc = regulator_disable(reg_8921_hdmi_mvs);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"8921_hdmi_mvs", rc);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+}
+
+static int hdmi_core_power(int on, int show)
+{
+	static struct regulator *reg_8921_lvs7, *reg_8921_s4, *reg_ext_3p3v;
+	static int prev_on;
+	int rc;
+	int pmic_gpio14 = PM8921_GPIO_PM_TO_SYS(14);
+
+	if (on == prev_on)
+		return 0;
+
+	/* TBD: PM8921 regulator instead of 8901 */
+	if (!reg_ext_3p3v) {
+		reg_ext_3p3v = regulator_get(&hdmi_msm_device.dev,
+					     "hdmi_mux_vdd");
+		if (IS_ERR_OR_NULL(reg_ext_3p3v)) {
+			pr_err("could not get reg_ext_3p3v, rc = %ld\n",
+			       PTR_ERR(reg_ext_3p3v));
+			reg_ext_3p3v = NULL;
+			return -ENODEV;
+		}
+	}
+
+	if (!reg_8921_lvs7) {
+		reg_8921_lvs7 = regulator_get(&hdmi_msm_device.dev,
+					      "hdmi_vdda");
+		if (IS_ERR(reg_8921_lvs7)) {
+			pr_err("could not get reg_8921_lvs7, rc = %ld\n",
+				PTR_ERR(reg_8921_lvs7));
+			reg_8921_lvs7 = NULL;
+			return -ENODEV;
+		}
+	}
+	if (!reg_8921_s4) {
+		reg_8921_s4 = regulator_get(&hdmi_msm_device.dev,
+					    "hdmi_lvl_tsl");
+		if (IS_ERR(reg_8921_s4)) {
+			pr_err("could not get reg_8921_s4, rc = %ld\n",
+				PTR_ERR(reg_8921_s4));
+			reg_8921_s4 = NULL;
+			return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000);
+		if (rc) {
+			pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc);
+			return -EINVAL;
+		}
+	}
+
+	if (on) {
+		/*
+		 * Configure 3P3V_BOOST_EN as GPIO, 8mA drive strength,
+		 * pull none, out-high
+		 */
+		rc = regulator_set_optimum_mode(reg_ext_3p3v, 290000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode ext_3p3v failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+
+		rc = regulator_enable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_enable(reg_8921_lvs7);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"hdmi_vdda", rc);
+			return rc;
+		}
+		rc = regulator_enable(reg_8921_s4);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"hdmi_lvl_tsl", rc);
+			return rc;
+		}
+		rc = gpio_request(HDMI_DDC_CLK_GPIO, "HDMI_DDC_CLK");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_CLK", HDMI_DDC_CLK_GPIO, rc);
+			goto error1;
+		}
+		rc = gpio_request(HDMI_DDC_DATA_GPIO, "HDMI_DDC_DATA");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_DATA", HDMI_DDC_DATA_GPIO, rc);
+			goto error2;
+		}
+		rc = gpio_request(HDMI_HPD_GPIO, "HDMI_HPD");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_HPD", HDMI_HPD_GPIO, rc);
+			goto error3;
+		}
+		if (machine_is_apq8064_liquid()) {
+			rc = gpio_request(pmic_gpio14, "PMIC_HDMI_MUX_SEL");
+			if (rc) {
+				pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+					"PMIC_HDMI_MUX_SEL", 14, rc);
+				goto error4;
+			}
+			gpio_set_value_cansleep(pmic_gpio14, 0);
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(HDMI_DDC_CLK_GPIO);
+		gpio_free(HDMI_DDC_DATA_GPIO);
+		gpio_free(HDMI_HPD_GPIO);
+
+		if (machine_is_apq8064_liquid()) {
+			gpio_set_value_cansleep(pmic_gpio14, 1);
+			gpio_free(pmic_gpio14);
+		}
+
+		rc = regulator_disable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_8921_lvs7);
+		if (rc) {
+			pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_8921_s4);
+		if (rc) {
+			pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+
+error4:
+	gpio_free(HDMI_HPD_GPIO);
+error3:
+	gpio_free(HDMI_DDC_DATA_GPIO);
+error2:
+	gpio_free(HDMI_DDC_CLK_GPIO);
+error1:
+	regulator_disable(reg_8921_lvs7);
+	regulator_disable(reg_8921_s4);
+	return rc;
+}
+
+static int hdmi_cec_power(int on)
+{
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (on) {
+		rc = gpio_request(HDMI_CEC_VAR_GPIO, "HDMI_CEC_VAR");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_CEC_VAR", HDMI_CEC_VAR_GPIO, rc);
+			goto error;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(HDMI_CEC_VAR_GPIO);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+error:
+	return rc;
+}
+
 void __init apq8064_init_fb(void)
 {
 	platform_device_register(&msm_fb_device);
 	platform_device_register(&lvds_chimei_panel_device);
 
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+	platform_device_register(&wfd_panel_device);
+	platform_device_register(&wfd_device);
+#endif
+
 	if (machine_is_apq8064_liquid())
 		platform_device_register(&mipi_dsi2lvds_bridge_device);
 	if (machine_is_apq8064_mtp())
@@ -587,4 +943,59 @@
 	msm_fb_register_device("mdp", &mdp_pdata);
 	msm_fb_register_device("lvds", &lvds_pdata);
 	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+	platform_device_register(&hdmi_msm_device);
+	msm_fb_register_device("dtv", &dtv_pdata);
+}
+
+/**
+ * Set MDP clocks to high frequency to avoid DSI underflow
+ * when using high resolution 1200x1920 WUXGA panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+	int i;
+
+	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;
+
+	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+		mdp_core_clk_rate_table[i] = 200000000;
+
+	if (apq8064_hdmi_as_primary_selected()) {
+		dtv_bus_def_vectors[0].ab = 2000000000;
+		dtv_bus_def_vectors[0].ib = 2000000000;
+	}
+}
+
+void __init apq8064_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;
+			set_mdp_clocks_for_wuxga();
+		}
+	}
+	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-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 9b6c253..2f94069 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -53,6 +53,13 @@
 	.pull = GPIOMUX_PULL_UP,
 };
 
+/* Chip selects for EPM SPI clients */
+static struct gpiomux_setting gpio_epm_spi_cs_config = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
 struct msm_gpiomux_config apq8064_ethernet_configs[] = {
 	{
 		.gpio = 43,
@@ -82,22 +89,6 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting audio_auxpcm[] = {
-	/* Suspended state */
-	{
-		.func = GPIOMUX_FUNC_GPIO,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_NONE,
-	},
-	/* Active state */
-	{
-		.func = GPIOMUX_FUNC_1,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_NONE,
-	},
-};
-
-
 static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv  = GPIOMUX_DRV_2MA,
@@ -154,6 +145,24 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting hdmi_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 static struct gpiomux_setting hsic_act_cfg = {
 	.func = GPIOMUX_FUNC_1,
@@ -270,6 +279,37 @@
 	.pull = GPIOMUX_PULL_UP,
 };
 
+static struct msm_gpiomux_config apq8064_hdmi_configs[] __initdata = {
+	{
+		.gpio = 69,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 70,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 71,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 72,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+};
+
 static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
 	{
 		.gpio      = 8,			/* GSBI3 I2C QUP SDA */
@@ -338,7 +378,7 @@
 	{
 		.gpio      = 32,		/* EPM CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+			[GPIOMUX_SUSPENDED] = &gpio_epm_spi_cs_config,
 		},
 	},
 	{
@@ -399,37 +439,6 @@
 	},
 };
 
-static struct msm_gpiomux_config apq8064_audio_auxpcm_configs[] __initdata = {
-	{
-		.gpio = 43,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 44,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 45,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 46,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-};
-
 /* External 3.3 V regulator enable */
 static struct msm_gpiomux_config apq8064_ext_regulator_configs[] __initdata = {
 	{
@@ -499,7 +508,7 @@
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &ap2mdm_pon_reset_n_cfg,
 		}
-	}
+	},
 };
 
 static struct msm_gpiomux_config apq8064_mxt_configs[] __initdata = {
@@ -584,8 +593,9 @@
 	msm_gpiomux_install(apq8064_audio_codec_configs,
 			ARRAY_SIZE(apq8064_audio_codec_configs));
 
-	msm_gpiomux_install(apq8064_audio_auxpcm_configs,
-			ARRAY_SIZE(apq8064_audio_auxpcm_configs));
+	pr_debug("%s(): audio-auxpcm: Include GPIO configs"
+		" as audio is not the primary user"
+		" for these GPIO Pins\n", __func__);
 
 	msm_gpiomux_install(apq8064_ext_regulator_configs,
 			ARRAY_SIZE(apq8064_ext_regulator_configs));
@@ -599,11 +609,15 @@
 				ARRAY_SIZE(cyts_gpio_configs));
 
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
-	msm_gpiomux_install(apq8064_hsic_configs,
-			ARRAY_SIZE(apq8064_hsic_configs));
+	if (machine_is_apq8064_mtp())
+		msm_gpiomux_install(apq8064_hsic_configs,
+				ARRAY_SIZE(apq8064_hsic_configs));
 #endif
 
 	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
 		msm_gpiomux_install(apq8064_mxt_configs,
 			ARRAY_SIZE(apq8064_mxt_configs));
+
+	msm_gpiomux_install(apq8064_hdmi_configs,
+			ARRAY_SIZE(apq8064_hdmi_configs));
 }
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 0357c40..7b84a68 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -16,10 +16,36 @@
 #include <linux/msm_kgsl.h>
 #include <mach/msm_bus_board.h>
 #include <mach/board.h>
+#include <mach/msm_dcvs.h>
 
 #include "devices.h"
 #include "board-8064.h"
 
+#ifdef CONFIG_MSM_DCVS
+static struct msm_dcvs_freq_entry grp3d_freq[] = {
+	{0, 0, 333932},
+	{0, 0, 497532},
+	{0, 0, 707610},
+	{0, 0, 844545},
+};
+
+static struct msm_dcvs_core_info grp3d_core_info = {
+	.freq_tbl = &grp3d_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(grp3d_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 39000,
+		.disable_pc_threshold = 86000,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.em_max_util_pct = 97,
+		.ss_iobusy_conv = 100,
+	},
+};
+#endif /* CONFIG_MSM_DCVS */
+
 #ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors grp3d_init_vectors[] = {
 	{
@@ -122,27 +148,51 @@
 	},
 };
 
+static const char *kgsl_3d0_iommu0_ctx_names[] = {
+	"gfx3d_user",
+	/* priv_ctx goes here */
+};
+
+static const char *kgsl_3d0_iommu1_ctx_names[] = {
+	"gfx3d1_user",
+	/* priv_ctx goes here */
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_3d0_iommu0_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctx_names),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+	{
+		.iommu_ctx_names = kgsl_3d0_iommu1_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu1_ctx_names),
+		.physstart = 0x07D00000,
+		.physend = 0x07D00000 + SZ_1M - 1,
+	},
+};
+
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
-			.gpu_freq = 192000000,
+			.gpu_freq = 400000000,
+			.bus_freq = 3,
+			.io_fraction = 0,
+		},
+		{
+			.gpu_freq = 325000000,
 			.bus_freq = 2,
+			.io_fraction = 33,
+		},
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 1,
 			.io_fraction = 100,
 		},
 		{
-			.gpu_freq = 192000000,
-			.bus_freq = 2,
-			.io_fraction = 100,
-		},
-		{
-			.gpu_freq = 1920000000,
-			.bus_freq = 2,
-			.io_fraction = 100,
-		},
-		{
-			.gpu_freq = 192000000,
-			.bus_freq = 2,
-			.io_fraction = 100,
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
 		},
 	},
 	.init_level = 0,
@@ -154,8 +204,11 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp3d_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx3d_user",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+#ifdef CONFIG_MSM_DCVS
+	.core_info = &grp3d_core_info,
+#endif
 };
 
 struct platform_device device_kgsl_3d0 = {
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 4c386e9..f915657 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -113,21 +113,38 @@
 
 /* Initial PM8921 GPIO configurations */
 static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
+	PM8921_GPIO_OUTPUT(14, 1, HIGH),	/* HDMI Mux Selector */
 	PM8921_GPIO_OUTPUT(23, 0, HIGH),	/* touchscreen power FET */
 	PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
 	PM8921_GPIO_OUTPUT_FUNC(26, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
+	PM8921_GPIO_OUTPUT_VIN(30, 1, PM_GPIO_VIN_VPH), /* SMB349 susp line */
 	PM8921_GPIO_OUTPUT_BUFCONF(36, 1, LOW, OPEN_DRAIN),
 	PM8921_GPIO_OUTPUT_FUNC(44, 0, PM_GPIO_FUNC_2),
 	PM8921_GPIO_OUTPUT(33, 0, HIGH),
 	PM8921_GPIO_OUTPUT(20, 0, HIGH),
+	PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
+	/* TABLA CODEC RESET */
+	PM8921_GPIO_OUTPUT(34, 1, MED),
+};
+
+static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
+	PM8921_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(4, PM_GPIO_PULL_UP_30),
+};
+
+static struct pm8xxx_gpio_init pm8921_cdp_kp_gpios[] __initdata = {
+	PM8921_GPIO_INPUT(27, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(42, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(17, PM_GPIO_PULL_UP_1P5),	/* SD_WP */
 };
 
 /* Initial PM8XXX MPP configurations */
 static struct pm8xxx_mpp_init pm8xxx_mpps[] __initdata = {
 	PM8921_MPP_INIT(3, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_LOW),
-	/* 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)
@@ -143,6 +160,28 @@
 		}
 	}
 
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+		for (i = 0; i < ARRAY_SIZE(pm8921_cdp_kp_gpios); i++) {
+			rc = pm8xxx_gpio_config(pm8921_cdp_kp_gpios[i].gpio,
+						&pm8921_cdp_kp_gpios[i].config);
+			if (rc) {
+				pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
+					__func__, rc);
+				break;
+			}
+		}
+
+	if (machine_is_apq8064_mtp())
+		for (i = 0; i < ARRAY_SIZE(pm8921_mtp_kp_gpios); i++) {
+			rc = pm8xxx_gpio_config(pm8921_mtp_kp_gpios[i].gpio,
+						&pm8921_mtp_kp_gpios[i].config);
+			if (rc) {
+				pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
+					__func__, rc);
+				break;
+			}
+		}
+
 	for (i = 0; i < ARRAY_SIZE(pm8xxx_mpps); i++) {
 		rc = pm8xxx_mpp_config(pm8xxx_mpps[i].mpp,
 					&pm8xxx_mpps[i].config);
@@ -275,8 +314,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,
 };
 
@@ -321,6 +360,7 @@
 
 static struct pm8921_bms_platform_data
 apq8064_pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -393,5 +433,9 @@
 	if (machine_is_apq8064_rumi3()) {
 		apq8064_pm8921_irq_pdata.devirq = 0;
 		apq8064_pm8821_irq_pdata.devirq = 0;
+	} else if (machine_is_apq8064_mtp()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	} else if (machine_is_apq8064_liquid()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index caee8ba..24df393 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -27,8 +27,9 @@
 };
 VREG_CONSUMERS(L2) = {
 	REGULATOR_SUPPLY("8921_l2",		NULL),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 	REGULATOR_SUPPLY("lvds_pll_vdda",	"lvds.0"),
 	REGULATOR_SUPPLY("dsi1_pll_vdda",	"mipi_dsi.1"),
 };
@@ -41,8 +42,6 @@
 VREG_CONSUMERS(L4) = {
 	REGULATOR_SUPPLY("8921_l4",		NULL),
 	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
-	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.0"),
-	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.1"),
 	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L5) = {
@@ -60,7 +59,9 @@
 VREG_CONSUMERS(L8) = {
 	REGULATOR_SUPPLY("8921_l8",		NULL),
 	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0034"),
 };
 VREG_CONSUMERS(L9) = {
 	REGULATOR_SUPPLY("8921_l9",		NULL),
@@ -76,7 +77,9 @@
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0034"),
 	REGULATOR_SUPPLY("8921_l12",		NULL),
 };
 VREG_CONSUMERS(L14) = {
@@ -88,7 +91,9 @@
 VREG_CONSUMERS(L16) = {
 	REGULATOR_SUPPLY("8921_l16",		NULL),
 	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0034"),
 };
 VREG_CONSUMERS(L17) = {
 	REGULATOR_SUPPLY("8921_l17",		NULL),
@@ -103,7 +108,8 @@
 	REGULATOR_SUPPLY("8921_l23",		NULL),
 	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
 	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
-
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.0"),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.1"),
 };
 VREG_CONSUMERS(L24) = {
 	REGULATOR_SUPPLY("8921_l24",		NULL),
@@ -158,6 +164,7 @@
 	REGULATOR_SUPPLY("vcc_i2c",		"3-005b"),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
 	REGULATOR_SUPPLY("vddp",		"0-0048"),
+	REGULATOR_SUPPLY("hdmi_lvl_tsl",	"hdmi_msm.0"),
 };
 VREG_CONSUMERS(S5) = {
 	REGULATOR_SUPPLY("8921_s5",		NULL),
@@ -187,7 +194,9 @@
 VREG_CONSUMERS(LVS5) = {
 	REGULATOR_SUPPLY("8921_lvs5",		NULL),
 	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0034"),
 };
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
@@ -197,6 +206,7 @@
 	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
 	REGULATOR_SUPPLY("lvds_vdda",		"lvds.0"),
 	REGULATOR_SUPPLY("dsi1_vddio",		"mipi_dsi.1"),
+	REGULATOR_SUPPLY("hdmi_vdda",		"hdmi_msm.0"),
 };
 VREG_CONSUMERS(USB_OTG) = {
 	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
@@ -204,6 +214,7 @@
 };
 VREG_CONSUMERS(HDMI_MVS) = {
 	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
+	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
 };
 VREG_CONSUMERS(NCP) = {
 	REGULATOR_SUPPLY("8921_ncp",		NULL),
@@ -218,9 +229,12 @@
 };
 VREG_CONSUMERS(EXT_5V) = {
 	REGULATOR_SUPPLY("ext_5v",		NULL),
+	REGULATOR_SUPPLY("ext_ddr3",		NULL),
+	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.0"),
 };
 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),
@@ -228,6 +242,7 @@
 	REGULATOR_SUPPLY("mhl_ext_3p3v",	"msm_otg"),
 	REGULATOR_SUPPLY("lvds_vccs_3p3v",      "lvds.0"),
 	REGULATOR_SUPPLY("dsi1_vccs_3p3v",      "mipi_dsi.1"),
+	REGULATOR_SUPPLY("hdmi_mux_vdd",        "hdmi_msm.0"),
 };
 VREG_CONSUMERS(EXT_TS_SW) = {
 	REGULATOR_SUPPLY("ext_ts_sw",		NULL),
@@ -359,8 +374,8 @@
 
 #define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
 		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
-		 _force_mode, _power_mode, _state, _sleep_selectable, \
-		 _always_on, _supply_regulator, _system_uA) \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -386,6 +401,7 @@
 		.freq			= RPM_VREG_FREQ_##_freq, \
 		.pin_fn			= _pin_fn, \
 		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
 		.power_mode		= _power_mode, \
 		.state			= _state, \
 		.sleep_selectable	= _sleep_selectable, \
@@ -399,24 +415,28 @@
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
 		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, _system_uA)
 
 #define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
-		 _supply_regulator, _system_uA, _freq) \
+		 _supply_regulator, _system_uA, _freq, _force_mode, \
+		 _sleep_set_force_mode) \
 	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
-		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
-		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
-		 _supply_regulator, _system_uA)
+		 RPM_VREG_FORCE_MODE_8960_##_force_mode, \
+		 RPM_VREG_FORCE_MODE_8960_##_sleep_set_force_mode, \
+		 RPM_VREG_POWER_MODE_8960_PWM, RPM_VREG_STATE_OFF, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA)
 
 #define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
 	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
 		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
@@ -426,6 +446,7 @@
 	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
 		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
 		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
@@ -464,15 +485,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
@@ -491,12 +512,12 @@
 
 static struct rpm_regulator_init_data
 apq8064_rpm_regulator_init_data[] __devinitdata = {
-	/*	ID a_on pd ss min_uV   max_uV   supply    sys_uA  freq */
-	RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL,     100000, 3p20),
-	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,          0, 1p60),
-	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL,     100000, 4p80),
-	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL,     100000, 1p60),
-	RPM_SMPS(S7, 0, 1, 0, 1300000, 1300000, NULL,     100000, 3p20),
+	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
+	RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
+	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, NONE, NONE),
+	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, NONE, NONE),
+	RPM_SMPS(S7, 0, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
 
 	/*	ID a_on pd ss min_uV   max_uV   supply    sys_uA init_ip */
 	RPM_LDO(L1,  1, 1, 0, 1100000, 1100000, "8921_s4",     0, 10000),
@@ -507,7 +528,7 @@
 	RPM_LDO(L6,  0, 1, 0, 2950000, 2950000, NULL,          0,     0),
 	RPM_LDO(L7,  0, 1, 0, 1850000, 2950000, NULL,          0,     0),
 	RPM_LDO(L8,  0, 1, 0, 2800000, 2800000, NULL,          0,     0),
-	RPM_LDO(L9,  0, 1, 0, 2850000, 2850000, NULL,          0,     0),
+	RPM_LDO(L9,  0, 1, 0, 3000000, 3000000, NULL,          0,     0),
 	RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL,          0,     0),
 	RPM_LDO(L11, 0, 1, 0, 3000000, 3000000, NULL,          0,     0),
 	RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4",     0,     0),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 9069039..cd8fba5 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.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
@@ -51,7 +51,7 @@
 		.name = "sdc_vdd",
 		.high_vol_level = 2950000,
 		.low_vol_level = 2950000,
-		.hpm_uA = 600000, /* 600mA */
+		.hpm_uA = 800000, /* 800mA */
 	}
 };
 
@@ -210,8 +210,11 @@
 #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],
+	.uhs_caps	= MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50,
 };
 static struct mmc_platform_data *apq8064_sdc1_pdata = &sdc1_data;
 #else
@@ -228,8 +231,11 @@
 	.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],
+	.wpswitch_gpio	= PM8921_GPIO_PM_TO_SYS(17),
+	.wpswitch_polarity = 1,
 	.status_gpio	= 26,
 	.status_irq	= MSM_GPIO_TO_INT(26),
 	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
@@ -260,6 +266,18 @@
 			apq8064_sdc3_pdata->disable_cmd23 = true;
 		}
 	}
-	apq8064_add_sdcc(1, apq8064_sdc1_pdata);
-	apq8064_add_sdcc(3, apq8064_sdc3_pdata);
+	if (apq8064_sdc1_pdata) {
+		apq8064_sdc1_pdata->swfi_latency =
+				apq8064_rpm_get_swfi_latency();
+		apq8064_add_sdcc(1, apq8064_sdc1_pdata);
+	}
+	if (apq8064_sdc3_pdata) {
+		apq8064_sdc3_pdata->swfi_latency =
+				apq8064_rpm_get_swfi_latency();
+		if (!machine_is_apq8064_cdp()) {
+			apq8064_sdc3_pdata->wpswitch_gpio = 0;
+			apq8064_sdc3_pdata->wpswitch_polarity = 0;
+		}
+		apq8064_add_sdcc(3, apq8064_sdc3_pdata);
+	}
 }
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 12cee78..d06b5bd 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -15,9 +15,11 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
+#include <linux/i2c/smb349.h>
+#include <linux/i2c/sx150x.h>
 #include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
 #include <linux/mfd/pm8xxx/misc.h>
 #include <linux/msm_ssbi.h>
 #include <linux/spi/spi.h>
@@ -28,6 +30,8 @@
 #include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/cyttsp.h>
 #include <linux/i2c/isa1200.h>
+#include <linux/gpio_keys.h>
+#include <linux/epm_adc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -53,10 +57,13 @@
 #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 <mach/msm_rtb.h>
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
@@ -69,15 +76,15 @@
 #include "devices-msm8x60.h"
 
 #define MSM_PMEM_ADSP_SIZE         0x7800000
-#define MSM_PMEM_AUDIO_SIZE        0x2B4000
+#define MSM_PMEM_AUDIO_SIZE        0x4CF000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 #define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 #else
-#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 #endif
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
@@ -90,6 +97,14 @@
 #define MSM_ION_HEAP_NUM	1
 #endif
 
+#define GPIO_EXPANDER_IRQ_BASE	(PM8821_IRQ_BASE + PM8821_NR_IRQS)
+#define GPIO_EXPANDER_GPIO_BASE	(PM8821_MPP_BASE + PM8821_NR_MPPS)
+#define GPIO_EPM_EXPANDER_BASE	GPIO_EXPANDER_GPIO_BASE
+
+enum {
+	SX150X_EPM,
+};
+
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
 static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
 static int __init pmem_kernel_ebi1_size_setup(char *p)
@@ -154,7 +169,6 @@
 	.id = 2,
 	.dev = { .platform_data = &android_pmem_adsp_pdata },
 };
-#endif
 
 static struct android_pmem_platform_data android_pmem_audio_pdata = {
 	.name = "pmem_audio",
@@ -168,7 +182,8 @@
 	.id = 4,
 	.dev = { .platform_data = &android_pmem_audio_pdata },
 };
-#endif
+#endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
+#endif /* CONFIG_ANDROID_PMEM */
 
 static struct memtype_reserve apq8064_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
@@ -181,21 +196,58 @@
 	},
 };
 
+#if defined(CONFIG_MSM_RTB)
+static struct msm_rtb_platform_data msm_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+static struct platform_device msm_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm_rtb_pdata,
+	},
+};
+#endif
+
+static void __init reserve_rtb_memory(void)
+{
+#if defined(CONFIG_MSM_RTB)
+	apq8064_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size;
+#endif
+}
+
+
 static void __init size_pmem_devices(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 	android_pmem_pdata.size = pmem_size;
-#endif
 	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
 }
 
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 static void __init reserve_memory_for(struct android_pmem_platform_data *p)
 {
 	apq8064_reserve_table[p->memory_type].size += p->size;
 }
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
 
 static void __init reserve_pmem_memory(void)
 {
@@ -203,10 +255,10 @@
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	reserve_memory_for(&android_pmem_adsp_pdata);
 	reserve_memory_for(&android_pmem_pdata);
-#endif
 	reserve_memory_for(&android_pmem_audio_pdata);
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
 	apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
+#endif /*CONFIG_ANDROID_PMEM*/
 }
 
 static int apq8064_paddr_to_memtype(unsigned int paddr)
@@ -344,6 +396,7 @@
 	reserve_pmem_memory();
 	reserve_ion_memory();
 	reserve_mdp_memory();
+	reserve_rtb_memory();
 }
 
 static struct reserve_info apq8064_reserve_info __initdata = {
@@ -386,13 +439,45 @@
 		apq8064_reserve_info.bank_size);
 }
 
+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 apq8064_reserve(void)
 {
-	reserve_info = &apq8064_reserve_info;
-	locate_unstable_memory();
+	apq8064_set_display_params(prim_panel_name, ext_panel_name);
 	msm_reserve();
 }
 
+static void __init place_movable_zone(void)
+{
+	movable_reserved_start = apq8064_reserve_info.low_unstable_address;
+	movable_reserved_size = apq8064_reserve_info.max_unstable_size;
+	pr_info("movable zone start %lx size %lx\n",
+		movable_reserved_start, movable_reserved_size);
+}
+
+static void __init apq8064_early_reserve(void)
+{
+	reserve_info = &apq8064_reserve_info;
+	locate_unstable_memory();
+	place_movable_zone();
+
+}
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 static struct msm_hsic_host_platform_data msm_hsic_pdata = {
 	.strobe		= 88,
@@ -466,15 +551,144 @@
 	},
 };
 
+/* 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,
 };
 
-#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+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_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
+	}
+}
+
+static struct smb349_platform_data smb349_data __initdata = {
+	.en_n_gpio		= PM8921_GPIO_PM_TO_SYS(37),
+	.chg_susp_gpio		= PM8921_GPIO_PM_TO_SYS(30),
+	.chg_current_ma		= 2200,
+};
+
+static struct i2c_board_info smb349_charger_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(SMB349_NAME, 0x1B),
+		.platform_data	= &smb349_data,
+	},
+};
+
+struct sx150x_platform_data apq8064_sx150x_data[] = {
+	[SX150X_EPM] = {
+		.gpio_base	= GPIO_EPM_EXPANDER_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+};
+
+static struct epm_chan_properties ads_adc_channel_data[] = {
+	{10, 100}, {500, 50}, {1, 1}, {1, 1},
+	{20, 50}, {10, 100}, {1, 1}, {1, 1},
+	{10, 100}, {10, 100}, {100, 100}, {200, 100},
+	{100, 50}, {2000, 50}, {1000, 50}, {200, 50},
+	{200, 100}, {1, 1}, {20, 50}, {500, 50},
+	{50, 50}, {200, 100}, {500, 100}, {20, 50},
+	{200, 50}, {2000, 100}, {1000, 50}, {100, 50},
+	{200, 100}, {500, 50}, {1000, 100}, {200, 50},
+	{1000, 50}, {50, 50}, {100, 50}, {100, 50},
+	{1, 1}, {1, 1}, {20, 100}, {20, 50},
+	{500, 100}, {1000, 100}, {100, 50}, {1000, 50},
+	{100, 50}, {1000, 100}, {100, 50}, {100, 50},
+};
+
+static struct epm_adc_platform_data epm_adc_pdata = {
+	.channel		= ads_adc_channel_data,
+	.bus_id	= 0x0,
+	.epm_i2c_board_info = {
+		.type	= "sx1509q",
+		.addr = 0x3e,
+		.platform_data = &apq8064_sx150x_data[SX150X_EPM],
+	},
+	.gpio_expander_base_addr = GPIO_EPM_EXPANDER_BASE,
+};
+
+static struct platform_device epm_adc_device = {
+	.name   = "epm_adc",
+	.id = -1,
+	.dev = {
+		.platform_data = &epm_adc_pdata,
+	},
+};
+
+static void __init apq8064_epm_adc_init(void)
+{
+	epm_adc_pdata.num_channels = 32;
+	epm_adc_pdata.num_adc = 2;
+	epm_adc_pdata.chan_per_adc = 16;
+	epm_adc_pdata.chan_per_mux = 8;
+};
 
 /* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
  * 4 micbiases are used to power various analog and digital
@@ -485,14 +699,14 @@
  * does not need to be as high as 2.85V. It is choosen for
  * microphone sensitivity purpose.
  */
-static struct tabla_pdata apq8064_tabla_platform_data = {
+static struct wcd9xxx_pdata apq8064_tabla_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(42),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -503,7 +717,45 @@
 		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
 		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
 		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
-	}
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
 };
 
 static struct slim_device apq8064_slim_tabla = {
@@ -514,14 +766,14 @@
 	},
 };
 
-static struct tabla_pdata apq8064_tabla20_platform_data = {
+static struct wcd9xxx_pdata apq8064_tabla20_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(42),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -532,7 +784,45 @@
 		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
 		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
 		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
-	}
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
 };
 
 static struct slim_device apq8064_slim_tabla20 = {
@@ -628,7 +918,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	14, 0, 0, 24, 1, 12, 0, 0, 0, 0,
+	14, 1, 0, 22, 2, 12, 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,
@@ -636,14 +926,14 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T7 Object */
-	100, 16, 50,
+	100, 10, 50,
 	/* T8 Object */
-	25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
 	/* T9 Object */
 	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
 	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
-	85, 5, 10, 10, 10, 10, 135, 55, 70, 40,
-	10, 5, 0, 0, 0,
+	85, 5, 0, 5, 9, 5, 12, 35, 70, 40,
+	20, 5, 0, 0, 0,
 	/* T18 Object */
 	0, 0,
 	/* T24 Object */
@@ -661,14 +951,14 @@
 	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
 	16,
 	/* T46 Object */
-	64, 0, 20, 20, 0, 0, 0, 0, 0,
+	68, 0, 16, 16, 0, 0, 0, 0, 0,
 	/* T47 Object */
 	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
 	/* T48 Object */
 	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
-	48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
-	0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
-	52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
+	32, 40, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 10,
+	52, 10, 12, 0, 33, 0, 1, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T56 Object */
@@ -676,8 +966,8 @@
 	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,
-	2, 99, 33, 0, 149, 24, 193, 255, 255, 255,
-	255,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
 };
 
 #define MXT_TS_GPIO_IRQ			6
@@ -698,8 +988,14 @@
 static struct mxt_platform_data mxt_platform_data = {
 	.config_array		= mxt_config_array,
 	.config_array_size	= ARRAY_SIZE(mxt_config_array),
-	.x_size			= 1365,
-	.y_size			= 767,
+	.panel_minx		= 0,
+	.panel_maxx		= 1365,
+	.panel_miny		= 0,
+	.panel_maxy		= 767,
+	.disp_minx		= 0,
+	.disp_maxx		= 1365,
+	.disp_miny		= 0,
+	.disp_maxy		= 767,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.i2c_pull_up		= true,
 	.reset_gpio		= MXT_TS_RESET_GPIO,
@@ -866,6 +1162,11 @@
 	.dev		= {.platform_data = &qcom_wcnss_pdata},
 };
 
+static struct platform_device msm_device_iris_fm __devinitdata = {
+	.name = "iris_fm",
+	.id   = -1,
+};
+
 #if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
 		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
 		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
@@ -1048,64 +1349,83 @@
 	},
 };
 
-static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
+static struct msm_rpmrs_level msm_rpmrs_levels[] = {
 	{
 		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,
 	},
 };
 
+uint32_t apq8064_rpm_get_swfi_latency(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_levels); i++) {
+		if (msm_rpmrs_levels[i].sleep_mode ==
+			MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)
+			return msm_rpmrs_levels[i].latency_us;
+	}
+
+	return 0;
+}
+
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
 	.mode = MSM_PM_BOOT_CONFIG_TZ,
 };
@@ -1329,7 +1649,7 @@
 	[0] = {
 		.reg_base_addr = MSM_SAW_L2_BASE,
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
 		.modes = msm_spm_l2_seq_list,
@@ -1346,7 +1666,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1361,7 +1681,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1376,7 +1696,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1391,7 +1711,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1476,16 +1796,16 @@
 	&apq8064_device_otg,
 	&apq8064_device_gadget_peripheral,
 	&apq8064_device_hsusb_host,
-	&apq8064_device_hsic_host,
 	&android_usb_device,
 	&msm_device_wcnss_wlan,
+	&msm_device_iris_fm,
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	&android_pmem_device,
 	&android_pmem_adsp_device,
-#endif
 	&android_pmem_audio_device,
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
 #ifdef CONFIG_ION_MSM
 	&ion_dev,
 #endif
@@ -1530,6 +1850,8 @@
 	&apq_cpudai_auxpcm_rx,
 	&apq_cpudai_auxpcm_tx,
 	&apq_cpudai_stub,
+	&apq_cpudai_slimbus_1_rx,
+	&apq_cpudai_slimbus_1_tx,
 	&apq8064_rpm_device,
 	&apq8064_rpm_log_device,
 	&apq8064_rpm_stat_device,
@@ -1539,9 +1861,22 @@
 	&msm_bus_8064_sys_fpb,
 	&msm_bus_8064_cpss_fpb,
 	&apq8064_msm_device_vidc,
+	&msm_pil_dsps,
 	&msm_8960_riva,
 	&msm_8960_q6_lpass,
 	&msm_gss,
+#ifdef CONFIG_MSM_RTB
+	&msm_rtb_device,
+#endif
+	&apq8064_cpu_idle_device,
+	&apq8064_msm_gov_device,
+	&apq8064_device_cache_erp,
+	&epm_adc_device,
+	&apq8064_qdss_device,
+	&msm_etb_device,
+	&msm_tpiu_device,
+	&msm_funnel_device,
+	&apq8064_etm_device,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -1561,6 +1896,9 @@
 	&apq8064_device_uart_gsbi1,
 	&apq8064_device_uart_gsbi7,
 	&msm_device_sps_apq8064,
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
 };
 
 static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
@@ -1578,6 +1916,13 @@
 		.chip_select            = 2,
 		.mode                   = SPI_MODE_0,
 	},
+	{
+		.modalias		= "epm_adc",
+		.max_speed_hz		= 1100000,
+		.bus_num		= 0,
+		.chip_select		= 3,
+		.mode			= SPI_MODE_0,
+	},
 };
 
 static struct slim_boardinfo apq8064_slim_devices[] = {
@@ -1623,6 +1968,8 @@
 	apq8064_i2c_qup_gsbi1_pdata.use_gsbi_shared_mode = 1;
 	apq8064_device_qup_i2c_gsbi3.dev.platform_data =
 					&apq8064_i2c_qup_gsbi3_pdata;
+	apq8064_device_qup_i2c_gsbi1.dev.platform_data =
+					&apq8064_i2c_qup_gsbi1_pdata;
 	apq8064_device_qup_i2c_gsbi4.dev.platform_data =
 					&apq8064_i2c_qup_gsbi4_pdata;
 }
@@ -1648,6 +1995,128 @@
 }
 #endif
 
+#define GPIO_KEY_HOME		PM8921_GPIO_PM_TO_SYS(27)
+#define GPIO_KEY_VOLUME_UP	PM8921_GPIO_PM_TO_SYS(35)
+#define GPIO_KEY_VOLUME_DOWN	PM8921_GPIO_PM_TO_SYS(38)
+#define GPIO_KEY_CAM_FOCUS	PM8921_GPIO_PM_TO_SYS(3)
+#define GPIO_KEY_CAM_SNAP	PM8921_GPIO_PM_TO_SYS(4)
+#define GPIO_KEY_ROTATION	PM8921_GPIO_PM_TO_SYS(42)
+
+static struct gpio_keys_button cdp_keys[] = {
+	{
+		.code           = KEY_HOME,
+		.gpio           = GPIO_KEY_HOME,
+		.desc           = "home_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEUP,
+		.gpio           = GPIO_KEY_VOLUME_UP,
+		.desc           = "volume_up_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEDOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.desc           = "volume_down_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = SW_ROTATE_LOCK,
+		.gpio           = GPIO_KEY_ROTATION,
+		.desc           = "rotate_key",
+		.active_low     = 1,
+		.type		= EV_SW,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_platform_data cdp_keys_data = {
+	.buttons        = cdp_keys,
+	.nbuttons       = ARRAY_SIZE(cdp_keys),
+};
+
+static struct platform_device cdp_kp_pdev = {
+	.name           = "gpio-keys",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &cdp_keys_data,
+	},
+};
+
+static struct gpio_keys_button mtp_keys[] = {
+	{
+		.code           = KEY_CAMERA_FOCUS,
+		.gpio           = GPIO_KEY_CAM_FOCUS,
+		.desc           = "cam_focus_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEUP,
+		.gpio           = GPIO_KEY_VOLUME_UP,
+		.desc           = "volume_up_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEDOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.desc           = "volume_down_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_CAMERA_SNAPSHOT,
+		.gpio           = GPIO_KEY_CAM_SNAP,
+		.desc           = "cam_snap_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_platform_data mtp_keys_data = {
+	.buttons        = mtp_keys,
+	.nbuttons       = ARRAY_SIZE(mtp_keys),
+};
+
+static struct platform_device mtp_kp_pdev = {
+	.name           = "gpio-keys",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &mtp_keys_data,
+	},
+};
+
+/* 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)
 {
 	if (machine_is_apq8064_rumi3())
@@ -1671,6 +2140,12 @@
 
 static struct i2c_registry apq8064_i2c_devices[] __initdata = {
 	{
+		I2C_LIQUID,
+		APQ_8064_GSBI1_QUP_I2C_BUS_ID,
+		smb349_charger_i2c_info,
+		ARRAY_SIZE(smb349_charger_i2c_info)
+	},
+	{
 		I2C_SURF | I2C_LIQUID,
 		APQ_8064_GSBI3_QUP_I2C_BUS_ID,
 		mxt_device_info,
@@ -1732,6 +2207,20 @@
 #endif
 }
 
+static void enable_ddr3_regulator(void)
+{
+	static struct regulator *ext_ddr3;
+
+	/* Use MPP7 output state as a flag for PCDDR3 presence. */
+	if (gpio_get_value_cansleep(PM8921_MPP_PM_TO_SYS(7)) > 0) {
+		ext_ddr3 = regulator_get(NULL, "ext_ddr3");
+		if (IS_ERR(ext_ddr3) || ext_ddr3 == NULL)
+			pr_err("Could not get MPP7 regulator\n");
+		else
+			regulator_enable(ext_ddr3);
+	}
+}
+
 static void __init apq8064_common_init(void)
 {
 	if (socinfo_init() < 0)
@@ -1740,6 +2229,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();
@@ -1750,10 +2241,19 @@
 	apq8064_init_pmic();
 	if (machine_is_apq8064_liquid())
 		msm_otg_pdata.mhl_enable = true;
+
+	msm_otg_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us + 1;
+
 	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
-	apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+	apq8064_ehci_host_init();
 	apq8064_init_buses();
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	enable_ddr3_regulator();
+	if (machine_is_apq8064_mtp()) {
+		apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+		device_initialize(&apq8064_device_hsic_host.dev);
+	}
 	apq8064_pm8xxx_gpio_mpp_init();
 	apq8064_init_mmc();
 
@@ -1764,6 +2264,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);
@@ -1772,6 +2273,7 @@
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	apq8064_epm_adc_init();
 }
 
 static void __init apq8064_allocate_memory_regions(void)
@@ -1807,12 +2309,19 @@
 	apq8064_common_init();
 	ethernet_init();
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
+	if (!machine_is_apq8064_mtp())
+		msm_rotator_update_bus_vectors(1376, 768);
 	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
 	apq8064_init_fb();
 	apq8064_init_gpu();
-	platform_add_devices(msm_footswitch_devices,
-			     msm_num_footswitch_devices);
+	platform_add_devices(apq8064_fs_devices, apq8064_num_fs_devices);
 	apq8064_init_cam();
+
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+		platform_device_register(&cdp_kp_pdev);
+
+	if (machine_is_apq8064_mtp())
+		platform_device_register(&mtp_kp_pdev);
 }
 
 MACHINE_START(APQ8064_SIM, "QCT APQ8064 SIMULATOR")
@@ -1842,6 +2351,7 @@
 	.timer = &msm_timer,
 	.init_machine = apq8064_cdp_init,
 	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
 MACHINE_END
 
 MACHINE_START(APQ8064_MTP, "QCT APQ8064 MTP")
@@ -1852,6 +2362,7 @@
 	.timer = &msm_timer,
 	.init_machine = apq8064_cdp_init,
 	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
 MACHINE_END
 
 MACHINE_START(APQ8064_LIQUID, "QCT APQ8064 LIQUID")
@@ -1862,6 +2373,18 @@
 	.timer = &msm_timer,
 	.init_machine = apq8064_cdp_init,
 	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
+MACHINE_END
+
+MACHINE_START(MPQ8064_CDP, "QCT MPQ8064 CDP")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
 MACHINE_END
 
 MACHINE_START(MPQ8064_HRD, "QCT MPQ8064 HRD")
@@ -1871,6 +2394,7 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = apq8064_cdp_init,
+	.init_very_early = apq8064_early_reserve,
 MACHINE_END
 
 MACHINE_START(MPQ8064_DTV, "QCT MPQ8064 DTV")
@@ -1880,5 +2404,6 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = apq8064_cdp_init,
+	.init_very_early = apq8064_early_reserve,
 MACHINE_END
 
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index e8c8144..23ca39f 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -31,6 +31,8 @@
 #define PM8821_MPP_PM_TO_SYS(pm_mpp)	(pm_mpp - 1 + PM8821_MPP_BASE)
 #define PM8821_IRQ_BASE			(PM8921_IRQ_BASE + PM8921_NR_IRQS)
 
+#define TABLA_INTERRUPT_BASE		(PM8821_IRQ_BASE + PM8821_NR_IRQS)
+
 extern struct pm8xxx_regulator_platform_data
 	msm8064_pm8921_regulator_pdata[] __devinitdata;
 
@@ -69,9 +71,12 @@
 #define APQ_8064_GSBI3_QUP_I2C_BUS_ID 3
 #define APQ_8064_GSBI4_QUP_I2C_BUS_ID 4
 
+unsigned char apq8064_hdmi_as_primary_selected(void);
 void apq8064_init_fb(void);
 void apq8064_allocate_fb_region(void);
 void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
+uint32_t apq8064_rpm_get_swfi_latency(void);
+void __init apq8064_set_display_params(char *prim_panel, char *ext_panel);
 
 void apq8064_init_gpu(void);
 void apq8064_pm8xxx_gpio_mpp_init(void);
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 47a381a..92e88aa72 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -349,16 +349,14 @@
 };
 
 static struct camera_vreg_t msm_8930_back_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
+	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
 
 static struct camera_vreg_t msm_8930_front_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
-	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
+	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 };
@@ -427,11 +425,17 @@
 #endif
 };
 
+static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
 	.mount_angle	= 90,
 	.cam_vreg = msm_8930_back_cam_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8930_back_cam_vreg),
 	.gpio_conf = &msm_8930_back_cam_gpio_conf,
+	.csi_lane_params = &imx074_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
@@ -442,12 +446,12 @@
 	.sensor_platform_info = &sensor_board_info_imx074,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &imx074_actuator_info
 };
 
 static struct camera_vreg_t msm_8930_mt9m114_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
-	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
+	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
@@ -457,31 +461,44 @@
 	.flash_type = MSM_CAMERA_FLASH_NONE
 };
 
+static struct msm_camera_csi_lane_params mt9m114_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x1,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
 	.mount_angle = 90,
 	.cam_vreg = msm_8930_mt9m114_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8930_mt9m114_vreg),
-	.gpio_conf = &msm_8930_back_cam_gpio_conf,
+	.gpio_conf = &msm_8930_front_cam_gpio_conf,
+	.csi_lane_params = &mt9m114_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
 	.sensor_name = "mt9m114",
-	.pdata = &msm_camera_csi_device_data[0],
+	.pdata = &msm_camera_csi_device_data[1],
 	.flash_data = &flash_mt9m114,
 	.sensor_platform_info = &sensor_board_info_mt9m114,
 	.csi_if = 1,
-	.camera_type = BACK_CAMERA_2D,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
 };
 
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
 
+static struct msm_camera_csi_lane_params ov2720_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x3,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
 	.mount_angle	= 0,
 	.cam_vreg = msm_8930_front_cam_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8930_front_cam_vreg),
 	.gpio_conf = &msm_8930_front_cam_gpio_conf,
+	.csi_lane_params = &ov2720_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
@@ -491,13 +508,13 @@
 	.sensor_platform_info = &sensor_board_info_ov2720,
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
+	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
 
@@ -505,11 +522,17 @@
 	.flash_type = MSM_CAMERA_FLASH_NONE,
 };
 
+static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
 	.mount_angle  = 0,
 	.cam_vreg = msm_8930_s5k3l1yx_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8930_s5k3l1yx_vreg),
 	.gpio_conf = &msm_8930_back_cam_gpio_conf,
+	.csi_lane_params = &s5k3l1yx_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
@@ -519,6 +542,7 @@
 	.sensor_platform_info = &sensor_board_info_s5k3l1yx,
 	.csi_if               = 1,
 	.camera_type          = BACK_CAMERA_2D,
+	.sensor_type          = BAYER_SENSOR,
 };
 
 void __init msm8930_init_cam(void)
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index e6b342f..42b20b2 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"
@@ -442,7 +441,7 @@
 #endif
 	.mdp_rev = MDP_REV_42,
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	.mem_hid = ION_CP_MM_HEAP_ID,
+	.mem_hid = BIT(ION_CP_MM_HEAP_ID),
 #else
 	.mem_hid = MEMTYPE_EBI1,
 #endif
@@ -497,6 +496,7 @@
 	.fpga_ctrl_mode = FPGA_SPI_INTF,
 	.phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db,
 	.dlane_swap = 0x1,
+	.enable_wled_bl_ctrl = 0x1,
 };
 
 static struct platform_device mipi_dsi_novatek_panel_device = {
@@ -623,9 +623,15 @@
 	if (on == prev_on)
 		return 0;
 
-	if (!reg_ext_5v)
-		reg_ext_5v = regulator_get(&hdmi_msm_device.dev,
-			"hdmi_mvs");
+	if (!reg_ext_5v) {
+		reg_ext_5v = regulator_get(&hdmi_msm_device.dev, "hdmi_mvs");
+		if (IS_ERR(reg_ext_5v)) {
+			pr_err("'%s' regulator not found, rc=%ld\n",
+				"hdmi_mvs", IS_ERR(reg_ext_5v));
+			reg_ext_5v = NULL;
+			return -ENODEV;
+		}
+	}
 
 	if (on) {
 		rc = regulator_enable(reg_ext_5v);
@@ -775,8 +781,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-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 84dbea8..854f318 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -31,18 +31,6 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-static struct gpiomux_setting spi_active_config2 = {
-	.func = GPIOMUX_FUNC_2,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting spi_suspended_config2 = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_UP,
-};
-
 static struct gpiomux_setting gsbi3_suspended_cfg = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_2MA,
@@ -61,6 +49,12 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gsbi9 = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct gpiomux_setting gsbi10 = {
 	.func = GPIOMUX_FUNC_2,
 	.drv = GPIOMUX_DRV_8MA,
@@ -177,26 +171,6 @@
 	},
 };
 #endif
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-static struct gpiomux_setting hsic_act_cfg = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_12MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting hsic_sus_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_DOWN,
-	.dir = GPIOMUX_OUT_LOW,
-};
-
-static struct gpiomux_setting hsic_hub_act_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-#endif
 
 static struct gpiomux_setting hap_lvl_shft_suspended_config = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -313,13 +287,6 @@
 		},
 	},
 	{
-		.gpio      = 14,		/* GSBI1 SPI_CS_1 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &spi_suspended_config2,
-			[GPIOMUX_ACTIVE] = &spi_active_config2,
-		},
-	},
-	{
 		.gpio      = 16,	/* GSBI3 I2C QUP SDA */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
@@ -346,24 +313,24 @@
 		},
 	},
 	{
-		.gpio      = 24,	/* GSBI5 UART2 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi5,
-		},
-	},
-	{
-		.gpio      = 25,	/* GSBI5 UART2 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi5,
-		},
-	},
-	{
 		.gpio      = 44,	/* GSBI12 I2C QUP SDA */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi12,
 		},
 	},
 	{
+		.gpio      = 95,	/* GSBI9 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9,
+		},
+	},
+	{
+		.gpio      = 96,	/* GSBI12 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9,
+		},
+	},
+	{
 		.gpio      = 45,	/* GSBI12 I2C QUP SCL */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi12,
@@ -500,32 +467,6 @@
 	},
 };
 
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-static struct msm_gpiomux_config msm8960_hsic_configs[] = {
-	{
-		.gpio = 150,               /*HSIC_STROBE */
-		.settings = {
-			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
-			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
-		},
-	},
-	{
-		.gpio = 151,               /* HSIC_DATA */
-		.settings = {
-			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
-			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
-		},
-	},
-	{
-		.gpio = 91,               /* HSIC_HUB_RESET */
-		.settings = {
-			[GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
-			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
-		},
-	},
-};
-#endif
-
 static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
 	{
 		.gpio = 47,
@@ -624,7 +565,11 @@
 };
 #endif
 
-#ifdef MSM8930_PHASE_2
+static struct gpiomux_setting haptics_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
 static struct gpiomux_setting haptics_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
@@ -635,17 +580,18 @@
 	{
 		.gpio = 77,
 		.settings = {
+			[GPIOMUX_ACTIVE] = &haptics_active_cfg,
 			[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
 		},
 	},
 	{
 		.gpio = 78,
 		.settings = {
+			[GPIOMUX_ACTIVE] = &haptics_active_cfg,
 			[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
 		},
 	},
 };
-#endif
 
 int __init msm8930_init_gpiomux(void)
 {
@@ -692,19 +638,10 @@
 		msm_gpiomux_install(mdm_configs,
 			ARRAY_SIZE(mdm_configs));
 
-#ifdef MSM8930_PHASE_2
-	if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid())
+	if (machine_is_msm8930_cdp() || machine_is_msm8930_mtp()
+		|| machine_is_msm8930_fluid())
 		msm_gpiomux_install(msm8930_haptics_configs,
 			ARRAY_SIZE(msm8930_haptics_configs));
-#endif
-
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
-			!machine_is_msm8930_mtp() &&
-			!machine_is_msm8930_fluid())
-		msm_gpiomux_install(msm8960_hsic_configs,
-			ARRAY_SIZE(msm8960_hsic_configs));
-#endif
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 	msm_gpiomux_install(msm8960_hdmi_configs,
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
new file mode 100644
index 0000000..7c8c64f
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -0,0 +1,163 @@
+/* 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/msm_kgsl.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+
+#include "devices.h"
+#include "board-8930.h"
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors grp3d_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp3d_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2000),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(3200),
+	},
+};
+
+static struct msm_bus_vectors grp3d_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(4264),
+	},
+};
+
+static struct msm_bus_paths grp3d_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp3d_init_vectors),
+		grp3d_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_low_vectors),
+		grp3d_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_vectors),
+		grp3d_nominal_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_max_vectors),
+		grp3d_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata grp3d_bus_scale_pdata = {
+	grp3d_bus_scale_usecases,
+	ARRAY_SIZE(grp3d_bus_scale_usecases),
+	.name = "grp3d",
+};
+#endif
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name = KGSL_3D0_REG_MEMORY,
+		.start = 0x04300000, /* GFX3D address */
+		.end = 0x0431ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = GFX3D_IRQ,
+		.end = GFX3D_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static const char *kgsl_3d0_iommu0_ctx_names[] = {
+	"gfx3d_user",
+	/* priv_ctx goes here */
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_3d0_iommu0_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctx_names),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 450000000,
+			.bus_freq = 3,
+			.io_fraction = 0,
+		},
+		{
+			.gpu_freq = 320000000,
+			.bus_freq = 2,
+			.io_fraction = 33,
+		},
+		{
+			.gpu_freq = 192000000,
+			.bus_freq = 1,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 4,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/12,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp3d_bus_scale_pdata,
+#endif
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+};
+
+static struct platform_device device_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+void __init msm8930_init_gpu(void)
+{
+	platform_device_register(&device_kgsl_3d0);
+}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 3f9f976..86c0438 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -89,10 +89,12 @@
 /* Initial pm8038 GPIO configurations */
 static struct pm8xxx_gpio_init pm8038_gpios[] __initdata = {
 	/* keys GPIOs */
-	PM8XXX_GPIO_INPUT(3, PM_GPIO_PULL_UP_1P5),
-	PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_1P5),
-	PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_1P5),
-	PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_1P5),
+	PM8XXX_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
+	PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
+	PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
+	PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
+	/* haptics gpio */
+	PM8XXX_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
 };
 
 /* Initial pm8038 MPP configurations */
@@ -223,13 +225,28 @@
 	.warm_bat_voltage	= 4100,
 	.thermal_mitigation	= pm8921_therm_mitigation,
 	.thermal_levels		= ARRAY_SIZE(pm8921_therm_mitigation),
+	.led_src_config		= LED_SRC_VPH_PWR,
 };
 
 #define PM8038_WLED_MAX_CURRENT		25
+#define PM8XXX_LED_PWM_PERIOD		1000
+#define PM8XXX_LED_PWM_DUTY_MS		20
+#define PM8038_RGB_LED_MAX_CURRENT	12
 
 static struct led_info pm8038_led_info[] = {
 	[0] = {
 		.name			= "wled",
+		.default_trigger	= "bkl_trigger",
+	},
+	[1] = {
+		.name			= "led:rgb_red",
+		.default_trigger	= "battery-charging",
+	},
+	[2] = {
+		.name			= "led:rgb_green",
+	},
+	[3] = {
+		.name			= "led:rgb_blue",
 	},
 };
 
@@ -248,14 +265,54 @@
 	.num_strings = 1,
 };
 
+static int pm8038_led0_pwm_duty_pcts[56] = {
+		1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+		40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+		80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+		92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+		58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+		14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8038_led0_pwm_duty_cycles = {
+	.duty_pcts = (int *)&pm8038_led0_pwm_duty_pcts,
+	.num_duty_pcts = ARRAY_SIZE(pm8038_led0_pwm_duty_pcts),
+	.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+	.start_idx = 0,
+};
+
 static struct pm8xxx_led_config pm8038_led_configs[] = {
 	[0] = {
 		.id = PM8XXX_ID_WLED,
 		.mode = PM8XXX_LED_MODE_MANUAL,
 		.max_current = PM8038_WLED_MAX_CURRENT,
-		.default_state = 1,
+		.default_state = 0,
 		.wled_cfg = &wled_cfg,
 	},
+	[1] = {
+		.id = PM8XXX_ID_RGB_LED_RED,
+		.mode = PM8XXX_LED_MODE_PWM1,
+		.max_current = PM8038_RGB_LED_MAX_CURRENT,
+		.pwm_channel = 5,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+	},
+	[2] = {
+		.id = PM8XXX_ID_RGB_LED_GREEN,
+		.mode = PM8XXX_LED_MODE_PWM1,
+		.max_current = PM8038_RGB_LED_MAX_CURRENT,
+		.pwm_channel = 4,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+	},
+	[3] = {
+		.id = PM8XXX_ID_RGB_LED_BLUE,
+		.mode = PM8XXX_LED_MODE_PWM1,
+		.max_current = PM8038_RGB_LED_MAX_CURRENT,
+		.pwm_channel = 3,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+	},
 };
 
 static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
@@ -273,6 +330,7 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -310,4 +368,8 @@
 				&msm8930_ssbi_pm8038_pdata;
 	pm8038_platform_data.num_regulators
 		= msm8930_pm8038_regulator_pdata_len;
+	if (machine_is_apq8064_mtp())
+		pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	else if (machine_is_apq8064_liquid())
+		pm8921_bms_pdata.battery_type = BATT_DESAY;
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 2f9fdcd..f760e7b 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -30,10 +30,9 @@
 	REGULATOR_SUPPLY("8038_l2",		NULL),
 	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-0048"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",        "4-0020"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8038_l3",		NULL),
@@ -85,6 +84,7 @@
 	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar-slim"),
+	REGULATOR_SUPPLY("vddp",		"0-0048"),
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("8038_l12",		NULL),
@@ -109,10 +109,6 @@
 };
 VREG_CONSUMERS(L18) = {
 	REGULATOR_SUPPLY("8038_l18",		NULL),
-	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
-	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
-	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
-	REGULATOR_SUPPLY("cam_vio",             "4-0020"),
 };
 VREG_CONSUMERS(L19) = {
 	REGULATOR_SUPPLY("8038_l19",		NULL),
@@ -175,12 +171,16 @@
 };
 VREG_CONSUMERS(LVS1) = {
 	REGULATOR_SUPPLY("8038_lvs1",		NULL),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vio",             "4-0020"),
 };
 VREG_CONSUMERS(LVS2) = {
 	REGULATOR_SUPPLY("8038_lvs2",		NULL),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-004a"),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
-	REGULATOR_SUPPLY("vddp",		"12-0048"),
+	REGULATOR_SUPPLY("vcc_i2c",		"0-0048"),
 };
 VREG_CONSUMERS(EXT_5V) = {
 	REGULATOR_SUPPLY("ext_5v",		NULL),
@@ -190,6 +190,9 @@
 	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
 	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
 };
+VREG_CONSUMERS(VDD_DIG_CORNER) = {
+	REGULATOR_SUPPLY("vdd_dig_corner",	NULL),
+};
 
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
 			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
@@ -288,8 +291,8 @@
 
 #define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
 		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
-		 _force_mode, _power_mode, _state, _sleep_selectable, \
-		 _always_on, _supply_regulator, _system_uA) \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -315,6 +318,7 @@
 		.freq			= RPM_VREG_FREQ_##_freq, \
 		.pin_fn			= _pin_fn, \
 		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
 		.power_mode		= _power_mode, \
 		.state			= _state, \
 		.sleep_selectable	= _sleep_selectable, \
@@ -328,24 +332,28 @@
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
 		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, _system_uA)
 
 #define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
-		 _supply_regulator, _system_uA, _freq) \
+		 _supply_regulator, _system_uA, _freq, _force_mode, \
+		 _sleep_set_force_mode) \
 	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
-		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
+		 | REGULATOR_CHANGE_DRMS, 0, _min_uV, _system_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8930_NONE, \
-		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
-		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
-		 _supply_regulator, _system_uA)
+		 RPM_VREG_FORCE_MODE_8930_##_force_mode, \
+		 RPM_VREG_FORCE_MODE_8930_##_sleep_set_force_mode, \
+		 RPM_VREG_POWER_MODE_8930_PWM, RPM_VREG_STATE_OFF, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA)
 
 #define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
 	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
 		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
@@ -355,6 +363,17 @@
 	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
 		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+#define RPM_CORNER(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator) \
+	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 0, 0, 0, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
 		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
@@ -437,11 +456,11 @@
 
 static struct rpm_regulator_init_data
 msm8930_rpm_regulator_init_data[] __devinitdata = {
-	/*	 ID    a_on pd ss min_uV   max_uV  supply sys_uA freq */
-	RPM_SMPS(S1,	 1, 1, 1,  500000, 1150000, NULL, 100000, 4p80),
-	RPM_SMPS(S2,	 1, 1, 0, 1400000, 1400000, NULL, 100000, 1p60),
-	RPM_SMPS(S3,	 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20),
-	RPM_SMPS(S4,	 1, 1, 0, 2200000, 2200000, NULL, 100000, 1p60),
+	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
+	RPM_SMPS(S1, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
+	RPM_SMPS(S2, 1, 1, 1, 1400000, 1400000, NULL, 100000, 1p60, AUTO, LPM),
+	RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, LPM),
+	RPM_SMPS(S4, 1, 1, 1, 1950000, 2200000, NULL, 100000, 1p60, AUTO, LPM),
 
 	/*	ID     a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
 	RPM_LDO(L1,	 0, 1, 0, 1300000, 1300000, "8038_s2", 0, 0),
@@ -464,12 +483,16 @@
 	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
 	RPM_LDO(L22,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
-	RPM_LDO(L24,	 1, 1, 1,  500000, 1150000, "8038_s2", 10000, 10000),
+	RPM_LDO(L24,	 0, 1, 1,  500000, 1150000, "8038_s2", 10000, 10000),
 	RPM_LDO(L26,     1, 1, 0, 1050000, 1050000, "8038_s2", 10000, 10000),
 
 	/*	ID     a_on pd ss		    supply */
 	RPM_VS(LVS1,	 0, 1, 0,		    "8038_l11"),
 	RPM_VS(LVS2,	 0, 1, 0,		    "8038_l11"),
+
+	/*	   ID            a_on ss min_corner  max_corner  supply */
+	RPM_CORNER(VDD_DIG_CORNER, 0, 1, RPM_VREG_CORNER_NONE,
+		RPM_VREG_CORNER_HIGH, NULL),
 };
 
 int msm8930_pm8038_regulator_pdata_len __devinitdata =
@@ -480,5 +503,5 @@
 	.num_regulators		= ARRAY_SIZE(msm8930_rpm_regulator_init_data),
 	.version		= RPM_VREG_VERSION_8930,
 	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8038_L24,
-	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8038_S1,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
 };
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index dee1e98..83fb5fd 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
@@ -245,6 +245,7 @@
 	.wpswitch_gpio	= PM8921_GPIO_PM_TO_SYS(16),
 #else
 	.wpswitch_gpio	= 66,
+	.wpswitch_polarity = 1,
 #endif
 #endif
 	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
@@ -264,7 +265,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 a094ba5..5493628 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -42,6 +42,10 @@
 #include <linux/gpio_keys.h>
 #include <linux/memory.h>
 
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/setup.h>
@@ -68,12 +72,6 @@
 #include <mach/msm_xo.h>
 #include <mach/restart.h>
 
-#ifdef CONFIG_WCD9310_CODEC
-#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
-#endif
-
 #include <linux/ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
@@ -476,23 +474,30 @@
 
 	if (high - low <= bank_size)
 		return;
+
+	msm8930_reserve_info.bank_size = bank_size;
+#ifdef CONFIG_ENABLE_DMM
 	msm8930_reserve_info.low_unstable_address = mb->start -
 					MIN_MEMORY_BLOCK_SIZE + mb->size;
 	msm8930_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
-
-	msm8930_reserve_info.bank_size = bank_size;
 	pr_info("low unstable address %lx max size %lx bank size %lx\n",
 		msm8930_reserve_info.low_unstable_address,
 		msm8930_reserve_info.max_unstable_size,
 		msm8930_reserve_info.bank_size);
+#else
+	msm8930_reserve_info.low_unstable_address = 0;
+	msm8930_reserve_info.max_unstable_size = 0;
+#endif
 }
 
 static void __init place_movable_zone(void)
 {
+#ifdef CONFIG_ENABLE_DMM
 	movable_reserved_start = msm8930_reserve_info.low_unstable_address;
 	movable_reserved_size = msm8930_reserve_info.max_unstable_size;
 	pr_info("movable zone start %lx size %lx\n",
 		movable_reserved_start, movable_reserved_size);
+#endif
 }
 
 static void __init msm8930_early_memory(void)
@@ -518,9 +523,9 @@
 	msm8930_allocate_fb_region();
 }
 
-#ifdef CONFIG_WCD9310_CODEC
+#ifdef CONFIG_WCD9304_CODEC
 
-#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+#define SITAR_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
 
 /* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
  * 4 micbiases are used to power various analog and digital
@@ -531,82 +536,77 @@
  * does not need to be as high as 2.85V. It is choosen for
  * microphone sensitivity purpose.
  */
-static struct tabla_pdata tabla_platform_data = {
-	.slimbus_slave_device = {
-		.name = "tabla-slave",
-		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
+static struct wcd9xxx_pdata sitar_platform_data = {
+		.slimbus_slave_device = {
+		.name = "sitar-slave",
+		.e_addr = {0, 0, 0x00, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(62),
-	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
-
-/*TODO: Replace this with right PM8038 gpio */
-#ifndef MSM8930_PHASE_2
-	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
-#endif
+	.irq_base = SITAR_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = 42,
 	.micbias = {
-		.ldoh_v = TABLA_LDOH_2P85_V,
+		.ldoh_v = SITAR_LDOH_2P85_V,
 		.cfilt1_mv = 1800,
 		.cfilt2_mv = 1800,
-		.cfilt3_mv = 1800,
-		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
-		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
-		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
-		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
-	}
-};
-
-static struct slim_device msm_slim_tabla = {
-	.name = "tabla-slim",
-	.e_addr = {0, 1, 0x10, 0, 0x17, 2},
-	.dev = {
-		.platform_data = &tabla_platform_data,
+		.bias1_cfilt_sel = SITAR_CFILT1_SEL,
+		.bias2_cfilt_sel = SITAR_CFILT2_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1950000,
+		.max_uV = 2200000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
 	},
 };
 
-static struct tabla_pdata tabla20_platform_data = {
-	.slimbus_slave_device = {
-		.name = "tabla-slave",
-		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
-	},
-	.irq = MSM_GPIO_TO_INT(62),
-	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
-
-/*TODO: Replace this with right PM8038 gpio */
-#ifndef MSM8930_PHASE_2
-	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
-#endif
-	.micbias = {
-		.ldoh_v = TABLA_LDOH_2P85_V,
-		.cfilt1_mv = 1800,
-		.cfilt2_mv = 1800,
-		.cfilt3_mv = 1800,
-		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
-		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
-		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
-		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
-	}
-};
-
-static struct slim_device msm_slim_tabla20 = {
-	.name = "tabla2x-slim",
-	.e_addr = {0, 1, 0x60, 0, 0x17, 2},
+static struct slim_device msm_slim_sitar = {
+	.name = "sitar-slim",
+	.e_addr = {0, 1, 0x00, 0, 0x17, 2},
 	.dev = {
-		.platform_data = &tabla20_platform_data,
+	.platform_data = &sitar_platform_data,
 	},
 };
 #endif
 
+
 static struct slim_boardinfo msm_slim_devices[] = {
-#ifdef CONFIG_WCD9310_CODEC
+#ifdef CONFIG_WCD9304_CODEC
 	{
 		.bus_num = 1,
-		.slim_slave = &msm_slim_tabla,
-	},
-	{
-		.bus_num = 1,
-		.slim_slave = &msm_slim_tabla20,
+		.slim_slave = &msm_slim_sitar,
 	},
 #endif
 	/* add more slimbus slaves as needed */
@@ -952,15 +952,17 @@
 {
 #ifdef CONFIG_MSM_BUS_SCALING
 	msm_bus_rpm_set_mt_mask();
-	msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1;
-	msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1;
-	msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1;
-	msm_bus_apps_fabric.dev.platform_data =
-		&msm_bus_8960_apps_fabric_pdata;
-	msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata;
-	msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata;
-	msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata;
-	msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata;
+	msm_bus_8930_apps_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8930_sys_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8930_mm_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8930_apps_fabric.dev.platform_data =
+		&msm_bus_8930_apps_fabric_pdata;
+	msm_bus_8930_sys_fabric.dev.platform_data =
+		&msm_bus_8930_sys_fabric_pdata;
+	msm_bus_8930_mm_fabric.dev.platform_data =
+		&msm_bus_8930_mm_fabric_pdata;
+	msm_bus_8930_sys_fpb.dev.platform_data = &msm_bus_8930_sys_fpb_pdata;
+	msm_bus_8930_cpss_fpb.dev.platform_data = &msm_bus_8930_cpss_fpb_pdata;
 #endif
 }
 
@@ -971,23 +973,55 @@
 #ifdef CONFIG_USB_MSM_OTG_72K
 static struct msm_otg_platform_data msm_otg_pdata;
 #else
+#ifdef CONFIG_MSM_BUS_SCALING
+/* 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",
+};
+#endif
+
 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		= PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE),
 	.power_budget		= 750,
-};
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table	= &usb_bus_scale_pdata,
 #endif
-
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-#define HSIC_HUB_RESET_GPIO	91
-static struct msm_hsic_host_platform_data msm_hsic_pdata = {
-	.strobe		= 150,
-	.data		= 151,
 };
-#else
-static struct msm_hsic_host_platform_data msm_hsic_pdata;
 #endif
 
 #define PID_MAGIC_ID		0x71432909
@@ -1099,7 +1133,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1114,7 +1148,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1163,7 +1197,7 @@
 	[0] = {
 		.reg_base_addr = MSM_SAW_L2_BASE,
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
 		.modes = msm_spm_l2_seq_list,
@@ -1174,127 +1208,25 @@
 #/* TODO: Remove this once PM8038 physically becomes
  * available.
  */
-#ifndef MSM8930_PHASE_2
-#define PM_HAP_EN_GPIO		PM8921_GPIO_PM_TO_SYS(33)
-#define PM_HAP_LEN_GPIO		PM8921_GPIO_PM_TO_SYS(20)
-#else
 #define ISA1200_HAP_EN_GPIO	77
 #define ISA1200_HAP_LEN_GPIO	78
 #define ISA1200_HAP_CLK		PM8038_GPIO_PM_TO_SYS(7)
-#endif
-
-#ifndef MSM8930_PHASE_2
-static struct msm_xo_voter *xo_handle_d1;
-#endif
 
 static int isa1200_power(int on)
 {
-#ifndef MSM8930_PHASE_2
-	int rc = 0;
-
-	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
-
-	rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
-			msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
-	if (rc < 0) {
-		pr_err("%s: failed to %svote for TCXO D1 buffer%d\n",
-				__func__, on ? "" : "de-", rc);
-		goto err_xo_vote;
-	}
-
-	return 0;
-
-err_xo_vote:
-	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
-	return rc;
-#else
 	gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
 
 	return 0;
-#endif
-
 }
 
 static int isa1200_dev_setup(bool enable)
 {
 	int rc = 0;
 
-#ifndef MSM8930_PHASE_2
-	struct pm_gpio hap_gpio_config = {
-		.direction      = PM_GPIO_DIR_OUT,
-		.pull           = PM_GPIO_PULL_NO,
-		.out_strength   = PM_GPIO_STRENGTH_HIGH,
-		.function       = PM_GPIO_FUNC_NORMAL,
-		.inv_int_pol    = 0,
-		.vin_sel        = 2,
-		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
-		.output_value   = 0,
-	};
-
-	if (enable == true) {
-		rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
-		if (rc) {
-			pr_err("%s: pm8921 gpio %d config failed(%d)\n",
-					__func__, PM_HAP_EN_GPIO, rc);
-			return rc;
-		}
-
-		rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config);
-		if (rc) {
-			pr_err("%s: pm8921 gpio %d config failed(%d)\n",
-					__func__, PM_HAP_LEN_GPIO, rc);
-			return rc;
-		}
-
-		rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
-		if (rc) {
-			pr_err("%s: unable to request gpio %d (%d)\n",
-					__func__, HAP_SHIFT_LVL_OE_GPIO, rc);
-			return rc;
-		}
-
-		rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
-		if (rc) {
-			pr_err("%s: Unable to set direction\n", __func__);
-			goto free_gpio;
-		}
-
-		xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200");
-		if (IS_ERR(xo_handle_d1)) {
-			rc = PTR_ERR(xo_handle_d1);
-			pr_err("%s: failed to get the handle for D1(%d)\n",
-							__func__, rc);
-			goto gpio_set_dir;
-		}
-	} else {
-		gpio_free(HAP_SHIFT_LVL_OE_GPIO);
-
-		msm_xo_put(xo_handle_d1);
-	}
-
-	return 0;
-
-gpio_set_dir:
-	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
-free_gpio:
-	gpio_free(HAP_SHIFT_LVL_OE_GPIO);
-	return rc;
-#else
-	struct pm_gpio hap_clk_gpio_config = {
-		.direction      = PM_GPIO_DIR_OUT,
-		.pull           = PM_GPIO_PULL_NO,
-		.out_strength   = PM_GPIO_STRENGTH_HIGH,
-		.function       = PM_GPIO_FUNC_1,
-		.inv_int_pol    = 0,
-		.vin_sel        = PM_GPIO_VIN_S4,
-		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
-		.output_value   = 0,
-	};
-
-	rc = pm8xxx_gpio_config(ISA1200_HAP_CLK, &hap_clk_gpio_config);
+	rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, enable);
 	if (rc) {
-		pr_err("%s: pm8038 gpio %d config failed(%d)\n",
-				__func__, ISA1200_HAP_CLK, rc);
+		pr_err("%s: unable to write aux clock register(%d)\n",
+			__func__, rc);
 		return rc;
 	}
 
@@ -1319,38 +1251,29 @@
 fail_gpio_req:
 	return rc;
 
-#endif
 }
 
 static struct isa1200_regulator isa1200_reg_data[] = {
-#ifndef MSM8930_PHASE_2
-	{
-		.name = "vcc_i2c",
-		.min_uV = ISA_I2C_VTG_MIN_UV,
-		.max_uV = ISA_I2C_VTG_MAX_UV,
-		.load_uA = ISA_I2C_CURR_UA,
-	},
-#else
 	{
 		.name = "vddp",
 		.min_uV = ISA_I2C_VTG_MIN_UV,
 		.max_uV = ISA_I2C_VTG_MAX_UV,
 		.load_uA = ISA_I2C_CURR_UA,
 	},
-#endif
+	{
+		.name = "vcc_i2c",
+		.min_uV = ISA_I2C_VTG_MIN_UV,
+		.max_uV = ISA_I2C_VTG_MAX_UV,
+		.load_uA = ISA_I2C_CURR_UA,
+	},
 };
 
 static struct isa1200_platform_data isa1200_1_pdata = {
 	.name = "vibrator",
 	.dev_setup = isa1200_dev_setup,
 	.power_on = isa1200_power,
-#ifndef MSM8930_PHASE_2
-	.hap_en_gpio = PM_HAP_EN_GPIO,
-	.hap_len_gpio = PM_HAP_LEN_GPIO,
-#else
 	.hap_en_gpio = ISA1200_HAP_EN_GPIO,
 	.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
-#endif
 	.max_timeout = 15000,
 	.mode_ctrl = PWM_GEN_MODE,
 	.pwm_fd = {
@@ -1478,10 +1401,14 @@
 static struct mxt_platform_data mxt_platform_data_8930 = {
 	.config_array		= mxt_config_array,
 	.config_array_size	= ARRAY_SIZE(mxt_config_array),
-	.x_size			= 540,
-	.y_size			= 960,
-	.touch_x_size		= 566,
-	.touch_y_size		= 1067,
+	.panel_minx		= 0,
+	.panel_maxx		= 566,
+	.panel_miny		= 0,
+	.panel_maxy		= 1067,
+	.disp_minx		= 0,
+	.disp_maxx		= 540,
+	.disp_miny		= 0,
+	.disp_maxy		= 960,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 #ifdef MSM8930_PHASE_2
 	.digital_pwr_regulator	= true,
@@ -1566,6 +1493,11 @@
 	.src_clk_rate = 24000000,
 };
 
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi9_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
@@ -1618,10 +1550,11 @@
 };
 
 static struct tsens_platform_data msm_tsens_pdata  = {
-	.slope		= {872, 872, 872, 872, 872},
 	.tsens_factor		= 1000,
-	.hw_type		= MSM_8960,
-	.tsens_num_sensor	= 5,
+	.hw_type		= APQ_8064,
+	.tsens_num_sensor	= 11,
+	.slope = {1176, 1176, 1154, 1176, 1111,
+			1132, 1132, 1199, 1132, 1199, 1132},
 };
 
 #ifdef CONFIG_MSM_FAKE_BATTERY
@@ -1707,6 +1640,7 @@
 	&msm8960_device_qup_spi_gsbi1,
 	&msm8960_device_qup_i2c_gsbi3,
 	&msm8960_device_qup_i2c_gsbi4,
+	&msm8960_device_qup_i2c_gsbi9,
 	&msm8960_device_qup_i2c_gsbi10,
 	&msm8960_device_qup_i2c_gsbi12,
 	&msm_slim_ctrl,
@@ -1734,7 +1668,6 @@
 #endif
 	&android_pmem_audio_device,
 #endif
-	&msm_device_vidc,
 	&msm_device_bam_dmux,
 	&msm_fm_platform_init,
 
@@ -1750,10 +1683,11 @@
 	&msm_device_tz_log,
 
 #ifdef CONFIG_MSM_QDSS
+	&msm_qdss_device,
 	&msm_etb_device,
 	&msm_tpiu_device,
 	&msm_funnel_device,
-	&msm_ptm_device,
+	&msm_etm_device,
 #endif
 	&msm_device_dspcrashd_8960,
 	&msm8960_device_watchdog,
@@ -1763,6 +1697,14 @@
 #ifdef CONFIG_MSM_RTB
 	&msm_rtb_device,
 #endif
+	&msm8930_cpu_idle_device,
+	&msm8930_msm_gov_device,
+	&msm_bus_8930_apps_fabric,
+	&msm_bus_8930_sys_fabric,
+	&msm_bus_8930_mm_fabric,
+	&msm_bus_8930_sys_fpb,
+	&msm_bus_8930_cpss_fpb,
+	&msm8960_device_cache_erp,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -1783,11 +1725,6 @@
 	&msm_cpudai_auxpcm_tx,
 	&msm_cpu_fe,
 	&msm_stub_codec,
-	&msm_kgsl_3d0,
-#ifdef CONFIG_MSM_KGSL_2D
-	&msm_kgsl_2d0,
-	&msm_kgsl_2d1,
-#endif
 #ifdef CONFIG_MSM_GEMINI
 	&msm8960_gemini_device,
 #endif
@@ -1804,11 +1741,6 @@
 	&msm_cpudai_incall_record_rx,
 	&msm_cpudai_incall_record_tx,
 	&msm_pcm_hostless,
-	&msm_bus_apps_fabric,
-	&msm_bus_sys_fabric,
-	&msm_bus_mm_fabric,
-	&msm_bus_sys_fpb,
-	&msm_bus_cpss_fpb,
 };
 
 static void __init msm8930_i2c_init(void)
@@ -1819,6 +1751,9 @@
 	msm8960_device_qup_i2c_gsbi3.dev.platform_data =
 					&msm8960_i2c_qup_gsbi3_pdata;
 
+	msm8960_device_qup_i2c_gsbi9.dev.platform_data =
+					&msm8960_i2c_qup_gsbi9_pdata;
+
 	msm8960_device_qup_i2c_gsbi10.dev.platform_data =
 					&msm8960_i2c_qup_gsbi10_pdata;
 
@@ -1826,17 +1761,6 @@
 					&msm8960_i2c_qup_gsbi12_pdata;
 }
 
-static void __init msm8930_gfx_init(void)
-{
-	uint32_t soc_platform_version = socinfo_get_version();
-	if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
-		struct kgsl_device_platform_data *kgsl_3d0_pdata =
-				msm_kgsl_3d0.dev.platform_data;
-		kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
-		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
-	}
-}
-
 static struct msm_cpuidle_state msm_cstates[] __initdata = {
 	{0, 0, "C0", "WFI",
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
@@ -1903,62 +1827,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,
 	},
 };
 
@@ -2008,24 +1932,6 @@
 	int                    len;
 };
 
-static void __init msm8930_init_hsic(void)
-{
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-	uint32_t version = socinfo_get_version();
-
-	pr_info("%s: version:%d mtp:%d\n", __func__,
-			SOCINFO_VERSION_MAJOR(version),
-			machine_is_msm8930_mtp());
-
-	if ((SOCINFO_VERSION_MAJOR(version) == 1) ||
-			machine_is_msm8930_mtp() ||
-			machine_is_msm8930_fluid())
-		return;
-
-	platform_device_register(&msm_device_hsic_host);
-#endif
-}
-
 #ifdef CONFIG_ISL9519_CHARGER
 static struct isl_platform_data isl_data __initdata = {
 	.valid_n_gpio		= 0,	/* Not required when notify-by-pmic */
@@ -2055,23 +1961,14 @@
 		ARRAY_SIZE(isl_charger_i2c_info),
 	},
 #endif /* CONFIG_ISL9519_CHARGER */
-#ifndef MSM8930_PHASE_2
 	{
-		I2C_LIQUID,
-		MSM_8930_GSBI10_QUP_I2C_BUS_ID,
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_8930_GSBI9_QUP_I2C_BUS_ID,
 		msm_isa1200_board_info,
 		ARRAY_SIZE(msm_isa1200_board_info),
 	},
-#else
 	{
-		I2C_FFA | I2C_FLUID,
-		MSM_8930_GSBI10_QUP_I2C_BUS_ID,
-		msm_isa1200_board_info,
-		ARRAY_SIZE(msm_isa1200_board_info),
-	},
-#endif
-	{
-		I2C_SURF,
+		I2C_SURF | I2C_FFA | I2C_FLUID,
 		MSM_8930_GSBI3_QUP_I2C_BUS_ID,
 		mxt_device_info_8930,
 		ARRAY_SIZE(mxt_device_info_8930),
@@ -2132,9 +2029,8 @@
 	if (msm_xo_init())
 		pr_err("Failed to initialize XO votes\n");
 	platform_device_register(&msm8930_device_rpm_regulator);
-	msm_clock_init(&msm8960_clock_init_data);
+	msm_clock_init(&msm8930_clock_init_data);
 	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
-	msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
 	msm8930_init_gpiomux();
 	msm8960_device_qup_spi_gsbi1.dev.platform_data =
 				&msm8960_qup_spi_gsbi1_pdata;
@@ -2151,13 +2047,14 @@
 	msm8930_init_pmic();
 #endif
 	msm8930_i2c_init();
-	msm8930_gfx_init();
+	msm8930_init_gpu();
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	msm8930_init_buses();
 	platform_add_devices(msm_footswitch_devices,
 		msm_num_footswitch_devices);
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	msm8930_add_vidc_device();
 	/*
 	 * TODO: When physical 8930/PM8038 hardware becomes
 	 * available, remove this block or add the config
@@ -2169,12 +2066,10 @@
 	msm8930_pm8038_gpio_mpp_init();
 #endif
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
-	msm8930_init_hsic();
 	msm8930_init_cam();
 	msm8930_init_mmc();
 	acpuclk_init(&acpuclk_8930_soc_data);
-	if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
-		mxt_init_vkeys_8930();
+	mxt_init_vkeys_8930();
 	register_i2c_devices();
 	msm8930_init_fb();
 	slim_register_board_info(msm_slim_devices,
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index cefaff5..a8fad72 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -109,6 +109,7 @@
 void msm8930_init_cam(void);
 void msm8930_init_fb(void);
 void msm8930_init_pmic(void);
+extern void msm8930_add_vidc_device(void);
 
 /*
  * TODO: When physical 8930/PM8038 hardware becomes
@@ -125,12 +126,14 @@
 void msm8930_allocate_fb_region(void);
 void msm8930_pm8038_gpio_mpp_init(void);
 void msm8930_mdp_writeback(struct memtype_reserve *reserve_table);
+void __init msm8930_init_gpu(void);
 
 #define PLATFORM_IS_CHARM25() \
 	(machine_is_msm8930_cdp() && \
 		(socinfo_get_platform_subtype() == 1) \
 	)
 
-#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
 #define MSM_8930_GSBI3_QUP_I2C_BUS_ID 3
+#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
+#define MSM_8930_GSBI9_QUP_I2C_BUS_ID 0
 #define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 87cb105..c2a378f 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -420,7 +420,6 @@
 };
 
 static struct camera_vreg_t msm_8960_back_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -428,7 +427,6 @@
 };
 
 static struct camera_vreg_t msm_8960_front_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
@@ -498,11 +496,17 @@
 #endif
 };
 
+static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
 	.mount_angle	= 90,
 	.cam_vreg = msm_8960_back_cam_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8960_back_cam_vreg),
 	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.csi_lane_params = &imx074_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
@@ -513,11 +517,11 @@
 	.sensor_platform_info = &sensor_board_info_imx074,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &imx074_actuator_info
 };
 
 static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -528,31 +532,44 @@
 	.flash_type = MSM_CAMERA_FLASH_NONE
 };
 
+static struct msm_camera_csi_lane_params mt9m114_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x1,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
 	.mount_angle = 90,
 	.cam_vreg = msm_8960_mt9m114_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8960_mt9m114_vreg),
-	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.gpio_conf = &msm_8960_front_cam_gpio_conf,
+	.csi_lane_params = &mt9m114_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
 	.sensor_name = "mt9m114",
-	.pdata = &msm_camera_csi_device_data[0],
+	.pdata = &msm_camera_csi_device_data[1],
 	.flash_data = &flash_mt9m114,
 	.sensor_platform_info = &sensor_board_info_mt9m114,
 	.csi_if = 1,
-	.camera_type = BACK_CAMERA_2D,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
 };
 
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
 
+static struct msm_camera_csi_lane_params ov2720_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x3,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
 	.mount_angle	= 0,
 	.cam_vreg = msm_8960_front_cam_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8960_front_cam_vreg),
 	.gpio_conf = &msm_8960_front_cam_gpio_conf,
+	.csi_lane_params = &ov2720_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
@@ -562,10 +579,10 @@
 	.sensor_platform_info = &sensor_board_info_ov2720,
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vio", REG_VS, 0, 0, 0},
@@ -576,11 +593,17 @@
 	.flash_type = MSM_CAMERA_FLASH_NONE,
 };
 
+static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
 static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
 	.mount_angle  = 0,
 	.cam_vreg = msm_8960_s5k3l1yx_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8960_s5k3l1yx_vreg),
 	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.csi_lane_params = &s5k3l1yx_csi_lane_params,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
@@ -590,6 +613,41 @@
 	.sensor_platform_info = &sensor_board_info_s5k3l1yx,
 	.csi_if               = 1,
 	.camera_type          = BACK_CAMERA_2D,
+	.sensor_type          = BAYER_SENSOR,
+};
+
+static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct camera_vreg_t msm_8960_imx091_vreg[] = {
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+};
+
+static struct msm_camera_sensor_flash_data flash_imx091 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8960_imx091_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_imx091_vreg),
+	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.csi_lane_params = &imx091_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
+	.sensor_name	= "imx091",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx091,
+	.sensor_platform_info = &sensor_board_info_imx091,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 static struct pm8xxx_mpp_config_data privacy_light_on_config = {
@@ -679,6 +737,10 @@
 	I2C_BOARD_INFO("sc628a", 0x6E),
 	},
 #endif
+	{
+	I2C_BOARD_INFO("imx091", 0x34),
+	.platform_data = &msm_camera_sensor_imx091_data,
+	},
 };
 
 struct msm_camera_board_info msm8960_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 9a98058..b715346 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -30,45 +30,45 @@
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MSM_FB_PRIM_BUF_SIZE \
-		(roundup((1920 * 1200 * 4), 4096) * 3) /* 4 bpp x 3 pages */
+		(roundup((roundup(1920, 32) * roundup(1200, 32) * 4), 4096) * 3)
+			/* 4 bpp x 3 pages */
 #else
 #define MSM_FB_PRIM_BUF_SIZE \
-		(roundup((1920 * 1200 * 4), 4096) * 2) /* 4 bpp x 2 pages */
+		(roundup((roundup(1920, 32) * roundup(1200, 32) * 4), 4096) * 2)
+			/* 4 bpp x 2 pages */
 #endif
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 #define MSM_FB_EXT_BUF_SIZE \
-		(roundup((1920 * 1088 * 2), 4096) * 1) /* 2 bpp x 1 page */
+		(roundup((roundup(1920, 32) * roundup(1080, 32) * 2), 4096) * 1)
+			/* 2 bpp x 1 page */
 #elif defined(CONFIG_FB_MSM_TVOUT)
 #define MSM_FB_EXT_BUF_SIZE \
-		(roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
+		(roundup((roundup(720, 32) * roundup(576, 32) * 2), 4096) * 2)
+			/* 2 bpp x 2 pages */
 #else
 #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)
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE \
+		roundup((roundup(1920, 32) * roundup(1200, 32) * 3 * 2), 4096)
 #else
 #define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
 #endif  /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
 
 #ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
-#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE \
+		roundup((roundup(1920, 32) * roundup(1080, 32) * 3 * 2), 4096)
 #else
 #define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
 #endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
 
 #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 +77,22 @@
 #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
+static unsigned char hdmi_is_primary = 1;
+#else
+static unsigned char hdmi_is_primary;
+#endif
+
+unsigned char msm8960_hdmi_as_primary_selected(void)
+{
+	return hdmi_is_primary;
+}
+
 static struct resource msm_fb_resources[] = {
 	{
 		.flags = IORESOURCE_DMA,
@@ -139,13 +152,26 @@
 			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
 	}
 
 	if (!strncmp(name, HDMI_PANEL_NAME,
 			strnlen(HDMI_PANEL_NAME,
-				PANEL_NAME_MAX_LEN)))
+				PANEL_NAME_MAX_LEN))) {
+		if (hdmi_is_primary)
+			set_mdp_clocks_for_wuxga();
 		return 0;
+	}
 
 	if (!strncmp(name, TVOUT_PANEL_NAME,
 			strnlen(TVOUT_PANEL_NAME,
@@ -168,6 +194,50 @@
 	.dev.platform_data = &msm_fb_pdata,
 };
 
+static void mipi_dsi_panel_pwm_cfg(void)
+{
+	int rc;
+	static int mipi_dsi_panel_gpio_configured;
+	static struct pm_gpio pwm_enable = {
+		.direction        = PM_GPIO_DIR_OUT,
+		.output_buffer    = PM_GPIO_OUT_BUF_CMOS,
+		.output_value     = 1,
+		.pull             = PM_GPIO_PULL_NO,
+		.vin_sel          = PM_GPIO_VIN_VPH,
+		.out_strength     = PM_GPIO_STRENGTH_HIGH,
+		.function         = PM_GPIO_FUNC_NORMAL,
+		.inv_int_pol      = 0,
+		.disable_pin      = 0,
+	};
+	static struct pm_gpio pwm_mode = {
+		.direction        = PM_GPIO_DIR_OUT,
+		.output_buffer    = PM_GPIO_OUT_BUF_CMOS,
+		.output_value     = 0,
+		.pull             = PM_GPIO_PULL_NO,
+		.vin_sel          = PM_GPIO_VIN_S4,
+		.out_strength     = PM_GPIO_STRENGTH_HIGH,
+		.function         = PM_GPIO_FUNC_2,
+		.inv_int_pol      = 0,
+		.disable_pin      = 0,
+	};
+
+	if (mipi_dsi_panel_gpio_configured == 0) {
+		/* pm8xxx: gpio-21, Backlight Enable */
+		rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(21),
+					&pwm_enable);
+		if (rc != 0)
+			pr_err("%s: pwm_enabled failed\n", __func__);
+
+		/* pm8xxx: gpio-24, Bl: Off, PWM mode */
+		rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(24),
+					&pwm_mode);
+		if (rc != 0)
+			pr_err("%s: pwm_mode failed\n", __func__);
+
+		mipi_dsi_panel_gpio_configured++;
+	}
+}
+
 static bool dsi_power_on;
 
 /**
@@ -183,6 +253,7 @@
 	static int gpio21, gpio24, gpio43;
 	int rc;
 
+	mipi_dsi_panel_pwm_cfg();
 	pr_debug("%s: on=%d\n", __func__, on);
 
 	gpio21 = PM8921_GPIO_PM_TO_SYS(21); /* disp power enable_n */
@@ -429,80 +500,6 @@
 };
 
 #ifdef CONFIG_MSM_BUS_SCALING
-
-static struct msm_bus_vectors rotator_init_vectors[] = {
-	{
-		.src = MSM_BUS_MASTER_ROTATOR,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 0,
-		.ib = 0,
-	},
-};
-
-static struct msm_bus_vectors rotator_ui_vectors[] = {
-	{
-		.src = MSM_BUS_MASTER_ROTATOR,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = (1024 * 600 * 4 * 2 * 60),
-		.ib  = (1024 * 600 * 4 * 2 * 60 * 1.5),
-	},
-};
-
-static struct msm_bus_vectors rotator_vga_vectors[] = {
-	{
-		.src = MSM_BUS_MASTER_ROTATOR,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = (640 * 480 * 2 * 2 * 30),
-		.ib  = (640 * 480 * 2 * 2 * 30 * 1.5),
-	},
-};
-static struct msm_bus_vectors rotator_720p_vectors[] = {
-	{
-		.src = MSM_BUS_MASTER_ROTATOR,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = (1280 * 736 * 2 * 2 * 30),
-		.ib  = (1280 * 736 * 2 * 2 * 30 * 1.5),
-	},
-};
-
-static struct msm_bus_vectors rotator_1080p_vectors[] = {
-	{
-		.src = MSM_BUS_MASTER_ROTATOR,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = (1920 * 1088 * 2 * 2 * 30),
-		.ib  = (1920 * 1088 * 2 * 2 * 30 * 1.5),
-	},
-};
-
-static struct msm_bus_paths rotator_bus_scale_usecases[] = {
-	{
-		ARRAY_SIZE(rotator_init_vectors),
-		rotator_init_vectors,
-	},
-	{
-		ARRAY_SIZE(rotator_ui_vectors),
-		rotator_ui_vectors,
-	},
-	{
-		ARRAY_SIZE(rotator_vga_vectors),
-		rotator_vga_vectors,
-	},
-	{
-		ARRAY_SIZE(rotator_720p_vectors),
-		rotator_720p_vectors,
-	},
-	{
-		ARRAY_SIZE(rotator_1080p_vectors),
-		rotator_1080p_vectors,
-	},
-};
-
-struct msm_bus_scale_pdata rotator_bus_scale_pdata = {
-	rotator_bus_scale_usecases,
-	ARRAY_SIZE(rotator_bus_scale_usecases),
-	.name = "rotator",
-};
-
 static struct msm_bus_vectors mdp_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -512,43 +509,6 @@
 	},
 };
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
-	/* If HDMI is used as primary */
-	{
-		.src = MSM_BUS_MASTER_MDP_PORT0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 2000000000,
-		.ib = 2000000000,
-	},
-};
-static struct msm_bus_paths mdp_bus_scale_usecases[] = {
-	{
-		ARRAY_SIZE(mdp_init_vectors),
-		mdp_init_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-};
-#else
 static struct msm_bus_vectors mdp_ui_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -614,7 +574,6 @@
 		mdp_1080p_vectors,
 	},
 };
-#endif
 
 static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
 	mdp_bus_scale_usecases,
@@ -624,29 +583,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
@@ -654,30 +600,13 @@
 #endif
 	.mdp_rev = MDP_REV_42,
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	.mem_hid = ION_CP_MM_HEAP_ID,
+	.mem_hid = BIT(ION_CP_MM_HEAP_ID),
 #else
 	.mem_hid = MEMTYPE_EBI1,
 #endif
+	.cont_splash_enabled = 0x01,
 };
 
-/**
- * Set MDP clocks to high frequency to avoid DSI underflow
- * when using high resolution 1200x1920 WUXGA panels
- */
-static void set_mdp_clocks_for_wuxga(void)
-{
-	int i;
-
-	mdp_ui_vectors[0].ab = 2000000000;
-	mdp_ui_vectors[0].ib = 2000000000;
-
-	mdp_pdata.mdp_core_clk_rate = 200000000;
-
-	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
-		mdp_core_clk_rate_table[i] = 200000000;
-
-}
-
 void __init msm8960_mdp_writeback(struct memtype_reserve* reserve_table)
 {
 	mdp_pdata.ov0_wb_size = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
@@ -705,6 +634,7 @@
 
 static struct mipi_dsi_panel_platform_data toshiba_pdata = {
 	.gpio = toshiba_gpio,
+	.dsi_pwm_cfg = mipi_dsi_panel_pwm_cfg,
 };
 
 static struct platform_device mipi_dsi_toshiba_panel_device = {
@@ -762,6 +692,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 +762,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 +770,6 @@
 		.ib = 707616000 * 2,
 	},
 };
-#endif
 
 static struct msm_bus_paths dtv_bus_scale_usecases[] = {
 	{
@@ -879,9 +803,16 @@
 	if (on == prev_on)
 		return 0;
 
-	if (!reg_8921_hdmi_mvs)
+	if (!reg_8921_hdmi_mvs) {
 		reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
-			"hdmi_mvs");
+					"hdmi_mvs");
+		if (IS_ERR(reg_8921_hdmi_mvs)) {
+			pr_err("'%s' regulator not found, rc=%ld\n",
+				"hdmi_mvs", IS_ERR(reg_8921_hdmi_mvs));
+			reg_8921_hdmi_mvs = NULL;
+			return -ENODEV;
+		}
+	}
 
 	if (on) {
 		rc = regulator_enable(reg_8921_hdmi_mvs);
@@ -1061,6 +992,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);
@@ -1095,3 +1027,62 @@
 	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
 			size, addr, __pa(addr));
 }
+
+/**
+ * Set MDP clocks to high frequency to avoid DSI underflow
+ * when using high resolution 1200x1920 WUXGA panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+	int i;
+
+	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;
+
+	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+		mdp_core_clk_rate_table[i] = 200000000;
+
+	if (hdmi_is_primary) {
+		dtv_bus_def_vectors[0].ab = 2000000000;
+		dtv_bus_def_vectors[0].ib = 2000000000;
+	}
+}
+
+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;
+			set_mdp_clocks_for_wuxga();
+		}
+		if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+				MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN))) {
+			set_mdp_clocks_for_wuxga();
+		}
+	}
+	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-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 744709c..3bf1297 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -88,6 +88,12 @@
 			PM_GPIO_STRENGTH_HIGH, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
+#define PM8XXX_GPIO_OUTPUT_STRENGTH(_gpio, _val, _out_strength) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			_out_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
 /* Initial PM8921 GPIO configurations */
 static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
 	PM8XXX_GPIO_OUTPUT_VIN(6, 1, PM_GPIO_VIN_VPH),	 /* MHL power EN_N */
@@ -95,15 +101,15 @@
 	PM8XXX_GPIO_INPUT(16,	    PM_GPIO_PULL_UP_30), /* SD_CARD_WP */
     /* External regulator shared by display and touchscreen on LiQUID */
 	PM8XXX_GPIO_OUTPUT(17,	    0),			 /* DISP 3.3 V Boost */
-	PM8XXX_GPIO_OUTPUT(18,	1),	/* TABLA SPKR_LEFT_EN */
-	PM8XXX_GPIO_OUTPUT(19,	1),	/* TABLA SPKR_RIGHT_EN */
-	PM8XXX_GPIO_OUTPUT_VIN(21, 1, PM_GPIO_VIN_VPH),	 /* Backlight Enable */
+	PM8XXX_GPIO_OUTPUT(18,	0),	/* TABLA SPKR_LEFT_EN=off */
+	PM8XXX_GPIO_OUTPUT(19,	0),	/* TABLA SPKR_RIGHT_EN=off */
 	PM8XXX_GPIO_DISABLE(22),			 /* Disable NFC */
-	PM8XXX_GPIO_OUTPUT_FUNC(24, 0, PM_GPIO_FUNC_2),	 /* Bl: Off, PWM mode */
 	PM8XXX_GPIO_OUTPUT_FUNC(25, 0, PM_GPIO_FUNC_2),	 /* TN_CLK */
 	PM8XXX_GPIO_INPUT(26,	    PM_GPIO_PULL_UP_30), /* SD_CARD_DET_N */
-	PM8XXX_GPIO_OUTPUT(43,	    PM_GPIO_PULL_UP_30), /* DISP_RESET_N */
+	PM8XXX_GPIO_OUTPUT(43, 1),                       /* DISP_RESET_N */
 	PM8XXX_GPIO_OUTPUT(42, 0),                      /* USB 5V reg enable */
+	/* TABLA CODEC RESET */
+	PM8XXX_GPIO_OUTPUT_STRENGTH(34, 1, PM_GPIO_STRENGTH_MED)
 };
 
 /* Initial PM8921 MPP configurations */
@@ -424,6 +430,7 @@
 	.warm_bat_voltage	= 4100,
 	.thermal_mitigation	= pm8921_therm_mitigation,
 	.thermal_levels		= ARRAY_SIZE(pm8921_therm_mitigation),
+	.rconn_mohm		= 18,
 };
 
 static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
@@ -431,6 +438,7 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -555,6 +563,17 @@
 	.r_sense		= 10,
 };
 
+/**
+ * PM8XXX_PWM_DTEST_CHANNEL_NONE shall be used when no LPG
+ * channel should be in DTEST mode.
+ */
+
+#define PM8XXX_PWM_DTEST_CHANNEL_NONE   (-1)
+
+static struct pm8xxx_pwm_platform_data pm8xxx_pwm_pdata = {
+	.dtest_channel	= PM8XXX_PWM_DTEST_CHANNEL_NONE,
+};
+
 static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
 	.irq_pdata		= &pm8xxx_irq_pdata,
 	.gpio_pdata		= &pm8xxx_gpio_pdata,
@@ -569,6 +588,7 @@
 	.adc_pdata		= &pm8xxx_adc_pdata,
 	.leds_pdata		= &pm8xxx_leds_pdata,
 	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
+	.pwm_pdata		= &pm8xxx_pwm_pdata,
 };
 
 static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
@@ -593,5 +613,8 @@
 	if (machine_is_msm8960_liquid()) {
 		pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
 		pm8921_platform_data.leds_pdata = &pm8xxx_leds_pdata_liquid;
+		pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
+	} else if (machine_is_msm8960_mtp()) {
+		pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 0f05af5..23e3e69 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -30,10 +30,9 @@
 VREG_CONSUMERS(L2) = {
 	REGULATOR_SUPPLY("8921_l2",		NULL),
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-0048"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-0020"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8921_l3",		NULL),
@@ -76,6 +75,7 @@
 	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
 	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vana",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0034"),
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("8921_l12",		NULL),
@@ -83,6 +83,7 @@
 	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
 	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vdig",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0034"),
 };
 VREG_CONSUMERS(L14) = {
 	REGULATOR_SUPPLY("8921_l14",		NULL),
@@ -97,6 +98,7 @@
 	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
 	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vaf",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0034"),
 };
 VREG_CONSUMERS(L17) = {
 	REGULATOR_SUPPLY("8921_l17",		NULL),
@@ -212,6 +214,7 @@
 	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
 	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vio",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0034"),
 };
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
@@ -222,7 +225,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),
@@ -246,12 +248,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 = { \
@@ -273,8 +275,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, \
@@ -283,7 +283,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) \
@@ -291,7 +291,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) \
@@ -299,32 +299,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, \
@@ -376,8 +376,8 @@
 
 #define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
 		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
-		 _force_mode, _power_mode, _state, _sleep_selectable, \
-		 _always_on, _supply_regulator, _system_uA) \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -403,6 +403,7 @@
 		.freq			= RPM_VREG_FREQ_##_freq, \
 		.pin_fn			= _pin_fn, \
 		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
 		.power_mode		= _power_mode, \
 		.state			= _state, \
 		.sleep_selectable	= _sleep_selectable, \
@@ -416,24 +417,28 @@
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
 		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, _system_uA)
 
 #define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
-		 _supply_regulator, _system_uA, _freq) \
+		 _supply_regulator, _system_uA, _freq, _force_mode, \
+		 _sleep_set_force_mode) \
 	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
-		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
-		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
-		 _supply_regulator, _system_uA)
+		 RPM_VREG_FORCE_MODE_8960_##_force_mode, \
+		 RPM_VREG_FORCE_MODE_8960_##_sleep_set_force_mode, \
+		 RPM_VREG_POWER_MODE_8960_PWM, RPM_VREG_STATE_OFF, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA)
 
 #define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
 	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
 		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
@@ -443,6 +448,7 @@
 	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
 		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
 		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
 		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
@@ -473,7 +479,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 */
@@ -499,24 +505,20 @@
 	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
 msm_rpm_regulator_init_data[] __devinitdata = {
-	/*	 ID    a_on pd ss min_uV   max_uV  supply sys_uA freq */
-	RPM_SMPS(S1,	 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20),
-	RPM_SMPS(S2,	 0, 1, 0, 1300000, 1300000, NULL, 0,	  1p60),
-	RPM_SMPS(S3,	 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80),
-	RPM_SMPS(S4,	 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60),
-	RPM_SMPS(S7,	 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20),
-	RPM_SMPS(S8,	 1, 1, 1, 2100000, 2100000, NULL, 100000, 1p60),
+	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
+	RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
+	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, NONE, NONE),
+	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, AUTO),
+	RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S8, 1, 1, 1, 2100000, 2100000, NULL, 100000, 1p60, NONE, NONE),
 
 	/*	ID     a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
 	RPM_LDO(L1,	 1, 1, 0, 1050000, 1050000, "8921_s4", 0, 10000),
@@ -527,7 +529,7 @@
 	RPM_LDO(L6,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
 	RPM_LDO(L7,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L8,	 0, 1, 0, 2800000, 3000000, NULL,      0, 0),
-	RPM_LDO(L9,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+	RPM_LDO(L9,	 0, 1, 0, 3000000, 3000000, NULL,      0, 0),
 	RPM_LDO(L10,	 0, 1, 0, 3000000, 3000000, NULL,      0, 0),
 	RPM_LDO(L11,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
 	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index b99ce8a..257b27f 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -70,9 +70,8 @@
 #include <mach/restart.h>
 
 #ifdef CONFIG_WCD9310_CODEC
-#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
 #endif
 
 #include <linux/ion.h>
@@ -80,6 +79,8 @@
 #include <mach/mdm2.h>
 #include <mach/mdm-peripheral.h>
 #include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
+#include <mach/scm.h>
 
 #include <linux/fmem.h>
 
@@ -131,25 +132,31 @@
 #endif
 
 #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_AUDIO_SIZE        0x4CF000
 #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
-#define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#ifdef CONFIG_MSM_IOMMU
+#define MSM_ION_MM_SIZE            0x3800000
+#define MSM_ION_SF_SIZE            0x0
+#define MSM_ION_HEAP_NUM	7
+#else
+#define MSM_ION_MM_SIZE            MSM_PMEM_ADSP_SIZE
+#define MSM_ION_SF_SIZE            MSM_PMEM_SIZE
+#define MSM_ION_HEAP_NUM	8
+#endif
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
-#define MSM_ION_QSECOM_SIZE	0x300000 /* (3MB) */
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #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
@@ -221,7 +228,6 @@
 	.id = 2,
 	.dev = { .platform_data = &android_pmem_adsp_pdata },
 };
-#endif
 
 static struct android_pmem_platform_data android_pmem_audio_pdata = {
 	.name = "pmem_audio",
@@ -235,7 +241,8 @@
 	.id = 4,
 	.dev = { .platform_data = &android_pmem_audio_pdata },
 };
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
 
 struct fmem_platform_data fmem_pdata = {
 };
@@ -309,18 +316,27 @@
 #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 (msm8960_hdmi_as_primary_selected())
+			pmem_size = MSM_HDMI_PRIM_PMEM_SIZE;
+	}
+
 	android_pmem_pdata.size = pmem_size;
-#endif
 	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
 }
 
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 static void __init reserve_memory_for(struct android_pmem_platform_data *p)
 {
 	msm8960_reserve_table[p->memory_type].size += p->size;
 }
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
 
 static void __init reserve_pmem_memory(void)
 {
@@ -328,8 +344,8 @@
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	reserve_memory_for(&android_pmem_adsp_pdata);
 	reserve_memory_for(&android_pmem_pdata);
-#endif
 	reserve_memory_for(&android_pmem_audio_pdata);
+#endif
 	msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
 #endif
 }
@@ -414,6 +430,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *) &cp_mfc_ion_pdata,
 		},
+#ifndef CONFIG_MSM_IOMMU
 		{
 			.id	= ION_SF_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -422,6 +439,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *) &co_ion_pdata,
 		},
+#endif
 		{
 			.id	= ION_IOMMU_HEAP_ID,
 			.type	= ION_HEAP_TYPE_IOMMU,
@@ -464,14 +482,23 @@
 {
 	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 (msm8960_hdmi_as_primary_selected())
+			msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
+
+		if (machine_is_msm8960_liquid() ||
+			msm8960_hdmi_as_primary_selected()) {
+			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;
+				}
 			}
 		}
 	}
@@ -570,6 +597,52 @@
 	msm8960_mdp_writeback(msm8960_reserve_table);
 }
 
+#if defined(CONFIG_MSM_CACHE_DUMP)
+static struct msm_cache_dump_platform_data msm_cache_dump_pdata = {
+	.l2_size = L2_BUFFER_SIZE,
+};
+
+static struct platform_device msm_cache_dump_device = {
+	.name           = "msm_cache_dump",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm_cache_dump_pdata,
+	},
+};
+
+#endif
+
+static void reserve_cache_dump_memory(void)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP
+	unsigned int spare;
+	unsigned int l1_size;
+	unsigned int l2_size;
+	unsigned int total;
+	int ret;
+
+	ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_GET_SIZE_COMMAND_ID, &spare,
+		sizeof(spare), &l1_size, sizeof(l1_size));
+
+	if (ret)
+		/* Fall back to something reasonable here */
+		l1_size = L1_BUFFER_SIZE;
+
+	ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_GET_SIZE_COMMAND_ID, &spare,
+		sizeof(spare), &l2_size, sizeof(l2_size));
+
+	if (ret)
+		/* Fall back to something reasonable here */
+		l2_size = L2_BUFFER_SIZE;
+
+	total = l1_size + l2_size;
+
+	msm8960_reserve_table[MEMTYPE_EBI1].size += total;
+	msm_cache_dump_pdata.l1_size = l1_size;
+	msm_cache_dump_pdata.l2_size = l2_size;
+#endif
+}
+
 static void __init msm8960_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
@@ -577,6 +650,7 @@
 	reserve_ion_memory();
 	reserve_mdp_memory();
 	reserve_rtb_memory();
+	reserve_cache_dump_memory();
 }
 
 static struct reserve_info msm8960_reserve_info __initdata = {
@@ -608,23 +682,30 @@
 
 	if (high - low <= bank_size)
 		return;
+
+	msm8960_reserve_info.bank_size = bank_size;
+#ifdef CONFIG_ENABLE_DMM
 	msm8960_reserve_info.low_unstable_address = mb->start -
 					MIN_MEMORY_BLOCK_SIZE + mb->size;
 	msm8960_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
-
-	msm8960_reserve_info.bank_size = bank_size;
 	pr_info("low unstable address %lx max size %lx bank size %lx\n",
 		msm8960_reserve_info.low_unstable_address,
 		msm8960_reserve_info.max_unstable_size,
 		msm8960_reserve_info.bank_size);
+#else
+	msm8960_reserve_info.low_unstable_address = 0;
+	msm8960_reserve_info.max_unstable_size = 0;
+#endif
 }
 
 static void __init place_movable_zone(void)
 {
+#ifdef CONFIG_ENABLE_DMM
 	movable_reserved_start = msm8960_reserve_info.low_unstable_address;
 	movable_reserved_size = msm8960_reserve_info.max_unstable_size;
 	pr_info("movable zone start %lx size %lx\n",
 		movable_reserved_start, movable_reserved_size);
+#endif
 }
 
 static void __init msm8960_early_memory(void)
@@ -634,8 +715,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);
 }
@@ -664,14 +764,14 @@
  * does not need to be as high as 2.85V. It is choosen for
  * microphone sensitivity purpose.
  */
-static struct tabla_pdata tabla_platform_data = {
+static struct wcd9xxx_pdata tabla_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(62),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -682,7 +782,45 @@
 		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
 		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
 		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
-	}
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
 };
 
 static struct slim_device msm_slim_tabla = {
@@ -693,14 +831,14 @@
 	},
 };
 
-static struct tabla_pdata tabla20_platform_data = {
+static struct wcd9xxx_pdata tabla20_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(62),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -711,7 +849,45 @@
 		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
 		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
 		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
-	}
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
 };
 
 static struct slim_device msm_slim_tabla20 = {
@@ -1238,7 +1414,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1253,7 +1429,7 @@
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
 		.vctl_timeout_us = 50,
@@ -1302,7 +1478,7 @@
 	[0] = {
 		.reg_base_addr = MSM_SAW_L2_BASE,
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
-		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020202,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
 		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
 		.modes = msm_spm_l2_seq_list,
@@ -1716,6 +1892,63 @@
 	255,
 };
 
+/* configuration data for mxt1386e on 3D SKU using V2.1 firmware */
+static const u8 mxt1386e_config_data_3d[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	13, 1, 0, 23, 2, 12, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T7 Object */
+	100, 10, 50,
+	/* T8 Object */
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
+	/* T9 Object */
+	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	0, 5, 5, 0, 10, 30, 10, 10, 175, 4,
+	127, 7, 26, 21, 17, 19, 143, 35, 207, 40,
+	20, 5, 54, 49, 0,
+	/* T18 Object */
+	0, 0,
+	/* T24 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T25 Object */
+	0, 0, 72, 113, 168, 97,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T43 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+	/* T46 Object */
+	68, 0, 16, 16, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
+	/* T48 Object */
+	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+	32, 50, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 30,
+	52, 10, 5, 0, 33, 0, 1, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T56 Object */
+	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, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+};
+
 #define MXT_TS_GPIO_IRQ			11
 #define MXT_TS_LDO_EN_GPIO		50
 #define MXT_TS_RESET_GPIO		52
@@ -1744,7 +1977,7 @@
 	gpio_free(MXT_TS_LDO_EN_GPIO);
 }
 
-static struct mxt_config_info mxt_config_array[] = {
+static struct mxt_config_info mxt_config_array_2d[] = {
 	{
 		.config		= mxt1386_config_data,
 		.config_length	= ARRAY_SIZE(mxt1386_config_data),
@@ -1752,6 +1985,7 @@
 		.variant_id	= 0x0,
 		.version	= 0x10,
 		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386,
 	},
 	{
 		.config		= mxt1386e_config_data_v1_0,
@@ -1760,6 +1994,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,
@@ -1768,14 +2004,49 @@
 		.variant_id	= 0x7,
 		.version	= 0x21,
 		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
 	},
 };
 
-static struct mxt_platform_data mxt_platform_data = {
-	.config_array		= mxt_config_array,
-	.config_array_size	= ARRAY_SIZE(mxt_config_array),
-	.x_size			= 1365,
-	.y_size			= 767,
+static struct mxt_platform_data mxt_platform_data_2d = {
+	.config_array		= mxt_config_array_2d,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array_2d),
+	.panel_minx		= 0,
+	.panel_maxx		= 1365,
+	.panel_miny		= 0,
+	.panel_maxy		= 767,
+	.disp_minx		= 0,
+	.disp_maxx		= 1365,
+	.disp_miny		= 0,
+	.disp_maxy		= 767,
+	.irqflags		= IRQF_TRIGGER_FALLING,
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
+};
+
+static struct mxt_config_info mxt_config_array_3d[] = {
+	{
+		.config		= mxt1386e_config_data_3d,
+		.config_length	= ARRAY_SIZE(mxt1386e_config_data_3d),
+		.family_id	= 0xA0,
+		.variant_id	= 0x7,
+		.version	= 0x21,
+		.build		= 0xAA,
+	},
+};
+
+static struct mxt_platform_data mxt_platform_data_3d = {
+	.config_array		= mxt_config_array_3d,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array_3d),
+	.panel_minx		= 0,
+	.panel_maxx		= 1919,
+	.panel_miny		= 0,
+	.panel_maxy		= 1199,
+	.disp_minx		= 0,
+	.disp_maxx		= 1919,
+	.disp_miny		= 0,
+	.disp_maxy		= 1199,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.i2c_pull_up		= true,
 	.reset_gpio		= MXT_TS_RESET_GPIO,
@@ -1785,7 +2056,6 @@
 static struct i2c_board_info mxt_device_info[] __initdata = {
 	{
 		I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
-		.platform_data = &mxt_platform_data,
 		.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
 	},
 };
@@ -1927,8 +2197,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,
@@ -1959,13 +2229,21 @@
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	&android_pmem_device,
 	&android_pmem_adsp_device,
-#endif
 	&android_pmem_audio_device,
 #endif
+#endif
 	&msm_device_vidc,
 	&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
@@ -1977,16 +2255,23 @@
 	&msm8960_rpm_stat_device,
 	&msm_device_tz_log,
 #ifdef CONFIG_MSM_QDSS
+	&msm_qdss_device,
 	&msm_etb_device,
 	&msm_tpiu_device,
 	&msm_funnel_device,
-	&msm_ptm_device,
+	&msm_etm_device,
 #endif
 	&msm_device_dspcrashd_8960,
 	&msm8960_device_watchdog,
 #ifdef CONFIG_MSM_RTB
 	&msm_rtb_device,
 #endif
+	&msm8960_cpu_idle_device,
+	&msm8960_msm_gov_device,
+	&msm8960_device_cache_erp,
+#ifdef CONFIG_MSM_CACHE_DUMP
+	&msm_cache_dump_device,
+#endif
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -2049,6 +2334,7 @@
 	&msm_8960_q6_mss_sw,
 	&msm_8960_riva,
 	&msm_pil_tzapps,
+	&msm_pil_dsps,
 	&msm8960_device_otg,
 	&msm8960_device_gadget_peripheral,
 	&msm_device_hsusb_host,
@@ -2188,62 +2474,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,
 	},
 };
 
@@ -2463,6 +2749,15 @@
 	else
 		pr_err("unmatched machine ID in register_i2c_devices\n");
 
+	if (machine_is_msm8960_liquid()) {
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_platform_version()) == 3)
+			mxt_device_info[0].platform_data =
+						&mxt_platform_data_3d;
+		else
+			mxt_device_info[0].platform_data =
+						&mxt_platform_data_2d;
+	}
+
 	/* Run the array and install devices as appropriate */
 	for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
 		if (msm8960_i2c_devices[i].machs & mach_mask)
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 20af7b8..dea957c 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;
+
 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);
+unsigned char msm8960_hdmi_as_primary_selected(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-9615-display.c b/arch/arm/mach-msm/board-9615-display.c
new file mode 100644
index 0000000..74bc984
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-display.c
@@ -0,0 +1,169 @@
+/* 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/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <linux/ion.h>
+#include <asm/mach-types.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/ion.h>
+#include <mach/msm_bus_board.h>
+
+#include "devices.h"
+#include "board-9615.h"
+
+/* prim = 240 x 320 x 4(bpp) x 2(pages) */
+#define MSM_FB_PRIM_BUF_SIZE roundup(240 * 320 * 4 * 2, 0x10000)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
+
+#define GPIO_PIN_EBI2_LCD_A_D	21
+#define GPIO_PIN_EBI2_LCD_CS	22
+#define GPIO_PIN_EBI2_LCD_RS	24
+
+
+#ifdef CONFIG_FB_MSM
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+	return 0;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+	.detect_client = msm_fb_detect_panel,
+};
+
+static struct platform_device msm_fb_device = {
+	.name              = "msm_fb",
+	.id                = 0,
+	.num_resources     = ARRAY_SIZE(msm_fb_resources),
+	.resource          = msm_fb_resources,
+	.dev.platform_data = &msm_fb_pdata,
+};
+
+void __init mdm9615_allocate_fb_region(void)
+{
+	void *addr;
+	unsigned long size;
+
+	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;
+	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
+			size, addr, __pa(addr));
+}
+
+
+static bool ebi2_power_init;
+static int ebi2_panel_power(int on)
+{
+	static struct regulator *panel_power;
+	int rc;
+
+	pr_debug("%s: on=%d\n", __func__, on);
+
+	if (!ebi2_power_init) {
+		panel_power = regulator_get(&msm_ebi2_lcdc_device.dev,
+				"VDDI2");
+		if (IS_ERR_OR_NULL(panel_power)) {
+			pr_err("could not get L14, rc = %ld\n",
+				PTR_ERR(panel_power));
+			return -ENODEV;
+		}
+
+		rc = regulator_set_voltage(panel_power, 2800000, 3800000);
+		if (rc) {
+			pr_err("set_voltage L14 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+
+		ebi2_power_init = true;
+	}
+
+	if (on) {
+		rc = regulator_enable(panel_power);
+		if (rc) {
+			pr_err("enable L14 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = gpio_request(GPIO_PIN_EBI2_LCD_A_D, "disp_a_d");
+		if (rc) {
+			pr_err("request gpio EBI2_LCD_A_D failed, rc=%d\n", rc);
+			goto error1;
+		}
+		rc = gpio_request(GPIO_PIN_EBI2_LCD_CS, "disp_cs");
+		if (rc) {
+			pr_err("request gpio EBI2_LCD_CS failed, rc=%d\n", rc);
+			goto error2;
+		}
+		rc = gpio_request(GPIO_PIN_EBI2_LCD_RS, "disp_rs");
+		if (rc) {
+			pr_err("request gpio EBI2_LCD_RS failed, rc=%d\n", rc);
+			goto error3;
+		}
+	} else {
+		gpio_free(GPIO_PIN_EBI2_LCD_RS);
+		gpio_free(GPIO_PIN_EBI2_LCD_CS);
+		gpio_free(GPIO_PIN_EBI2_LCD_A_D);
+
+		rc = regulator_disable(panel_power);
+		if (rc) {
+			pr_err("disable L14 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+error3:
+	gpio_free(GPIO_PIN_EBI2_LCD_CS);
+error2:
+	gpio_free(GPIO_PIN_EBI2_LCD_A_D);
+error1:
+	regulator_disable(panel_power);
+	return rc;
+
+}
+
+static struct lcdc_platform_data ebi2_lcdc_pdata = {
+	.lcdc_power_save = ebi2_panel_power,
+};
+
+static struct lvds_panel_platform_data ebi2_epson_s1d_pdata;
+
+static struct platform_device ebi2_epson_s1d_panel_device = {
+	.name = "ebi2_epson_s1d_qvga",
+	.id = 0,
+	.dev = {
+		.platform_data = &ebi2_epson_s1d_pdata,
+	}
+};
+
+void __init mdm9615_init_fb(void)
+{
+	platform_device_register(&msm_fb_device);
+	platform_device_register(&ebi2_epson_s1d_panel_device);
+
+	msm_fb_register_device("ebi2_lcd", &ebi2_lcdc_pdata);
+}
+#endif
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index ea8caf5..0e18918 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.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
@@ -79,6 +79,41 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting cdc_mclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+#ifdef CONFIG_FB_MSM_EBI2
+static struct gpiomux_setting ebi2_lcdc_a_d = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ebi2_lcdc_cs = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ebi2_lcdc_rs = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+#endif
+
+static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_mclk,
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
 	{
 		/* SDC2_DATA_0 */
@@ -248,6 +283,29 @@
 	},
 };
 
+#ifdef CONFIG_FB_MSM_EBI2
+static struct msm_gpiomux_config msm9615_ebi2_lcdc_configs[] __initdata = {
+	{
+		.gpio      = 21,	/* a_d */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_lcdc_a_d,
+		},
+	},
+	{
+		.gpio      = 22,	/* cs */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_lcdc_cs,
+		},
+	},
+	{
+		.gpio      = 24,	/* rs */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_lcdc_rs,
+		},
+	},
+};
+#endif
+
 int __init msm9615_init_gpiomux(void)
 {
 	int rc;
@@ -271,6 +329,13 @@
 	msm_gpiomux_install(msm9615_ltc4088_charger_config,
 			ARRAY_SIZE(msm9615_ltc4088_charger_config));
 #endif
+	msm_gpiomux_install(msm9615_audio_codec_configs,
+			ARRAY_SIZE(msm9615_audio_codec_configs));
+
+#ifdef CONFIG_FB_MSM_EBI2
+	msm_gpiomux_install(msm9615_ebi2_lcdc_configs,
+			ARRAY_SIZE(msm9615_ebi2_lcdc_configs));
+#endif
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 58e40db..8328501 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -65,6 +65,7 @@
 };
 VREG_CONSUMERS(L14) = {
 	REGULATOR_SUPPLY("8018_l14",		NULL),
+	REGULATOR_SUPPLY("VDDI2",		"ebi2_lcd.0"),
 };
 VREG_CONSUMERS(S1) = {
 	REGULATOR_SUPPLY("8018_s1",		NULL),
@@ -74,10 +75,22 @@
 };
 VREG_CONSUMERS(S2) = {
 	REGULATOR_SUPPLY("8018_s2",		NULL),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla2x-slim"),
 };
 VREG_CONSUMERS(S3) = {
 	REGULATOR_SUPPLY("8018_s3",		NULL),
 	REGULATOR_SUPPLY("wlan_vreg",		"wlan_ar6000_pm_dev"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla2x-slim"),
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8018_s4",		NULL),
@@ -171,8 +184,8 @@
 
 #define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
 		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
-		 _force_mode, _power_mode, _state, _sleep_selectable, \
-		 _always_on, _supply_regulator, _system_uA) \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -198,6 +211,7 @@
 		.freq			= RPM_VREG_FREQ_##_freq, \
 		.pin_fn			= _pin_fn, \
 		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
 		.power_mode		= _power_mode, \
 		.state			= _state, \
 		.sleep_selectable	= _sleep_selectable, \
@@ -211,6 +225,7 @@
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, \
 		 RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, _system_uA)
@@ -222,6 +237,7 @@
 		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
 		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, \
 		 RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, _system_uA)
@@ -229,6 +245,7 @@
 #define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
 	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
 		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, \
 		 RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
index 95c87bf..5a795c0 100644
--- a/arch/arm/mach-msm/board-9615-storage.c
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -21,6 +21,8 @@
 #include <mach/gpiomux.h>
 #include "devices.h"
 
+#include "board-9615.h"
+
 #if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
 		|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
 
@@ -212,11 +214,15 @@
 void __init msm9615_init_mmc(void)
 {
 	if (msm9615_sdc1_pdata) {
+		msm9615_sdc1_pdata->swfi_latency =
+			msm9615_rpm_get_swfi_latency();
 		/* SDC1: External card slot for SD/MMC cards */
 		msm_add_sdcc(1, msm9615_sdc1_pdata);
 	}
 
 	if (msm9615_sdc2_pdata) {
+		msm9615_sdc2_pdata->swfi_latency =
+			msm9615_rpm_get_swfi_latency();
 		/* SDC2: External card slot used for WLAN */
 		msm_add_sdcc(2, msm9615_sdc2_pdata);
 	}
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 74471dd..8a8e575 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -15,6 +15,10 @@
 #include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/slimbus/slimbus.h>
+#ifdef CONFIG_WCD9310_CODEC
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#endif
 #include <linux/msm_ssbi.h>
 #include <linux/memblock.h>
 #include <linux/usb/android.h>
@@ -23,15 +27,22 @@
 #include <linux/leds.h>
 #include <linux/leds-pm8xxx.h>
 #include <linux/power/ltc4088-charger.h>
+#include <linux/msm_tsens.h>
+#include <linux/ion.h>
+#include <linux/memory.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/gpio.h>
+#include <mach/socinfo.h>
 #include <mach/msm_spi.h>
 #include <mach/msm_bus_board.h>
 #include <mach/msm_xo.h>
+#include <mach/dma.h>
+#include <mach/ion.h>
+#include <mach/msm_memtypes.h>
 #include "timer.h"
 #include "devices.h"
 #include "board-9615.h"
@@ -40,6 +51,80 @@
 #include "acpuclock.h"
 #include "pm-boot.h"
 
+#ifdef CONFIG_ION_MSM
+#define MSM_ION_AUDIO_SIZE	0xAF000
+#define MSM_ION_HEAP_NUM	3
+#define MSM_KERNEL_EBI_SIZE	0x51000
+
+static struct memtype_reserve msm9615_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static int msm9615_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+	.adjacent_mem_id = INVALID_HEAP_ID,
+	.align = PAGE_SIZE,
+};
+
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+		{
+			.id	= ION_IOMMU_HEAP_ID,
+			.type	= ION_HEAP_TYPE_IOMMU,
+			.name	= ION_IOMMU_HEAP_NAME,
+		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+	}
+};
+
+static struct platform_device ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &ion_pdata },
+};
+
+static void reserve_ion_memory(void)
+{
+	msm9615_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+}
+
+static void __init msm9615_calculate_reserve_sizes(void)
+{
+	reserve_ion_memory();
+	msm9615_reserve_table[MEMTYPE_EBI1].size += MSM_KERNEL_EBI_SIZE;
+}
+
+static struct reserve_info msm9615_reserve_info __initdata = {
+	.memtype_reserve_table = msm9615_reserve_table,
+	.calculate_reserve_sizes = msm9615_calculate_reserve_sizes,
+	.paddr_to_memtype = msm9615_paddr_to_memtype,
+};
+#endif
+
 static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
 	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
@@ -230,8 +315,96 @@
 #endif
 }
 
+#ifdef CONFIG_WCD9310_CODEC
+
+#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+
+static struct wcd9xxx_pdata tabla20_platform_data = {
+	.slimbus_slave_device = {
+		.name = "tabla-slave",
+		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
+	},
+	.irq = 85,
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = 84,
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device msm_slim_tabla20 = {
+	.name = "tabla2x-slim",
+	.e_addr = {0, 1, 0x60, 0, 0x17, 2},
+	.dev = {
+		.platform_data = &tabla20_platform_data,
+	},
+};
+#endif
+
 static struct slim_boardinfo msm_slim_devices[] = {
 	/* add slimbus slaves as needed */
+#ifdef CONFIG_WCD9310_CODEC
+	{
+		.bus_num = 1,
+		.slim_slave = &msm_slim_tabla20,
+	},
+#endif
 };
 
 static struct msm_spi_platform_data msm9615_qup_spi_gsbi3_pdata = {
@@ -272,16 +445,15 @@
 	0x44, 0x80,/* set VBUS valid threshold and
 			disconnect valid threshold */
 	0x38, 0x81, /* update DC voltage level */
-	0x14, 0x82,/* set preemphasis and rise/fall time */
+	0x24, 0x82,/* set preemphasis and rise/fall time */
 	0x13, 0x83,/* set source impedance adjustment */
 	-1};
 
 #define USB_BAM_PHY_BASE	0x12502000
 #define HSIC_BAM_PHY_BASE	0x12542000
 #define A2_BAM_PHY_BASE		0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[4][2] = {
-#ifndef CONFIG_USB_GADGET_CI13XXX_MSM_HSIC
-	[0][USB_TO_PEER_PERIPHERAL] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[2][4][2] = {
+	[0][0][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 11,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -291,7 +463,7 @@
 		.desc_fifo_base_offset = 0x1700,
 		.desc_fifo_size = 0x300,
 	},
-	[0][PEER_PERIPHERAL_TO_USB] = {
+	[0][0][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -301,7 +473,7 @@
 		.desc_fifo_base_offset = 0x1000,
 		.desc_fifo_size = 0x100,
 	},
-	[1][USB_TO_PEER_PERIPHERAL] = {
+	[0][1][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 13,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -311,7 +483,7 @@
 		.desc_fifo_base_offset = 0x2700,
 		.desc_fifo_size = 0x300,
 	},
-	[1][PEER_PERIPHERAL_TO_USB] = {
+	[0][1][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -321,7 +493,7 @@
 		.desc_fifo_base_offset = 0x2000,
 		.desc_fifo_size = 0x100,
 	},
-	[2][USB_TO_PEER_PERIPHERAL] = {
+	[0][2][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 15,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -331,7 +503,7 @@
 		.desc_fifo_base_offset = 0x3700,
 		.desc_fifo_size = 0x300,
 	},
-	[2][PEER_PERIPHERAL_TO_USB] = {
+	[0][2][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -340,9 +512,8 @@
 		.data_fifo_size = 0x600,
 		.desc_fifo_base_offset = 0x3000,
 		.desc_fifo_size = 0x100,
-	}
-#else
-	[0][USB_TO_PEER_PERIPHERAL] = {
+	},
+	[1][0][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -352,7 +523,7 @@
 		.desc_fifo_base_offset = 0x1700,
 		.desc_fifo_size = 0x300,
 	},
-	[0][PEER_PERIPHERAL_TO_USB] = {
+	[1][0][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -362,7 +533,7 @@
 		.desc_fifo_base_offset = 0x1000,
 		.desc_fifo_size = 0x100,
 	},
-	[1][USB_TO_PEER_PERIPHERAL] = {
+	[1][1][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -372,7 +543,7 @@
 		.desc_fifo_base_offset = 0x2700,
 		.desc_fifo_size = 0x300,
 	},
-	[1][PEER_PERIPHERAL_TO_USB] = {
+	[1][1][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -382,7 +553,7 @@
 		.desc_fifo_base_offset = 0x2000,
 		.desc_fifo_size = 0x100,
 	},
-	[2][USB_TO_PEER_PERIPHERAL] = {
+	[1][2][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -392,7 +563,7 @@
 		.desc_fifo_base_offset = 0x3700,
 		.desc_fifo_size = 0x300,
 	},
-	[2][PEER_PERIPHERAL_TO_USB] = {
+	[1][2][PEER_PERIPHERAL_TO_USB] = {
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -402,18 +573,16 @@
 		.desc_fifo_base_offset = 0x3000,
 		.desc_fifo_size = 0x100,
 	}
-#endif
 };
 
 static struct msm_usb_bam_platform_data msm_usb_bam_pdata = {
-	.connections = &msm_usb_bam_connections[0][0],
-#ifndef CONFIG_USB_GADGET_CI13XXX_MSM_HSIC
+	.connections = &msm_usb_bam_connections[0][0][0],
+#ifndef CONFIG_USB_CI13XXX_MSM_HSIC
 	.usb_active_bam = HSUSB_BAM,
-	.usb_bam_num_pipes = 16,
 #else
 	.usb_active_bam = HSIC_BAM,
-	.usb_bam_num_pipes = 16,
 #endif
+	.usb_bam_num_pipes = 16,
 };
 
 static struct msm_otg_platform_data msm_otg_pdata = {
@@ -508,13 +677,22 @@
 };
 #endif
 
+static struct tsens_platform_data msm_tsens_pdata  = {
+	.tsens_factor		= 1000,
+	.hw_type		= MDM_9615,
+	.tsens_num_sensor	= 5,
+	.slope = {1176, 1176, 1154, 1176, 1111},
+};
+
 static struct platform_device *common_devices[] = {
 	&msm9615_device_dmov,
 	&msm_device_smd,
 #ifdef CONFIG_LTC4088_CHARGER
 	&msm_device_charger,
 #endif
+#ifndef CONFIG_USB_CI13XXX_MSM_HSIC
 	&msm_device_otg,
+#endif
 	&msm_device_hsic_peripheral,
 	&msm_device_gadget_peripheral,
 	&msm_device_hsusb_host,
@@ -528,13 +706,35 @@
 	&msm9615_device_qup_spi_gsbi3,
 	&msm_device_sps,
 	&msm9615_slim_ctrl,
-	&msm9615_device_tsens,
 	&msm_device_nand,
 	&msm_device_bam_dmux,
 	&msm9615_rpm_device,
 #ifdef CONFIG_HW_RANDOM_MSM
 	&msm_device_rng,
 #endif
+#ifdef CONFIG_ION_MSM
+	&ion_dev,
+#endif
+
+	&msm_pcm,
+	&msm_multi_ch_pcm,
+	&msm_pcm_routing,
+	&msm_cpudai0,
+	&msm_cpudai1,
+	&msm_cpudai_bt_rx,
+	&msm_cpudai_bt_tx,
+	&msm_cpu_fe,
+	&msm_stub_codec,
+	&msm_voice,
+	&msm_voip,
+	&msm_pcm_hostless,
+	&msm_cpudai_afe_01_rx,
+	&msm_cpudai_afe_01_tx,
+	&msm_cpudai_afe_02_rx,
+	&msm_cpudai_afe_02_tx,
+	&msm_pcm_afe,
+	&msm_cpudai_auxpcm_rx,
+	&msm_cpudai_auxpcm_tx,
 
 #if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
 		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
@@ -560,7 +760,10 @@
 
 static void __init msm9615_reserve(void)
 {
-	msm_pm_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
+#ifdef CONFIG_ION_MSM
+	reserve_info = &msm9615_reserve_info;
+	msm_reserve();
+#endif
 }
 
 static void __init msm9615_common_init(void)
@@ -596,12 +799,17 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 						msm_pm_data);
+	msm_pm_boot_pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_tsens_early_init(&msm_tsens_pdata);
 }
 
 static void __init msm9615_cdp_init(void)
 {
 	msm9615_common_init();
+#ifdef CONFIG_FB_MSM
+	mdm9615_init_fb();
+#endif
 }
 
 static void __init msm9615_mtp_init(void)
@@ -609,6 +817,13 @@
 	msm9615_common_init();
 }
 
+#ifdef CONFIG_FB_MSM
+static void __init mdm9615_allocate_memory_regions(void)
+{
+	mdm9615_allocate_fb_region();
+}
+#endif
+
 MACHINE_START(MSM9615_CDP, "QCT MSM9615 CDP")
 	.map_io = msm9615_map_io,
 	.init_irq = msm9615_init_irq,
@@ -616,6 +831,9 @@
 	.timer = &msm_timer,
 	.init_machine = msm9615_cdp_init,
 	.reserve = msm9615_reserve,
+#ifdef CONFIG_FB_MSM
+	.init_early = mdm9615_allocate_memory_regions,
+#endif
 MACHINE_END
 
 MACHINE_START(MSM9615_MTP, "QCT MSM9615 MTP")
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 4759f8c..239453f 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.h
@@ -36,7 +36,10 @@
 #define GPIO_VREG_ID_EXT_2P95V		0
 
 extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
+uint32_t msm9615_rpm_get_swfi_latency(void);
 
 int msm9615_init_gpiomux(void);
 void msm9615_init_mmc(void);
+void mdm9615_allocate_fb_region(void);
+void mdm9615_init_fb(void);
 #endif
diff --git a/arch/arm/mach-msm/board-copper-regulator.c b/arch/arm/mach-msm/board-copper-regulator.c
new file mode 100644
index 0000000..9409936
--- /dev/null
+++ b/arch/arm/mach-msm/board-copper-regulator.c
@@ -0,0 +1,359 @@
+/*
+ * 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/platform_device.h>
+#include <linux/regulator/stub-regulator.h>
+
+#define VREG_CONSUMERS(_name) \
+	static struct regulator_consumer_supply vreg_consumers_##_name[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(S1B) = {
+	REGULATOR_SUPPLY("8841_s1",		NULL),
+};
+VREG_CONSUMERS(S2B) = {
+	REGULATOR_SUPPLY("8841_s2",		NULL),
+	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
+};
+VREG_CONSUMERS(S3B) = {
+	REGULATOR_SUPPLY("8841_s3",		NULL),
+};
+VREG_CONSUMERS(S4B) = {
+	REGULATOR_SUPPLY("8841_s4",		NULL),
+};
+VREG_CONSUMERS(S5B) = {
+	REGULATOR_SUPPLY("8841_s5",		NULL),
+};
+VREG_CONSUMERS(S6B) = {
+	REGULATOR_SUPPLY("8841_s6",		NULL),
+};
+VREG_CONSUMERS(S7B) = {
+	REGULATOR_SUPPLY("8841_s7",		NULL),
+};
+VREG_CONSUMERS(S8B) = {
+	REGULATOR_SUPPLY("8841_s8",		NULL),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8941_s1",		NULL),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8941_s2",		NULL),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8941_s3",		NULL),
+};
+VREG_CONSUMERS(L1) = {
+	REGULATOR_SUPPLY("8941_l1",		NULL),
+};
+VREG_CONSUMERS(L2) = {
+	REGULATOR_SUPPLY("8941_l2",		NULL),
+};
+VREG_CONSUMERS(L3) = {
+	REGULATOR_SUPPLY("8941_l3",		NULL),
+};
+VREG_CONSUMERS(L4) = {
+	REGULATOR_SUPPLY("8941_l4",		NULL),
+};
+VREG_CONSUMERS(L5) = {
+	REGULATOR_SUPPLY("8941_l5",		NULL),
+};
+VREG_CONSUMERS(L6) = {
+	REGULATOR_SUPPLY("8941_l6",		NULL),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
+};
+VREG_CONSUMERS(L7) = {
+	REGULATOR_SUPPLY("8941_l7",		NULL),
+};
+VREG_CONSUMERS(L8) = {
+	REGULATOR_SUPPLY("8941_l8",		NULL),
+};
+VREG_CONSUMERS(L9) = {
+	REGULATOR_SUPPLY("8941_l9",		NULL),
+};
+VREG_CONSUMERS(L10) = {
+	REGULATOR_SUPPLY("8941_l10",		NULL),
+};
+VREG_CONSUMERS(L11) = {
+	REGULATOR_SUPPLY("8941_l11",		NULL),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8941_l12",		NULL),
+};
+VREG_CONSUMERS(L13) = {
+	REGULATOR_SUPPLY("8941_l13",		NULL),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8941_l14",		NULL),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8941_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8941_l16",		NULL),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8941_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8941_l18",		NULL),
+};
+VREG_CONSUMERS(L19) = {
+	REGULATOR_SUPPLY("8941_l19",		NULL),
+};
+VREG_CONSUMERS(L20) = {
+	REGULATOR_SUPPLY("8941_l20",		NULL),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8941_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8941_l22",		NULL),
+};
+VREG_CONSUMERS(L23) = {
+	REGULATOR_SUPPLY("8941_l23",		NULL),
+};
+VREG_CONSUMERS(L24) = {
+	REGULATOR_SUPPLY("8941_l24",		NULL),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8941_lvs1",		NULL),
+};
+VREG_CONSUMERS(LVS2) = {
+	REGULATOR_SUPPLY("8941_lvs2",		NULL),
+};
+VREG_CONSUMERS(LVS3) = {
+	REGULATOR_SUPPLY("8941_lvs3",		NULL),
+};
+VREG_CONSUMERS(K0) = {
+	REGULATOR_SUPPLY("krait0",		NULL),
+};
+VREG_CONSUMERS(K1) = {
+	REGULATOR_SUPPLY("krait1",		NULL),
+};
+VREG_CONSUMERS(K2) = {
+	REGULATOR_SUPPLY("krait2",		NULL),
+};
+VREG_CONSUMERS(K3) = {
+	REGULATOR_SUPPLY("krait3",		NULL),
+};
+
+#define PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _always_on, _supply_regulator, _hpm_min, _system_uA)  \
+	struct stub_regulator_pdata vreg_dev_##_id##_pdata __devinitdata = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= 0,	\
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.hpm_min_load		= _hpm_min, \
+		.system_uA		= _system_uA, \
+	}
+
+#define PM8X41_LDO(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+#define PM8X41_SMPS(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+#define PM8X41_FTSMPS(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
+		| REGULATOR_CHANGE_MODE, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+#define PM8X41_VS(_id, _name, _always_on, _supply_regulator) \
+	PM8X41_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, \
+		 _always_on, _supply_regulator, 0, 0)
+
+#define KRAIT_PWR(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+/* PM8x41 regulator constraints */
+
+/*	    ID      name     a_on  min_uV   max_uV  supply    hpm_min sys_uA  */
+PM8X41_SMPS(S1B,   "8841_s1", 0, 900000,  1150000,  NULL,       100000, 0);
+PM8X41_FTSMPS(S2B, "8841_s2", 0, 900000,  1150000,  NULL,       100000, 0);
+PM8X41_SMPS(S3B,   "8841_s3", 0, 1150000, 1150000, NULL,       100000, 0);
+PM8X41_FTSMPS(S4B, "8841_s4", 0, 900000,  900000,  NULL,       100000, 0);
+PM8X41_FTSMPS(S5B, "8841_s5", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_FTSMPS(S6B, "8841_s6", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_FTSMPS(S7B, "8841_s7", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_FTSMPS(S8B, "8841_s8", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_SMPS(S1,   "8941_s1", 0, 1300000, 1300000, NULL,       100000, 0);
+PM8X41_SMPS(S2,   "8941_s2", 0, 2150000, 2150000, NULL,       100000, 0);
+PM8X41_SMPS(S3,   "8941_s3", 0, 1800000, 1800000, NULL,       100000, 0);
+PM8X41_LDO(L1,     "8941_l1",  0, 1225000, 1225000, "8941_s1", 100000, 0);
+PM8X41_LDO(L2,     "8941_l2",  0, 1200000, 1200000, "8941_s3", 5000,   0);
+PM8X41_LDO(L3,     "8941_l3",  0, 1200000, 1200000, "8941_s1", 10000,  0);
+PM8X41_LDO(L4,     "8941_l4",  0, 1150000, 1150000, "8941_s1", 10000,  0);
+PM8X41_LDO(L5,     "8941_l5",  0, 1800000, 1800000, "8941_s2", 1000,   0);
+PM8X41_LDO(L6,     "8941_l6",  0, 1800000, 1800000, "8941_s2", 10000,  0);
+PM8X41_LDO(L7,     "8941_l7",  0, 1800000, 1800000, "8941_s2", 1000,   0);
+PM8X41_LDO(L8,     "8941_l8",  0, 1800000, 1800000, NULL,       1000,   0);
+PM8X41_LDO(L9,     "8941_l9",  0, 1800000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L10,    "8941_l10", 0, 1800000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L11,    "8941_l11", 0, 1250000, 1250000, "8941_s1", 10000,  0);
+PM8X41_LDO(L12,    "8941_l12", 0, 1800000, 1800000, "8941_s2", 10000,  0);
+PM8X41_LDO(L13,    "8941_l13", 0, 2950000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L14,    "8941_l14", 0, 1800000, 1800000, "8941_s2", 10000,  0);
+PM8X41_LDO(L15,    "8941_l15", 0, 2050000, 2050000, "8941_s2", 10000,  0);
+PM8X41_LDO(L16,    "8941_l16", 0, 2700000, 2700000, NULL,       10000,  0);
+PM8X41_LDO(L17,    "8941_l17", 0, 2850000, 2850000, NULL,       10000,  0);
+PM8X41_LDO(L18,    "8941_l18", 0, 2850000, 2850000, NULL,       10000,  0);
+PM8X41_LDO(L19,    "8941_l19", 0, 2900000, 2900000, NULL,       10000,  0);
+PM8X41_LDO(L20,    "8941_l20", 0, 2950000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L21,    "8941_l21", 0, 2950000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L22,    "8941_l22", 0, 3000000, 3000000, NULL,       10000,  0);
+PM8X41_LDO(L23,    "8941_l23", 0, 3000000, 3000000, NULL,       10000,  0);
+PM8X41_LDO(L24,    "8941_l24", 0, 3075000, 3075000, NULL,       5000,   0);
+
+/*	  ID	      name     a_on   supply  */
+PM8X41_VS(LVS1,    "8941_lvs1", 0, "8941_s3");
+PM8X41_VS(LVS2,    "8941_lvs2", 0, "8941_s3");
+PM8X41_VS(LVS3,    "8941_lvs3", 0, "8941_s3");
+
+/*	 ID      name     a_on  min_uV   max_uV  supply  hpm_min sys_uA  */
+KRAIT_PWR(K0, "krait0", 0, 850000,  1100000, NULL,     100000, 0);
+KRAIT_PWR(K1, "krait1", 0, 850000,  1100000, NULL,     100000, 0);
+KRAIT_PWR(K2, "krait2", 0, 850000,  1100000, NULL,     100000, 0);
+KRAIT_PWR(K3, "krait3", 0, 850000,  1100000, NULL,     100000, 0);
+
+#define VREG_DEVICE(_name, _devid)					       \
+		vreg_device_##_name __devinitdata =			       \
+		{							       \
+			.name = STUB_REGULATOR_DRIVER_NAME,		       \
+			.id = _devid,					       \
+			.dev = { .platform_data = &vreg_dev_##_name##_pdata }, \
+		}
+
+static struct platform_device VREG_DEVICE(S1B, 0);
+static struct platform_device VREG_DEVICE(S2B, 1);
+static struct platform_device VREG_DEVICE(S3B, 3);
+static struct platform_device VREG_DEVICE(S4B, 4);
+static struct platform_device VREG_DEVICE(S5B, 5);
+static struct platform_device VREG_DEVICE(S6B, 6);
+static struct platform_device VREG_DEVICE(S7B, 7);
+static struct platform_device VREG_DEVICE(S8B, 8);
+static struct platform_device VREG_DEVICE(S1, 9);
+static struct platform_device VREG_DEVICE(S2, 10);
+static struct platform_device VREG_DEVICE(S3, 11);
+static struct platform_device VREG_DEVICE(L1, 12);
+static struct platform_device VREG_DEVICE(L2, 13);
+static struct platform_device VREG_DEVICE(L3, 14);
+static struct platform_device VREG_DEVICE(L4, 15);
+static struct platform_device VREG_DEVICE(L5, 16);
+static struct platform_device VREG_DEVICE(L6, 17);
+static struct platform_device VREG_DEVICE(L7, 18);
+static struct platform_device VREG_DEVICE(L8, 19);
+static struct platform_device VREG_DEVICE(L9, 20);
+static struct platform_device VREG_DEVICE(L10, 21);
+static struct platform_device VREG_DEVICE(L11, 22);
+static struct platform_device VREG_DEVICE(L12, 23);
+static struct platform_device VREG_DEVICE(L13, 24);
+static struct platform_device VREG_DEVICE(L14, 25);
+static struct platform_device VREG_DEVICE(L15, 26);
+static struct platform_device VREG_DEVICE(L16, 27);
+static struct platform_device VREG_DEVICE(L17, 28);
+static struct platform_device VREG_DEVICE(L18, 29);
+static struct platform_device VREG_DEVICE(L19, 30);
+static struct platform_device VREG_DEVICE(L20, 31);
+static struct platform_device VREG_DEVICE(L21, 32);
+static struct platform_device VREG_DEVICE(L22, 33);
+static struct platform_device VREG_DEVICE(L23, 34);
+static struct platform_device VREG_DEVICE(L24, 35);
+static struct platform_device VREG_DEVICE(LVS1, 36);
+static struct platform_device VREG_DEVICE(LVS2, 37);
+static struct platform_device VREG_DEVICE(LVS3, 38);
+static struct platform_device VREG_DEVICE(K0, 39);
+static struct platform_device VREG_DEVICE(K1, 40);
+static struct platform_device VREG_DEVICE(K2, 41);
+static struct platform_device VREG_DEVICE(K3, 42);
+
+struct platform_device *msm_copper_stub_regulator_devices[] __devinitdata = {
+	&vreg_device_S1B,
+	&vreg_device_S2B,
+	&vreg_device_S3B,
+	&vreg_device_S4B,
+	&vreg_device_S5B,
+	&vreg_device_S6B,
+	&vreg_device_S7B,
+	&vreg_device_S8B,
+	&vreg_device_S1,
+	&vreg_device_S2,
+	&vreg_device_S3,
+	&vreg_device_L1,
+	&vreg_device_L2,
+	&vreg_device_L3,
+	&vreg_device_L4,
+	&vreg_device_L5,
+	&vreg_device_L6,
+	&vreg_device_L7,
+	&vreg_device_L8,
+	&vreg_device_L9,
+	&vreg_device_L10,
+	&vreg_device_L11,
+	&vreg_device_L12,
+	&vreg_device_L13,
+	&vreg_device_L14,
+	&vreg_device_L15,
+	&vreg_device_L16,
+	&vreg_device_L17,
+	&vreg_device_L18,
+	&vreg_device_L19,
+	&vreg_device_L20,
+	&vreg_device_L21,
+	&vreg_device_L22,
+	&vreg_device_L23,
+	&vreg_device_L24,
+	&vreg_device_LVS1,
+	&vreg_device_LVS2,
+	&vreg_device_LVS3,
+	&vreg_device_K0,
+	&vreg_device_K1,
+	&vreg_device_K2,
+	&vreg_device_K3,
+};
+
+int msm_copper_stub_regulator_devices_len __devinitdata =
+			ARRAY_SIZE(msm_copper_stub_regulator_devices);
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 4b6716e..b074809 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -26,6 +26,7 @@
 #ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
 #endif
+#include <linux/regulator/stub-regulator.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <mach/board.h>
@@ -37,7 +38,9 @@
 #endif
 #include <mach/msm_memtypes.h>
 #include <mach/msm_smd.h>
+#include <mach/qpnp-int.h>
 #include "clock.h"
+#include "devices.h"
 
 #define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -350,17 +353,37 @@
 	return 0;
 }
 
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+};
+
 void __init msm_copper_add_devices(void)
 {
 #ifdef CONFIG_ION_MSM
 	platform_device_register(&ion_dev);
 #endif
 	platform_device_register(&msm_device_smd_copper);
+	platform_device_register(&android_usb_device);
+	platform_add_devices(msm_copper_stub_regulator_devices,
+					msm_copper_stub_regulator_devices_len);
+}
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msm_copper_add_drivers(void)
+{
+	regulator_stub_init();
 }
 
 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, },
 	{}
 };
 
@@ -380,11 +403,15 @@
 	CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
 	CLK_DUMMY("alt_core_clk", NULL, "msm_otg", OFF),
 	CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("xo", NULL, "msm_otg", OFF),
 	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
 	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
 	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
 	CLK_DUMMY("core_clk",	SPI_CLK,	"spi_qsd.1",	OFF),
 	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
 };
 
 struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 51ca29d..674df09 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -26,39 +26,13 @@
 
 static void __init msm_dt_timer_init(void)
 {
-	struct device_node *node;
-	struct resource res;
-	int rc;
-
-	node = of_find_compatible_node(NULL, NULL, "qcom,msm-qtimer");
-	if (!node) {
-		pr_err("no matching timer node found\n");
-		return;
-	}
-
-	rc = of_irq_to_resource(node, 0, &res);
-	if (rc < 0)
-		pr_err("interrupt not specified in timer node\n");
-	else
-		arch_timer_register(&res, 1);
-
-	of_node_put(node);
+	arch_timer_of_register();
 }
 
 static struct sys_timer msm_dt_timer = {
 	.init = msm_dt_timer_init
 };
 
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	return 0;
-}
-
-void local_timer_stop(void)
-{
-	return;
-}
-
 static void __init msm_dt_init_irq(void)
 {
 	if (machine_is_copper())
@@ -81,11 +55,13 @@
 		msm_copper_init(&adata);
 
 	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
-	if (machine_is_copper())
+	if (machine_is_copper()) {
 		msm_copper_add_devices();
+		msm_copper_add_drivers();
+	}
 }
 
-static const char *msm_dt_match[] __initdata = {
+static const char *msm_dt_match[] __initconst = {
 	"qcom,msmcopper",
 	NULL
 };
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 87fea3f..ce6bf35 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.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
@@ -835,6 +835,7 @@
 	&qcedev_device,
 	&ota_qcrypto_device,
 	&fsm_xo_device,
+	&fsm9xxx_device_watchdog,
 };
 
 static void __init fsm9xxx_init_irq(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index c70b30e..81abbc0 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -20,6 +20,7 @@
 #include <asm/gpio.h>
 #include <asm/mach-types.h>
 #include <mach/rpc_pmapp.h>
+#include <mach/socinfo.h>
 
 #include "board-msm7627a.h"
 #include "devices-msm7x2xa.h"
@@ -32,7 +33,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",
 };
 
@@ -98,10 +99,19 @@
 int gpio_bt_sys_rest_en = 133;
 static void gpio_bt_config(void)
 {
+	u32 socinfo = socinfo_get_platform_version();
 	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;
+	if (machine_is_msm8625_qrd7())
+		gpio_bt_sys_rest_en = 88;
+	if (machine_is_msm7627a_qrd3()) {
+		if (socinfo == 0x70002)
+			gpio_bt_sys_rest_en = 88;
+		 else
+			gpio_bt_sys_rest_en = 85;
+	}
 }
 
 static int bt_set_gpio(int on)
@@ -109,14 +119,37 @@
 	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() || machine_is_msm8625_qrd7()) {
+			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() ||
+					 machine_is_msm8625_qrd7()) {
+				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 +357,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 +401,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);
@@ -935,14 +970,23 @@
 	int i, rc = 0;
 	struct device *dev;
 
-	if (machine_is_msm7627a_qrd3())
-		return;
 
 	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 +1008,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 77af5e2..94b8710 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -24,6 +24,12 @@
 #include "board-msm7627a.h"
 #include <mach/vreg.h>
 
+#define GPIO_SKU1_CAM_VGA_SHDN    18
+#define GPIO_SKU1_CAM_VGA_RESET_N 29
+#define GPIO_SKU3_CAM_5MP_SHDN_N   5         /* PWDN */
+#define GPIO_SKU3_CAM_5MP_CAMIF_RESET   6    /* (board_is(EVT))?123:121 RESET */
+#define GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN 30
+
 #ifdef CONFIG_MSM_CAMERA_V4L2
 static uint32_t camera_off_gpio_table[] = {
 	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
@@ -33,6 +39,55 @@
 	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
 };
 
+static struct gpio s5k4e1_cam_req_gpio[] = {
+	{GPIO_CAM_GP_CAMIF_RESET_N, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl s5k4e1_cam_gpio_set_tbl[] = {
+	{GPIO_CAM_GP_CAMIF_RESET_N, GPIOF_OUT_INIT_LOW, 1000},
+	{GPIO_CAM_GP_CAMIF_RESET_N, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf gpio_conf_s5k4e1 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_off_table_size = ARRAY_SIZE(camera_off_gpio_table),
+	.camera_on_table = camera_on_gpio_table,
+	.camera_on_table_size = ARRAY_SIZE(camera_on_gpio_table),
+	.cam_gpio_req_tbl = s5k4e1_cam_req_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(s5k4e1_cam_req_gpio),
+	.cam_gpio_set_tbl = s5k4e1_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(s5k4e1_cam_gpio_set_tbl),
+	.gpio_no_mux = 1,
+};
+
+static struct msm_camera_gpio_conf gpio_conf_mt9e013 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+
+static struct msm_camera_gpio_conf gpio_conf_ov9726 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct msm_camera_gpio_conf gpio_conf_ov7692 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+#endif
+
+#ifdef CONFIG_OV5647
+static struct msm_camera_gpio_conf gpio_conf_ov5647 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+#endif
+
 #ifdef CONFIG_MSM_CAMERA_FLASH
 static struct msm_camera_sensor_flash_src msm_flash_src = {
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
@@ -41,111 +96,22 @@
 };
 #endif
 
-static struct regulator_bulk_data regs_camera[] = {
-	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
-	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
-	{ .supply = "usb2",  .min_uV = 1800000, .max_uV = 1800000 },
+static struct camera_vreg_t msm_cam_vreg[] = {
+	{"msme1", REG_LDO, 1800000, 1800000, 0},
+	{"gp2", REG_LDO, 2850000, 2850000, 0},
+	{"usb2", REG_LDO, 1800000, 1800000, 0},
 };
 
-static void msm_camera_vreg_config(int vreg_en)
-{
-	int rc = vreg_en ?
-		regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
-		regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
-
-	if (rc)
-		pr_err("%s: could not %sable regulators: %d\n",
-				__func__, vreg_en ? "en" : "dis", rc);
-}
-
-static int config_gpio_table(uint32_t *table, int len)
-{
-	int rc = 0, i = 0;
-
-	for (i = 0; i < len; i++) {
-		rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
-		if (rc) {
-			pr_err("%s not able to get gpio\n", __func__);
-			for (i--; i >= 0; i--)
-				gpio_tlmm_config(camera_off_gpio_table[i],
-							GPIO_CFG_ENABLE);
-			break;
-		}
-	}
-	return rc;
-}
-
 static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
-/* TODO: static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data; */
-static int config_camera_on_gpios_rear(void)
-{
-	int rc = 0;
-
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(1);
-
-	rc = config_gpio_table(camera_on_gpio_table,
-			ARRAY_SIZE(camera_on_gpio_table));
-	if (rc < 0) {
-		pr_err("%s: CAMSENSOR gpio table request"
-		"failed\n", __func__);
-		return rc;
-	}
-
-	return rc;
-}
-
-static void config_camera_off_gpios_rear(void)
-{
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(0);
-
-	config_gpio_table(camera_off_gpio_table,
-			ARRAY_SIZE(camera_off_gpio_table));
-}
-
-static int config_camera_on_gpios_front(void)
-{
-	int rc = 0;
-
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(1);
-
-	rc = config_gpio_table(camera_on_gpio_table,
-			ARRAY_SIZE(camera_on_gpio_table));
-	if (rc < 0) {
-		pr_err("%s: CAMSENSOR gpio table request"
-			"failed\n", __func__);
-		return rc;
-	}
-
-	return rc;
-}
-
-static void config_camera_off_gpios_front(void)
-{
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(0);
-
-	config_gpio_table(camera_off_gpio_table,
-			ARRAY_SIZE(camera_off_gpio_table));
-}
 
 struct msm_camera_device_platform_data msm_camera_device_data_csi1 = {
-	.camera_gpio_on  = config_camera_on_gpios_rear,
-	.camera_gpio_off = config_camera_off_gpios_rear,
-	.ioclk.mclk_clk_rate = 24000000,
-	.ioclk.vfe_clk_rate  = 192000000,
 	.csid_core = 1,
 	.is_csic = 1,
 };
 
 struct msm_camera_device_platform_data msm_camera_device_data_csi0 = {
-	.camera_gpio_on  = config_camera_on_gpios_front,
-	.camera_gpio_off = config_camera_off_gpios_front,
-	.ioclk.mclk_clk_rate = 24000000,
-	.ioclk.vfe_clk_rate  = 192000000,
 	.csid_core = 0,
+	.is_csic = 1,
 };
 
 #ifdef CONFIG_DW9712_ACT
@@ -169,10 +135,9 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_s5k4e1 = {
 	.mount_angle	= 90,
-	.sensor_reset	= GPIO_CAM_GP_CAMIF_RESET_N,
-	.sensor_pwd	= 85,
-	.vcm_pwd	= GPIO_CAM_GP_CAM_PWDN,
-	.vcm_enable	= 1,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_s5k4e1,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
@@ -184,12 +149,92 @@
 	.sensor_platform_info   = &sensor_board_info_s5k4e1,
 	.csi_if                 = 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 #ifdef CONFIG_DW9712_ACT
 	.actuator_info = &s5k4e1_actuator_info
 #endif
 };
 #endif
 
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov7692,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type     = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	    = "ov7692",
+	.sensor_reset_enable    = 0,
+	.pmic_gpio_enable  = 1,
+	.sensor_reset	   = GPIO_SKU1_CAM_VGA_RESET_N,
+	.sensor_pwd	     = GPIO_SKU1_CAM_VGA_SHDN,
+	.pdata			= &msm_camera_device_data_csi0,
+	.flash_data	     = &flash_ov7692,
+	.sensor_platform_info   = &sensor_board_info_ov7692,
+	.csi_if		 = 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
+};
+#endif
+
+#ifdef CONFIG_OV5647
+
+#ifdef CONFIG_AD5046_ACT
+static struct i2c_board_info ad5046_actuator_i2c_info = {
+	I2C_BOARD_INFO("ad5046_act", 0x18 >> 1),
+};
+
+static struct msm_actuator_info ad5046_actuator_info = {
+	.board_info     = &ad5046_actuator_i2c_info,
+	.bus_id         = MSM_GSBI0_QUP_I2C_BUS_ID,
+	.vcm_pwd        = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
+	.vcm_enable     = 1,
+};
+#endif
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov5647 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov5647,
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_ov5647 = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_LED1,
+	._fsrc.ext_driver_src.led_en = 13,
+	._fsrc.ext_driver_src.led_flash_en = 32,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov5647 = {
+	.flash_type             = MSM_CAMERA_FLASH_LED,
+	.flash_src              = &msm_flash_src_ov5647,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov5647_data = {
+	.sensor_name    = "ov5647",
+	.sensor_reset_enable = 1,
+	.pmic_gpio_enable  = 1,
+	.sensor_reset   = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
+	.sensor_pwd     = GPIO_SKU3_CAM_5MP_SHDN_N,
+	.pdata          = &msm_camera_device_data_csi1,
+	.flash_data     = &flash_ov5647,
+	.sensor_platform_info   = &sensor_board_info_ov5647,
+	.csi_if                 = 1,
+	.camera_type	= BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+
+#ifdef CONFIG_AD5046_ACT
+	.actuator_info = &ad5046_actuator_info
+#endif
+};
+
+#endif
 #ifdef CONFIG_MT9E013
 static struct msm_camera_sensor_flash_data flash_mt9e013 = {
 	.flash_type             = MSM_CAMERA_FLASH_LED,
@@ -198,10 +243,9 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_mt9e013 = {
 	.mount_angle	= 90,
-	.sensor_reset	= 0,
-	.sensor_pwd	= 85,
-	.vcm_pwd	= 1,
-	.vcm_enable	= 0,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_mt9e013,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
@@ -213,38 +257,7 @@
 	.sensor_platform_info   = &sensor_board_info_mt9e013,
 	.csi_if                 = 1,
 	.camera_type = BACK_CAMERA_2D,
-};
-#endif
-
-#ifdef CONFIG_IMX072
-static struct msm_camera_sensor_platform_info imx072_sensor_7627a_info = {
-	.mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_imx072 = {
-	.flash_type             = MSM_CAMERA_FLASH_LED,
-	.flash_src              = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_imx072_data = {
-	.sensor_name    = "imx072",
-	.sensor_reset_enable = 1,
-	.sensor_reset   = GPIO_CAM_GP_CAMIF_RESET_N, /* TODO 106,*/
-	.pmic_gpio_enable  = 0,
-	.sensor_pwd             = 85,
-	.vcm_pwd                = GPIO_CAM_GP_CAM_PWDN,
-	.vcm_enable             = 1,
-	.pdata                  = &msm_camera_device_data_csi1,
-	.flash_data             = &flash_imx072,
-	.sensor_platform_info = &imx072_sensor_7627a_info,
-	.csi_if                 = 1
-};
-
-static struct platform_device msm_camera_sensor_imx072 = {
-	.name   = "msm_camera_imx072",
-	.dev    = {
-		.platform_data = &msm_camera_sensor_imx072_data,
-	},
+	.sensor_type = BAYER_SENSOR,
 };
 #endif
 
@@ -256,10 +269,9 @@
 
 static struct msm_camera_sensor_platform_info sensor_board_info_ov9726 = {
 	.mount_angle	= 90,
-	.sensor_reset	= GPIO_CAM_GP_CAM1MP_XCLR,
-	.sensor_pwd	= 85,
-	.vcm_pwd	= 1,
-	.vcm_enable	= 0,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov9726,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
@@ -271,41 +283,57 @@
 	.sensor_platform_info   = &sensor_board_info_ov9726,
 	.csi_if                 = 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 #endif
 
 static void __init msm7x27a_init_cam(void)
 {
-	platform_device_register(&msm7x27a_device_csic0);
-	platform_device_register(&msm7x27a_device_csic1);
+	if (!(machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1())) {
+		sensor_board_info_s5k4e1.cam_vreg = NULL;
+		sensor_board_info_s5k4e1.num_vreg = 0;
+		sensor_board_info_mt9e013.cam_vreg = NULL;
+		sensor_board_info_mt9e013.num_vreg = 0;
+		sensor_board_info_ov9726.cam_vreg = NULL;
+		sensor_board_info_ov9726.num_vreg = 0;
+		sensor_board_info_ov7692.cam_vreg = NULL;
+		sensor_board_info_ov7692.num_vreg = 0;
+		sensor_board_info_ov5647.cam_vreg = NULL;
+		sensor_board_info_ov5647.num_vreg = 0;
+	}
+	if (machine_is_msm8625_surf() || machine_is_msm8625_evb()) {
+		platform_device_register(&msm8625_device_csic0);
+		platform_device_register(&msm8625_device_csic1);
+	} else {
+		platform_device_register(&msm7x27a_device_csic0);
+		platform_device_register(&msm7x27a_device_csic1);
+	}
 	platform_device_register(&msm7x27a_device_clkctl);
 	platform_device_register(&msm7x27a_device_vfe);
 }
 
 static struct i2c_board_info i2c_camera_devices[] = {
-	#ifdef CONFIG_S5K4E1
 	{
 		I2C_BOARD_INFO("s5k4e1", 0x36),
 		.platform_data = &msm_camera_sensor_s5k4e1_data,
 	},
-	#endif
-	#ifdef CONFIG_WEBCAM_OV9726
 	{
 		I2C_BOARD_INFO("ov9726", 0x10),
 		.platform_data = &msm_camera_sensor_ov9726_data,
 	},
-	#endif
-	#ifdef CONFIG_IMX072
-	{
-		I2C_BOARD_INFO("imx072", 0x34),
-	},
-	#endif
-	#ifdef CONFIG_MT9E013
 	{
 		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
 		.platform_data = &msm_camera_sensor_mt9e013_data,
 	},
-	#endif
+	{
+		I2C_BOARD_INFO("ov7692", 0x78),
+		.platform_data = &msm_camera_sensor_ov7692_data,
+	},
+	{
+		I2C_BOARD_INFO("ov5647", 0x36 << 1),
+		.platform_data = &msm_camera_sensor_ov5647_data,
+	},
 	{
 		I2C_BOARD_INFO("sc628a", 0x6E),
 	},
@@ -389,13 +417,7 @@
 	gpio_direction_output(QRD_GPIO_CAM_5MP_RESET, 1);
 	gpio_direction_output(QRD_GPIO_CAM_3MP_PWDN, 1);
 }
-
-#define GPIO_SKU3_CAM_5MP_SHDN_N   5         /* PWDN */
-#define GPIO_SKU3_CAM_5MP_CAMIF_RESET   6    /* (board_is(EVT))?123:121 RESET */
-#define GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN 30
-
-#define GPIO_SKU1_CAM_VGA_SHDN    18
-#define GPIO_SKU1_CAM_VGA_RESET_N 29
+#endif
 
 static void evb_camera_gpio_cfg(void)
 {
@@ -469,6 +491,8 @@
 
 }
 
+#ifndef CONFIG_MSM_CAMERA_V4L2
+
 static void msm_camera_vreg_config(int vreg_en)
 {
 	int rc = vreg_en ?
@@ -603,7 +627,7 @@
 	.pmic_gpio_enable  = 1,
 	.sensor_pwd     = GPIO_SKU3_CAM_5MP_SHDN_N,
 	.vcm_pwd        = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
-	.vcm_enable     = 0,
+	.vcm_enable     = 1,
 	.pdata          = &msm_camera_device_data_rear,
 	.flash_data     = &flash_ov5647,
 	.sensor_platform_info   = &ov5647_sensor_7627a_info,
@@ -1034,23 +1058,26 @@
 }
 EXPORT_SYMBOL(lcd_camera_power_onoff);
 
-
 void __init msm7627a_camera_init(void)
 {
+
+#ifndef CONFIG_MSM_CAMERA_V4L2
 	int rc;
+#endif
 
 	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();
+		evb_camera_gpio_cfg();
+	}
 
 #ifndef CONFIG_MSM_CAMERA_V4L2
 	if (machine_is_msm7627a_qrd1()) {
 		qrd1_camera_gpio_cfg();
 		platform_add_devices(camera_devices_qrd,
 				ARRAY_SIZE(camera_devices_qrd));
-	} else if (machine_is_msm7627a_evb()) {
-		evb_camera_gpio_cfg();
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		platform_add_devices(camera_devices_evb,
 				ARRAY_SIZE(camera_devices_evb));
 	} else if (machine_is_msm7627a_qrd3())
@@ -1059,8 +1086,10 @@
 		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();
+#ifndef CONFIG_MSM_CAMERA_V4L2
 	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
 
 	if (rc) {
@@ -1074,6 +1103,7 @@
 		pr_err("%s: could not set voltages: %d\n", __func__, rc);
 		return;
 	}
+#endif
 
 #if defined(CONFIG_MSM_CAMERA_V4L2)
 	msm7x27a_init_cam();
@@ -1083,13 +1113,14 @@
 		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,
 				ARRAY_SIZE(i2c_camera_devices_evb));
 	} else
 #endif
+		pr_debug("i2c_register_board_info\n");
 		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
 				i2c_camera_devices,
 				ARRAY_SIZE(i2c_camera_devices));
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 4e856b1..e96284a 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -35,6 +35,12 @@
 #define MSM7x25A_MSM_FB_SIZE    0x96000
 #endif
 
+/*
+ * Reserve enough v4l2 space for a double buffered full screen
+ * res image (864x480x1.5x2)
+ */
+#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 1244160
+
 static unsigned fb_size = MSM_FB_SIZE;
 static int __init fb_size_setup(char *p)
 {
@@ -44,6 +50,245 @@
 
 early_param("fb_size", fb_size_setup);
 
+static uint32_t lcdc_truly_gpio_initialized;
+static struct regulator_bulk_data regs_truly_lcdc[] = {
+	{ .supply = "rfrx1",   .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+#define SKU3_LCDC_GPIO_DISPLAY_RESET	90
+#define SKU3_LCDC_GPIO_SPI_MOSI		19
+#define SKU3_LCDC_GPIO_SPI_CLK		20
+#define SKU3_LCDC_GPIO_SPI_CS0_N	21
+#define SKU3_LCDC_LCD_CAMERA_LDO_2V8	35  /*LCD_CAMERA_LDO_2V8*/
+#define SKU3_LCDC_LCD_CAMERA_LDO_1V8	34  /*LCD_CAMERA_LDO_1V8*/
+#define SKU3_1_LCDC_LCD_CAMERA_LDO_1V8	58  /*LCD_CAMERA_LDO_1V8*/
+
+static uint32_t lcdc_truly_gpio_table[] = {
+	19,
+	20,
+	21,
+	89,
+	90,
+};
+
+static char *lcdc_gpio_name_table[5] = {
+	"spi_mosi",
+	"spi_clk",
+	"spi_cs",
+	"gpio_bkl_en",
+	"gpio_disp_reset",
+};
+
+static int lcdc_truly_gpio_init(void)
+{
+	int i;
+	int rc = 0;
+
+	if (!lcdc_truly_gpio_initialized) {
+		for (i = 0; i < ARRAY_SIZE(lcdc_truly_gpio_table); i++) {
+			rc = gpio_request(lcdc_truly_gpio_table[i],
+				lcdc_gpio_name_table[i]);
+			if (rc < 0) {
+				pr_err("Error request gpio %s\n",
+					lcdc_gpio_name_table[i]);
+				goto truly_gpio_fail;
+			}
+			rc = gpio_tlmm_config(GPIO_CFG(lcdc_truly_gpio_table[i],
+				0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("Error config lcdc gpio:%d\n",
+					lcdc_truly_gpio_table[i]);
+				goto truly_gpio_fail;
+			}
+			rc = gpio_direction_output(lcdc_truly_gpio_table[i], 0);
+			if (rc < 0) {
+				pr_err("Error direct lcdc gpio:%d\n",
+					lcdc_truly_gpio_table[i]);
+				goto truly_gpio_fail;
+			}
+		}
+
+			lcdc_truly_gpio_initialized = 1;
+	}
+
+	return rc;
+
+truly_gpio_fail:
+	for (; i >= 0; i--) {
+		pr_err("Freeing GPIO: %d", lcdc_truly_gpio_table[i]);
+		gpio_free(lcdc_truly_gpio_table[i]);
+	}
+
+	lcdc_truly_gpio_initialized = 0;
+	return rc;
+}
+
+
+void sku3_lcdc_lcd_camera_power_init(void)
+{
+	int rc = 0;
+	u32 socinfo = socinfo_get_platform_type();
+
+	  /* LDO_EXT2V8 */
+	if (gpio_request(SKU3_LCDC_LCD_CAMERA_LDO_2V8, "lcd_camera_ldo_2v8")) {
+		pr_err("failed to request gpio lcd_camera_ldo_2v8\n");
+		return;
+	}
+
+	rc = gpio_tlmm_config(GPIO_CFG(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 0,
+		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		GPIO_CFG_ENABLE);
+
+	if (rc < 0) {
+		pr_err("%s:unable to enable lcd_camera_ldo_2v8!\n", __func__);
+		goto fail_gpio2;
+	}
+
+	/* LDO_EVT1V8 */
+	if (socinfo == 0x0B) {
+		if (gpio_request(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
+				"lcd_camera_ldo_1v8")) {
+			pr_err("failed to request gpio lcd_camera_ldo_1v8\n");
+			goto fail_gpio1;
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(SKU3_LCDC_LCD_CAMERA_LDO_1V8, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+
+		if (rc < 0) {
+			pr_err("%s: unable to enable lcdc_camera_ldo_1v8!\n",
+				__func__);
+			goto fail_gpio1;
+		}
+	} else if (socinfo == 0x0F || machine_is_msm8625_qrd7()) {
+		if (gpio_request(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+				"lcd_camera_ldo_1v8")) {
+			pr_err("failed to request gpio lcd_camera_ldo_1v8\n");
+			goto fail_gpio1;
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+			0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+
+		if (rc < 0) {
+			pr_err("%s: unable to enable lcdc_camera_ldo_1v8!\n",
+				__func__);
+			goto fail_gpio1;
+		}
+	}
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_truly_lcdc),
+			regs_truly_lcdc);
+	if (rc)
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_truly_lcdc),
+			regs_truly_lcdc);
+	if (rc)
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+
+	return;
+
+fail_gpio1:
+	if (socinfo == 0x0B)
+		gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_1V8);
+	else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+		gpio_free(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8);
+fail_gpio2:
+	gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_2V8);
+	return;
+}
+
+int sku3_lcdc_lcd_camera_power_onoff(int on)
+{
+	int rc = 0;
+	u32 socinfo = socinfo_get_platform_type();
+
+	if (on) {
+		if (socinfo == 0x0B)
+			gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
+				1);
+		else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+			gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+				1);
+
+		gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 1);
+
+		rc = regulator_bulk_enable(ARRAY_SIZE(regs_truly_lcdc),
+				regs_truly_lcdc);
+		if (rc)
+			pr_err("%s: could not enable regulators: %d\n",
+				__func__, rc);
+	} else {
+		if (socinfo == 0x0B)
+			gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
+				0);
+		else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+			gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+				0);
+
+		gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 0);
+
+		rc = regulator_bulk_disable(ARRAY_SIZE(regs_truly_lcdc),
+				regs_truly_lcdc);
+		if (rc)
+			pr_err("%s: could not disable regulators: %d\n",
+				__func__, rc);
+	}
+
+	return rc;
+}
+
+static int sku3_lcdc_power_save(int on)
+{
+	int rc = 0;
+
+	if (on) {
+		sku3_lcdc_lcd_camera_power_onoff(1);
+		rc = lcdc_truly_gpio_init();
+		if (rc < 0) {
+			pr_err("%s(): Truly GPIO initializations failed",
+				__func__);
+			return rc;
+		}
+
+		if (lcdc_truly_gpio_initialized) {
+			/*LCD reset*/
+			gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 1);
+			msleep(20);
+			gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 0);
+			msleep(20);
+			gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 1);
+			msleep(20);
+		}
+	} else {
+		/* pull down LCD IO to avoid current leakage */
+		gpio_set_value(SKU3_LCDC_GPIO_SPI_MOSI, 0);
+		gpio_set_value(SKU3_LCDC_GPIO_SPI_CLK, 0);
+		gpio_set_value(SKU3_LCDC_GPIO_SPI_CS0_N, 0);
+		gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 0);
+
+		sku3_lcdc_lcd_camera_power_onoff(0);
+	}
+	return rc;
+}
+
+static struct msm_panel_common_pdata lcdc_truly_panel_data = {
+	.panel_config_gpio = NULL,
+	.gpio_num	  = lcdc_truly_gpio_table,
+};
+
+static struct platform_device lcdc_truly_panel_device = {
+	.name   = "lcdc_truly_hvga_ips3p2335_pt",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &lcdc_truly_panel_data,
+	}
+};
+
 static struct regulator_bulk_data regs_lcdc[] = {
 	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
 	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
@@ -176,9 +421,21 @@
 	return ret;
 }
 
+
+static int msm_lcdc_power_save(int on)
+{
+	int rc = 0;
+	if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+		rc = sku3_lcdc_power_save(on);
+	else
+		rc = msm_fb_lcdc_power_save(on);
+
+	return rc;
+}
+
 static struct lcdc_platform_data lcdc_pdata = {
 	.lcdc_gpio_config = NULL,
-	.lcdc_power_save   = msm_fb_lcdc_power_save,
+	.lcdc_power_save   = msm_lcdc_power_save,
 };
 
 static int lcd_panel_spi_gpio_num[] = {
@@ -208,7 +465,14 @@
 	}
 };
 
-#define PANEL_NAME_MAX_LEN      30
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct resource msm_v4l2_video_overlay_resources[] = {
+	{
+		.flags = IORESOURCE_DMA,
+	}
+};
+#endif
+
 #define LCDC_TOSHIBA_FWVGA_PANEL_NAME   "lcdc_toshiba_fwvga_pt"
 #define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME       "mipi_cmd_renesas_fwvga"
 
@@ -216,7 +480,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 +491,10 @@
 	} 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_qrd3() || machine_is_msm8625_qrd7()) {
+		if (!strncmp(name, "lcdc_truly_hvga_ips3p2335_pt", 28))
+			ret = 0;
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		if (!strncmp(name, "mipi_cmd_nt35510_wvga", 21))
 			ret = 0;
 	}
@@ -235,7 +503,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)))
@@ -267,6 +536,16 @@
 	}
 };
 
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct platform_device msm_v4l2_video_overlay_device = {
+		.name   = "msm_v4l2_overlay_pd",
+		.id     = 0,
+		.num_resources  = ARRAY_SIZE(msm_v4l2_video_overlay_resources),
+		.resource       = msm_v4l2_video_overlay_resources,
+	};
+#endif
+
+
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 static int mipi_renesas_set_bl(int level)
 {
@@ -294,6 +573,93 @@
 };
 #endif
 
+static int evb_backlight_control(int level)
+{
+
+	int i = 0;
+	int remainder;
+	/* device address byte = 0x72 */
+	gpio_set_value_cansleep(96, 0);
+	udelay(67);
+	gpio_set_value_cansleep(96, 1);
+	udelay(33);
+	gpio_set_value_cansleep(96, 0);
+	udelay(33);
+	gpio_set_value_cansleep(96, 1);
+	udelay(67);
+	gpio_set_value_cansleep(96, 0);
+	udelay(33);
+	gpio_set_value_cansleep(96, 1);
+	udelay(67);
+	gpio_set_value_cansleep(96, 0);
+	udelay(33);
+	gpio_set_value_cansleep(96, 1);
+	udelay(67);
+	gpio_set_value_cansleep(96, 0);
+	udelay(67);
+	gpio_set_value_cansleep(96, 1);
+	udelay(33);
+	gpio_set_value_cansleep(96, 0);
+	udelay(67);
+	gpio_set_value_cansleep(96, 1);
+	udelay(33);
+	gpio_set_value_cansleep(96, 0);
+	udelay(33);
+	gpio_set_value_cansleep(96, 1);
+	udelay(67);
+	gpio_set_value_cansleep(96, 0);
+	udelay(67);
+	gpio_set_value_cansleep(96, 1);
+	udelay(33);
+
+	/* t-EOS and t-start */
+	gpio_set_value_cansleep(96, 0);
+	ndelay(4200);
+	gpio_set_value_cansleep(96, 1);
+	ndelay(9000);
+
+	/* data byte */
+	/* RFA = 0 */
+	gpio_set_value_cansleep(96, 0);
+	udelay(67);
+	gpio_set_value_cansleep(96, 1);
+	udelay(33);
+
+	/* Address bits */
+	gpio_set_value_cansleep(96, 0);
+	udelay(67);
+	gpio_set_value_cansleep(96, 1);
+	udelay(33);
+	gpio_set_value_cansleep(96, 0);
+	udelay(67);
+	gpio_set_value_cansleep(96, 1);
+	udelay(33);
+
+	/* Data bits */
+	for (i = 0; i < 5; i++) {
+		remainder = (level) & (16);
+		if (remainder) {
+			gpio_set_value_cansleep(96, 0);
+			udelay(33);
+			gpio_set_value_cansleep(96, 1);
+			udelay(67);
+		} else {
+			gpio_set_value_cansleep(96, 0);
+			udelay(67);
+			gpio_set_value_cansleep(96, 1);
+			udelay(33);
+		}
+		level = level << 1;
+	}
+
+	/* t-EOS */
+	gpio_set_value_cansleep(96, 0);
+	ndelay(12000);
+	gpio_set_value_cansleep(96, 1);
+	return 0;
+}
+
+
 static struct msm_panel_common_pdata mipi_truly_pdata = {
 	.pmic_backlight = mipi_truly_set_bl,
 };
@@ -307,7 +673,7 @@
 };
 
 static struct msm_panel_common_pdata mipi_NT35510_pdata = {
-	.pmic_backlight = NULL,/*mipi_NT35510_set_bl,*/
+	.pmic_backlight = evb_backlight_control,
 };
 
 static struct platform_device mipi_dsi_NT35510_panel_device = {
@@ -324,6 +690,9 @@
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 	&mipi_dsi_renesas_panel_device,
 #endif
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	&msm_v4l2_video_overlay_device,
+#endif
 };
 
 static struct platform_device *qrd_fb_devices[] __initdata = {
@@ -331,6 +700,11 @@
 	&mipi_dsi_truly_panel_device,
 };
 
+static struct platform_device *qrd3_fb_devices[] __initdata = {
+	&msm_fb_device,
+	&lcdc_truly_panel_device,
+};
+
 static struct platform_device *evb_fb_devices[] __initdata = {
 	&msm_fb_device,
 	&mipi_dsi_NT35510_panel_device,
@@ -350,6 +724,17 @@
 	msm_fb_resources[0].end = msm_fb_resources[0].start + fb_size - 1;
 	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", fb_size,
 						addr, __pa(addr));
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	fb_size = MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE;
+	addr = alloc_bootmem_align(fb_size, 0x1000);
+	msm_v4l2_video_overlay_resources[0].start = __pa(addr);
+	msm_v4l2_video_overlay_resources[0].end =
+		msm_v4l2_video_overlay_resources[0].start + fb_size - 1;
+	pr_debug("allocating %lu bytes at %p (%lx physical) for v4l2\n",
+		fb_size, addr, __pa(addr));
+#endif
+
 }
 
 static struct msm_panel_common_pdata mdp_pdata = {
@@ -427,7 +812,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));
 
@@ -533,19 +919,6 @@
 		return rc;
 	}
 
-	rc = gpio_tlmm_config(qrd3_mipi_dsi_gpio[0], GPIO_CFG_ENABLE);
-	if (rc < 0) {
-		pr_err("Failed to enable LCD Bridge reset enable\n");
-		return rc;
-	}
-
-	rc = gpio_direction_output(GPIO_QRD3_LCD_BRDG_RESET_N, 1);
-	if (rc < 0) {
-		pr_err("Failed GPIO bridge Reset\n");
-		gpio_free(GPIO_QRD3_LCD_BRDG_RESET_N);
-		return rc;
-	}
-
 	return rc;
 }
 
@@ -555,7 +928,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 +959,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 +999,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 +1024,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;
@@ -739,7 +1115,7 @@
 			return rc;
 
 		rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
-			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
 			GPIO_CFG_ENABLE);
 		if (rc < 0) {
 			pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
@@ -795,17 +1171,45 @@
 			qrd3_dsi_gpio_initialized = 1;
 	}
 
-	gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, !!on);
+	if (on) {
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+		udelay(190);
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 0);
+		udelay(286);
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+		/* 1 wire mode starts from this low to high transition */
+		udelay(50);
+	} else
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, !!on);
+
 	gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_2V85_EN, !!on);
 	gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_1V8_EN, !!on);
 
 	if (on) {
-		gpio_set_value_cansleep(GPIO_QRD3_LCD_BRDG_RESET_N, 1);
+		rc = gpio_tlmm_config(qrd3_mipi_dsi_gpio[0], GPIO_CFG_ENABLE);
+
+		if (rc < 0) {
+			pr_err("Failed to enable LCD Bridge reset enable\n");
+			return rc;
+		}
+
+		rc = gpio_direction_output(GPIO_QRD3_LCD_BRDG_RESET_N, 1);
+
+		if (rc < 0) {
+			pr_err("Failed GPIO bridge Reset\n");
+			gpio_free(GPIO_QRD3_LCD_BRDG_RESET_N);
+			return rc;
+		}
+
 		msleep(20);
 		gpio_set_value_cansleep(GPIO_QRD3_LCD_BRDG_RESET_N, 0);
 		msleep(20);
 		gpio_set_value_cansleep(GPIO_QRD3_LCD_BRDG_RESET_N, 1);
 		msleep(20);
+	} else {
+		gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BRDG_RESET_N, 0,
+			GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			GPIO_CFG_DISABLE);
 	}
 
 		return rc;
@@ -817,7 +1221,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);
@@ -826,7 +1230,7 @@
 
 #define MDP_303_VSYNC_GPIO 97
 
-#ifdef CONFIG_FB_MSM_MDP303
+#ifdef CONFIG_FB_MSM_MIPI_DSI
 static struct mipi_dsi_platform_data mipi_dsi_pdata = {
 	.vsync_gpio		= MDP_303_VSYNC_GPIO,
 	.dsi_power_save		= mipi_dsi_panel_power,
@@ -835,24 +1239,49 @@
 };
 #endif
 
+static char prim_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);
+
+void msm7x27a_set_display_params(char *prim_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);
+	}
+}
+
 void __init msm_fb_add_devices(void)
 {
+	msm7x27a_set_display_params(prim_panel_name);
 	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()) {
+		mipi_NT35510_pdata.bl_lock = 1;
 		platform_add_devices(evb_fb_devices,
 				ARRAY_SIZE(evb_fb_devices));
-	else if (machine_is_msm7627a_qrd3())
-		return;
-	else
+	} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+		sku3_lcdc_lcd_camera_power_init();
+		platform_add_devices(qrd3_fb_devices,
+						ARRAY_SIZE(qrd3_fb_devices));
+	} else
 		platform_add_devices(msm_fb_devices,
 				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() || machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7())
 		msm_fb_register_device("lcdc", &lcdc_pdata);
-#ifdef CONFIG_FB_MSM_MDP303
+#ifdef CONFIG_FB_MSM_MIPI_DSI
 	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
 #endif
 }
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
new file mode 100644
index 0000000..8a2f53a
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -0,0 +1,756 @@
+/* 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/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio_event.h>
+#include <linux/leds.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/i2c.h>
+#include <linux/input/rmi_platformdata.h>
+#include <linux/input/rmi_i2c.h>
+#include <linux/delay.h>
+#include <linux/atmel_maxtouch.h>
+#include <linux/input/ft5x06_ts.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/rpc_server_handset.h>
+
+#include "devices.h"
+#include "board-msm7627a.h"
+#include "devices-msm7x2xa.h"
+
+#define ATMEL_TS_I2C_NAME "maXTouch"
+#define ATMEL_X_OFFSET 13
+#define ATMEL_Y_OFFSET 0
+
+#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
+defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
+
+#ifndef CLEARPAD3000_ATTEN_GPIO
+#define CLEARPAD3000_ATTEN_GPIO (48)
+#endif
+
+#ifndef CLEARPAD3000_RESET_GPIO
+#define CLEARPAD3000_RESET_GPIO (26)
+#endif
+
+#define KP_INDEX(row, col) ((row)*ARRAY_SIZE(kp_col_gpios) + (col))
+
+static unsigned int kp_row_gpios[] = {31, 32, 33, 34, 35};
+static unsigned int kp_col_gpios[] = {36, 37, 38, 39, 40};
+
+static const unsigned short keymap[ARRAY_SIZE(kp_col_gpios) *
+					  ARRAY_SIZE(kp_row_gpios)] = {
+	[KP_INDEX(0, 0)] = KEY_7,
+	[KP_INDEX(0, 1)] = KEY_DOWN,
+	[KP_INDEX(0, 2)] = KEY_UP,
+	[KP_INDEX(0, 3)] = KEY_RIGHT,
+	[KP_INDEX(0, 4)] = KEY_ENTER,
+
+	[KP_INDEX(1, 0)] = KEY_LEFT,
+	[KP_INDEX(1, 1)] = KEY_SEND,
+	[KP_INDEX(1, 2)] = KEY_1,
+	[KP_INDEX(1, 3)] = KEY_4,
+	[KP_INDEX(1, 4)] = KEY_CLEAR,
+
+	[KP_INDEX(2, 0)] = KEY_6,
+	[KP_INDEX(2, 1)] = KEY_5,
+	[KP_INDEX(2, 2)] = KEY_8,
+	[KP_INDEX(2, 3)] = KEY_3,
+	[KP_INDEX(2, 4)] = KEY_NUMERIC_STAR,
+
+	[KP_INDEX(3, 0)] = KEY_9,
+	[KP_INDEX(3, 1)] = KEY_NUMERIC_POUND,
+	[KP_INDEX(3, 2)] = KEY_0,
+	[KP_INDEX(3, 3)] = KEY_2,
+	[KP_INDEX(3, 4)] = KEY_SLEEP,
+
+	[KP_INDEX(4, 0)] = KEY_BACK,
+	[KP_INDEX(4, 1)] = KEY_HOME,
+	[KP_INDEX(4, 2)] = KEY_MENU,
+	[KP_INDEX(4, 3)] = KEY_VOLUMEUP,
+	[KP_INDEX(4, 4)] = KEY_VOLUMEDOWN,
+};
+
+/* SURF keypad platform device information */
+static struct gpio_event_matrix_info kp_matrix_info = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= keymap,
+	.output_gpios	= kp_row_gpios,
+	.input_gpios	= kp_col_gpios,
+	.noutputs	= ARRAY_SIZE(kp_row_gpios),
+	.ninputs	= ARRAY_SIZE(kp_col_gpios),
+	.settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info[] = {
+	&kp_matrix_info.info
+};
+
+static struct gpio_event_platform_data kp_pdata = {
+	.name		= "7x27a_kp",
+	.info		= kp_info,
+	.info_count	= ARRAY_SIZE(kp_info)
+};
+
+static struct platform_device kp_pdev = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &kp_pdata,
+	},
+};
+
+/* 8625 keypad device information */
+static unsigned int kp_row_gpios_8625[] = {31};
+static unsigned int kp_col_gpios_8625[] = {36, 37};
+
+static const unsigned short keymap_8625[] = {
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_8625 = {
+	.info.func      = gpio_event_matrix_func,
+	.keymap         = keymap_8625,
+	.output_gpios   = kp_row_gpios_8625,
+	.input_gpios    = kp_col_gpios_8625,
+	.noutputs       = ARRAY_SIZE(kp_row_gpios_8625),
+	.ninputs        = ARRAY_SIZE(kp_col_gpios_8625),
+	.settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+	.flags          = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_8625[] = {
+	&kp_matrix_info_8625.info,
+};
+
+static struct gpio_event_platform_data kp_pdata_8625 = {
+	.name           = "7x27a_kp",
+	.info           = kp_info_8625,
+	.info_count     = ARRAY_SIZE(kp_info_8625)
+};
+
+static struct platform_device kp_pdev_8625 = {
+	.name   = GPIO_EVENT_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &kp_pdata_8625,
+	},
+};
+
+#define LED_GPIO_PDM 96
+#define LED_RED_GPIO_8625 49
+#define LED_GREEN_GPIO_8625 34
+
+static struct gpio_led gpio_leds_config_8625[] = {
+	{
+		.name = "green",
+		.gpio = LED_GREEN_GPIO_8625,
+	},
+	{
+		.name = "red",
+		.gpio = LED_RED_GPIO_8625,
+	},
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
+	.num_leds = ARRAY_SIZE(gpio_leds_config_8625),
+	.leds = gpio_leds_config_8625,
+};
+
+static struct platform_device gpio_leds_8625 = {
+	.name          = "leds-gpio",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &gpio_leds_pdata_8625,
+	},
+};
+
+#define MXT_TS_IRQ_GPIO         48
+#define MXT_TS_RESET_GPIO       26
+
+static const u8 mxt_config_data[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	16, 0, 0, 0, 0, 0, 0, 0,
+	/* T7 Object */
+	32, 16, 50,
+	/* T8 Object */
+	30, 0, 20, 20, 0, 0, 20, 0, 50, 0,
+	/* T9 Object */
+	3, 0, 0, 18, 11, 0, 32, 75, 3, 3,
+	0, 1, 1, 0, 10, 10, 10, 10, 31, 3,
+	223, 1, 11, 11, 15, 15, 151, 43, 145, 80,
+	100, 15, 0, 0, 0,
+	/* T15 Object */
+	131, 0, 11, 11, 1, 1, 0, 45, 3, 0,
+	0,
+	/* T18 Object */
+	0, 0,
+	/* T19 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0,
+	/* T23 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0,
+	/* T25 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	/* T46 Object */
+	0, 2, 32, 48, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	1, 20, 60, 5, 2, 50, 40, 0, 0, 40,
+	/* T48 Object */
+	1, 12, 80, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 6, 6, 0, 0, 100, 4, 64,
+	10, 0, 20, 5, 0, 38, 0, 20, 0, 0,
+	0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
+	10, 10, 10, 0, 0, 15, 15, 154, 58, 145,
+	80, 100, 15, 3,
+};
+
+static struct mxt_config_info mxt_config_array[] = {
+	{
+		.config		= mxt_config_data,
+		.config_length	= ARRAY_SIZE(mxt_config_data),
+		.family_id	= 0x81,
+		.variant_id	= 0x01,
+		.version	= 0x10,
+		.build		= 0xAA,
+	},
+};
+
+static int mxt_key_codes[MXT_KEYARRAY_MAX_KEYS] = {
+	[0] = KEY_HOME,
+	[1] = KEY_MENU,
+	[9] = KEY_BACK,
+	[10] = KEY_SEARCH,
+};
+
+static struct mxt_platform_data mxt_platform_data = {
+	.config_array		= mxt_config_array,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array),
+	.panel_minx		= 0,
+	.panel_maxx		= 479,
+	.panel_miny		= 0,
+	.panel_maxy		= 799,
+	.disp_minx		= 0,
+	.disp_maxx		= 479,
+	.disp_miny		= 0,
+	.disp_maxy		= 799,
+	.irqflags		= IRQF_TRIGGER_FALLING,
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_IRQ_GPIO,
+	.key_codes		= mxt_key_codes,
+};
+
+static struct i2c_board_info mxt_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
+		.platform_data = &mxt_platform_data,
+		.irq = MSM_GPIO_TO_INT(MXT_TS_IRQ_GPIO),
+	},
+};
+
+static int synaptics_touchpad_setup(void);
+
+static struct msm_gpio clearpad3000_cfg_data[] = {
+	{GPIO_CFG(CLEARPAD3000_ATTEN_GPIO, 0, GPIO_CFG_INPUT,
+			GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "rmi4_attn"},
+	{GPIO_CFG(CLEARPAD3000_RESET_GPIO, 0, GPIO_CFG_OUTPUT,
+			GPIO_CFG_PULL_DOWN, GPIO_CFG_8MA), "rmi4_reset"},
+};
+
+static struct rmi_XY_pair rmi_offset = {.x = 0, .y = 0};
+static struct rmi_range rmi_clipx = {.min = 48, .max = 980};
+static struct rmi_range rmi_clipy = {.min = 7, .max = 1647};
+static struct rmi_f11_functiondata synaptics_f11_data = {
+	.swap_axes = false,
+	.flipX = false,
+	.flipY = false,
+	.offset = &rmi_offset,
+	.button_height = 113,
+	.clipX = &rmi_clipx,
+	.clipY = &rmi_clipy,
+};
+
+#define MAX_LEN		100
+
+static ssize_t clearpad3000_virtual_keys_register(struct kobject *kobj,
+		     struct kobj_attribute *attr, char *buf)
+{
+	char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
+			     ":60:830:120:60" ":" __stringify(EV_KEY) \
+			     ":" __stringify(KEY_HOME)   ":180:830:120:60" \
+				":" __stringify(EV_KEY) ":" \
+				__stringify(KEY_SEARCH) ":300:830:120:60" \
+				":" __stringify(EV_KEY) ":" \
+			__stringify(KEY_BACK)   ":420:830:120:60" "\n";
+
+	return snprintf(buf, strnlen(virtual_keys, MAX_LEN) + 1 , "%s",
+			virtual_keys);
+}
+
+static struct kobj_attribute clearpad3000_virtual_keys_attr = {
+	.attr = {
+		.name = "virtualkeys.sensor00fn11",
+		.mode = S_IRUGO,
+	},
+	.show = &clearpad3000_virtual_keys_register,
+};
+
+static struct attribute *virtual_key_properties_attrs[] = {
+	&clearpad3000_virtual_keys_attr.attr,
+	NULL
+};
+
+static struct attribute_group virtual_key_properties_attr_group = {
+	.attrs = virtual_key_properties_attrs,
+};
+
+struct kobject *virtual_key_properties_kobj;
+
+static struct rmi_functiondata synaptics_functiondata[] = {
+	{
+		.function_index = RMI_F11_INDEX,
+		.data = &synaptics_f11_data,
+	},
+};
+
+static struct rmi_functiondata_list synaptics_perfunctiondata = {
+	.count = ARRAY_SIZE(synaptics_functiondata),
+	.functiondata = synaptics_functiondata,
+};
+
+static struct rmi_sensordata synaptics_sensordata = {
+	.perfunctiondata = &synaptics_perfunctiondata,
+	.rmi_sensor_setup	= synaptics_touchpad_setup,
+};
+
+static struct rmi_i2c_platformdata synaptics_platformdata = {
+	.i2c_address = 0x2c,
+	.irq_type = IORESOURCE_IRQ_LOWLEVEL,
+	.sensordata = &synaptics_sensordata,
+};
+
+static struct i2c_board_info synaptic_i2c_clearpad3k[] = {
+	{
+	I2C_BOARD_INFO("rmi4_ts", 0x2c),
+	.platform_data = &synaptics_platformdata,
+	},
+};
+
+static int synaptics_touchpad_setup(void)
+{
+	int retval = 0;
+
+	virtual_key_properties_kobj =
+		kobject_create_and_add("board_properties", NULL);
+	if (virtual_key_properties_kobj)
+		retval = sysfs_create_group(virtual_key_properties_kobj,
+				&virtual_key_properties_attr_group);
+	if (!virtual_key_properties_kobj || retval)
+		pr_err("failed to create ft5202 board_properties\n");
+
+	retval = msm_gpios_request_enable(clearpad3000_cfg_data,
+		    sizeof(clearpad3000_cfg_data)/sizeof(struct msm_gpio));
+	if (retval) {
+		pr_err("%s:Failed to obtain touchpad GPIO %d. Code: %d.",
+				__func__, CLEARPAD3000_ATTEN_GPIO, retval);
+		retval = 0; /* ignore the err */
+	}
+	synaptics_platformdata.irq = gpio_to_irq(CLEARPAD3000_ATTEN_GPIO);
+
+	gpio_set_value(CLEARPAD3000_RESET_GPIO, 0);
+	usleep(10000);
+	gpio_set_value(CLEARPAD3000_RESET_GPIO, 1);
+	usleep(50000);
+
+	return retval;
+}
+#endif
+
+static struct regulator_bulk_data regs_atmel[] = {
+	{ .supply = "ldo2",  .min_uV = 2850000, .max_uV = 2850000 },
+	{ .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+#define ATMEL_TS_GPIO_IRQ 82
+
+static int atmel_ts_power_on(bool on)
+{
+	int rc = on ?
+		regulator_bulk_enable(ARRAY_SIZE(regs_atmel), regs_atmel) :
+		regulator_bulk_disable(ARRAY_SIZE(regs_atmel), regs_atmel);
+
+	if (rc)
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, on ? "en" : "dis", rc);
+	else
+		msleep(50);
+
+	return rc;
+}
+
+static int atmel_ts_platform_init(struct i2c_client *client)
+{
+	int rc;
+	struct device *dev = &client->dev;
+
+	rc = regulator_bulk_get(dev, ARRAY_SIZE(regs_atmel), regs_atmel);
+	if (rc) {
+		dev_err(dev, "%s: could not get regulators: %d\n",
+				__func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_atmel), regs_atmel);
+	if (rc) {
+		dev_err(dev, "%s: could not set voltages: %d\n",
+				__func__, rc);
+		goto reg_free;
+	}
+
+	rc = gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+				GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+	if (rc) {
+		dev_err(dev, "%s: gpio_tlmm_config for %d failed\n",
+			__func__, ATMEL_TS_GPIO_IRQ);
+		goto reg_free;
+	}
+
+	/* configure touchscreen interrupt gpio */
+	rc = gpio_request(ATMEL_TS_GPIO_IRQ, "atmel_maxtouch_gpio");
+	if (rc) {
+		dev_err(dev, "%s: unable to request gpio %d\n",
+			__func__, ATMEL_TS_GPIO_IRQ);
+		goto ts_gpio_tlmm_unconfig;
+	}
+
+	rc = gpio_direction_input(ATMEL_TS_GPIO_IRQ);
+	if (rc < 0) {
+		dev_err(dev, "%s: unable to set the direction of gpio %d\n",
+			__func__, ATMEL_TS_GPIO_IRQ);
+		goto free_ts_gpio;
+	}
+	return 0;
+
+free_ts_gpio:
+	gpio_free(ATMEL_TS_GPIO_IRQ);
+ts_gpio_tlmm_unconfig:
+	gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+				GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_DISABLE);
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
+out:
+	return rc;
+}
+
+static int atmel_ts_platform_exit(struct i2c_client *client)
+{
+	gpio_free(ATMEL_TS_GPIO_IRQ);
+	gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+				GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_DISABLE);
+	regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
+	return 0;
+}
+
+static u8 atmel_ts_read_chg(void)
+{
+	return gpio_get_value(ATMEL_TS_GPIO_IRQ);
+}
+
+static u8 atmel_ts_valid_interrupt(void)
+{
+	return !atmel_ts_read_chg();
+}
+
+
+static struct maxtouch_platform_data atmel_ts_pdata = {
+	.numtouch = 4,
+	.init_platform_hw = atmel_ts_platform_init,
+	.exit_platform_hw = atmel_ts_platform_exit,
+	.power_on = atmel_ts_power_on,
+	.display_res_x = 480,
+	.display_res_y = 864,
+	.min_x = ATMEL_X_OFFSET,
+	.max_x = (505 - ATMEL_X_OFFSET),
+	.min_y = ATMEL_Y_OFFSET,
+	.max_y = (863 - ATMEL_Y_OFFSET),
+	.valid_interrupt = atmel_ts_valid_interrupt,
+	.read_chg = atmel_ts_read_chg,
+};
+
+static struct i2c_board_info atmel_ts_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(ATMEL_TS_I2C_NAME, 0x4a),
+		.platform_data = &atmel_ts_pdata,
+		.irq = MSM_GPIO_TO_INT(ATMEL_TS_GPIO_IRQ),
+	},
+};
+
+static struct msm_handset_platform_data hs_platform_data = {
+	.hs_name = "7k_handset",
+	.pwr_key_delay_ms = 500, /* 0 will disable end key */
+};
+
+static struct platform_device hs_pdev = {
+	.name   = "msm-handset",
+	.id     = -1,
+	.dev    = {
+		.platform_data = &hs_platform_data,
+	},
+};
+
+#define FT5X06_IRQ_GPIO		48
+#define FT5X06_RESET_GPIO	26
+
+static ssize_t
+ft5x06_virtual_keys_register(struct kobject *kobj,
+			     struct kobj_attribute *attr,
+			     char *buf)
+{
+	return snprintf(buf, 200,
+	__stringify(EV_KEY) ":" __stringify(KEY_MENU)  ":40:510:80:60"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME)   ":120:510:80:60"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":200:510:80:60"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_BACK)   ":280:510:80:60"
+	"\n");
+}
+
+static struct kobj_attribute ft5x06_virtual_keys_attr = {
+	.attr = {
+		.name = "virtualkeys.ft5x06_ts",
+		.mode = S_IRUGO,
+	},
+	.show = &ft5x06_virtual_keys_register,
+};
+
+static struct attribute *ft5x06_virtual_key_properties_attrs[] = {
+	&ft5x06_virtual_keys_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ft5x06_virtual_key_properties_attr_group = {
+	.attrs = ft5x06_virtual_key_properties_attrs,
+};
+
+struct kobject *ft5x06_virtual_key_properties_kobj;
+
+static struct ft5x06_ts_platform_data ft5x06_platformdata = {
+	.x_max		= 320,
+	.y_max		= 480,
+	.reset_gpio	= FT5X06_RESET_GPIO,
+	.irq_gpio	= FT5X06_IRQ_GPIO,
+	.irqflags	= IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+};
+
+static struct i2c_board_info ft5x06_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("ft5x06_ts", 0x38),
+		.platform_data = &ft5x06_platformdata,
+		.irq = MSM_GPIO_TO_INT(FT5X06_IRQ_GPIO),
+	},
+};
+
+static void ft5x06_touchpad_setup(void)
+{
+	int rc;
+
+	rc = gpio_tlmm_config(GPIO_CFG(FT5X06_IRQ_GPIO, 0,
+			GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+			GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+	if (rc)
+		pr_err("%s: gpio_tlmm_config for %d failed\n",
+			__func__, FT5X06_IRQ_GPIO);
+
+	rc = gpio_tlmm_config(GPIO_CFG(FT5X06_RESET_GPIO, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+			GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+	if (rc)
+		pr_err("%s: gpio_tlmm_config for %d failed\n",
+			__func__, FT5X06_RESET_GPIO);
+
+	ft5x06_virtual_key_properties_kobj =
+			kobject_create_and_add("board_properties", NULL);
+
+	if (ft5x06_virtual_key_properties_kobj)
+		rc = sysfs_create_group(ft5x06_virtual_key_properties_kobj,
+				&ft5x06_virtual_key_properties_attr_group);
+
+	if (!ft5x06_virtual_key_properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n", __func__);
+
+	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+				ft5x06_device_info,
+				ARRAY_SIZE(ft5x06_device_info));
+}
+
+/* SKU3/SKU7 keypad device information */
+#define KP_INDEX_SKU3(row, col) ((row)*ARRAY_SIZE(kp_col_gpios_sku3) + (col))
+static unsigned int kp_row_gpios_sku3[] = {31, 32};
+static unsigned int kp_col_gpios_sku3[] = {36, 37};
+
+static const unsigned short keymap_sku3[] = {
+	[KP_INDEX_SKU3(0, 0)] = KEY_VOLUMEUP,
+	[KP_INDEX_SKU3(0, 1)] = KEY_VOLUMEDOWN,
+	[KP_INDEX_SKU3(1, 1)] = KEY_CAMERA,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_sku3 = {
+	.info.func      = gpio_event_matrix_func,
+	.keymap         = keymap_sku3,
+	.output_gpios   = kp_row_gpios_sku3,
+	.input_gpios    = kp_col_gpios_sku3,
+	.noutputs       = ARRAY_SIZE(kp_row_gpios_sku3),
+	.ninputs        = ARRAY_SIZE(kp_col_gpios_sku3),
+	.settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+	.flags          = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+				GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_sku3[] = {
+	&kp_matrix_info_sku3.info,
+};
+static struct gpio_event_platform_data kp_pdata_sku3 = {
+	.name           = "7x27a_kp",
+	.info           = kp_info_sku3,
+	.info_count     = ARRAY_SIZE(kp_info_sku3)
+};
+
+static struct platform_device kp_pdev_sku3 = {
+	.name   = GPIO_EVENT_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &kp_pdata_sku3,
+	},
+};
+
+void __init msm7627a_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;
+		atmel_ts_pdata.min_y = 0;
+		atmel_ts_pdata.max_y = 320;
+	}
+
+	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+				atmel_ts_i2c_info,
+				ARRAY_SIZE(atmel_ts_i2c_info));
+	/* keypad */
+	platform_device_register(&kp_pdev);
+
+	/* headset */
+	platform_device_register(&hs_pdev);
+
+	/* 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))
+		pr_err("%s: gpio_tlmm_config for %d failed\n",
+			__func__, LED_GPIO_PDM);
+	else
+		platform_device_register(&led_pdev);
+
+	/* Vibrator */
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
+		msm_init_pmic_vibrator();
+}
+
+void __init qrd7627a_add_io_devices(void)
+{
+	int rc;
+
+	/* touchscreen */
+	if (machine_is_msm7627a_qrd1()) {
+		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+					synaptic_i2c_clearpad3k,
+					ARRAY_SIZE(synaptic_i2c_clearpad3k));
+	} 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);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, MXT_TS_IRQ_GPIO);
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_RESET_GPIO, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, MXT_TS_RESET_GPIO);
+		}
+
+		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+					mxt_device_info,
+					ARRAY_SIZE(mxt_device_info));
+	} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+		ft5x06_touchpad_setup();
+	}
+
+	/* headset */
+	platform_device_register(&hs_pdev);
+
+	/* vibrator */
+#ifdef CONFIG_MSM_RPC_VIBRATOR
+	msm_init_pmic_vibrator();
+#endif
+
+	/* keypad */
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+		platform_device_register(&kp_pdev_8625);
+	else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+		platform_device_register(&kp_pdev_sku3);
+
+	/* leds */
+	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);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, LED_RED_GPIO_8625);
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, LED_GREEN_GPIO_8625);
+		}
+
+		platform_device_register(&gpio_leds_8625);
+	}
+}
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index a10d81a..564c59d 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -19,6 +19,7 @@
 #include <mach/board.h>
 
 #include "devices.h"
+#include "pm.h"
 #include "board-msm7627a.h"
 
 #if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
@@ -26,6 +27,7 @@
 	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
 	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
 
+#define MAX_SDCC_CONTROLLER 4
 static unsigned long vreg_sts, gpio_sts;
 
 struct sdcc_gpio {
@@ -148,11 +150,14 @@
 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()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7())
 		gpio_sdc1_hw_det = 42;
 }
 
-static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
+static struct regulator *sdcc_vreg_data[MAX_SDCC_CONTROLLER];
 static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
 {
 	int rc = 0;
@@ -249,7 +254,10 @@
 		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()  ||
+					machine_is_msm7627a_qrd3() ||
+					machine_is_msm8625_qrd7())
 				status = !gpio_get_value(gpio_sdc1_hw_det);
 			else
 				status = gpio_get_value(gpio_sdc1_hw_det);
@@ -363,9 +371,15 @@
 {
 	/* eMMC slot */
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
-	if (mmc_regulator_init(3, "emmc", 3000000))
-		return;
-	msm_add_sdcc(3, &sdc3_plat_data);
+
+	/* There is no eMMC on SDC3 for QRD3 based devices */
+	if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
+		if (mmc_regulator_init(3, "emmc", 3000000))
+			return;
+		sdc3_plat_data.swfi_latency = msm7627a_power_collapse_latency(
+			MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
+		msm_add_sdcc(3, &sdc3_plat_data);
+	}
 #endif
 	/* Micro-SD slot */
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
@@ -373,20 +387,25 @@
 	if (mmc_regulator_init(1, "mmc", 2850000))
 		return;
 	sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+	sdc1_plat_data.swfi_latency = msm7627a_power_collapse_latency(
+			MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
 	msm_add_sdcc(1, &sdc1_plat_data);
 #endif
 	/* SDIO WLAN slot */
 #ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-	if (mmc_regulator_init(2, "mmc", 2850000))
+	if (mmc_regulator_init(2, "smps3", 1800000))
 		return;
 	msm_add_sdcc(2, &sdc2_plat_data);
 #endif
 	/* Not Used */
 #if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
 		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
-	if (mmc_regulator_init(4, "mmc", 2850000))
-		return;
-	msm_add_sdcc(4, &sdc4_plat_data);
+	/* There is no SDC4 for QRD3/7 based devices */
+	if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
+		if (mmc_regulator_init(4, "smps3", 1800000))
+			return;
+		msm_add_sdcc(4, &sdc4_plat_data);
+	}
 #endif
 }
 #endif
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 6df7626..b72ecd4 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -48,7 +48,10 @@
 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()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7())
 		gpio_wlan_sys_rest_en = 124;
 }
 
@@ -229,7 +232,10 @@
 	 * 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()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7()) {
 		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 +308,10 @@
 	 * 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()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7()) {
 		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 b0481a0..68e333f 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -13,6 +13,7 @@
 #ifndef __ARCH_ARM_MACH_MSM_BOARD_7627A__
 #define __ARCH_ARM_MACH_MSM_BOARD_7627A__
 
+#include "pm.h"
 void __init msm7627a_init_mmc(void);
 
 void __init msm_msm7627a_allocate_memory_regions(void);
@@ -65,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
@@ -97,11 +99,12 @@
 	struct regulator *reg;
 };
 
-extern struct platform_device msm_bt_power_device;
-
 void __init msm7627a_bt_power_init(void);
 #endif
 
 void __init msm7627a_camera_init(void);
+u32 msm7627a_power_collapse_latency(enum msm_pm_sleep_mode);
 
+void __init msm7627a_add_io_devices(void);
+void __init qrd7627a_add_io_devices(void);
 #endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d5d8edc..34ae4c8 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -92,6 +92,7 @@
 
 #define PMEM_KERNEL_EBI1_SIZE	0x1C000
 #endif
+#define ADSP_RPC_PROG           0x3000000a
 
 static struct resource smc91x_resources[] = {
 	[0] = {
@@ -1731,6 +1732,25 @@
 	}
 }
 
+static void msm_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;
+	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 msm7x2x_init(void)
 {
 
@@ -1797,6 +1817,7 @@
 #ifdef CONFIG_MSM_CAMERA
 	config_camera_off_gpios(); /* might not be necessary */
 #endif
+	msm_adsp_add_pdev();
 	msm_device_i2c_init();
 	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
 
diff --git a/arch/arm/mach-msm/board-msm7x27a-regulator.c b/arch/arm/mach-msm/board-msm7x27a-regulator.c
index 5be382f..469c543 100644
--- a/arch/arm/mach-msm/board-msm7x27a-regulator.c
+++ b/arch/arm/mach-msm/board-msm7x27a-regulator.c
@@ -85,6 +85,7 @@
 	REGULATOR_SUPPLY("smps3",	NULL),
 	REGULATOR_SUPPLY("msme1",	NULL),
 	REGULATOR_SUPPLY("vcc_i2c",	"1-004a"),
+	REGULATOR_SUPPLY("vcc_i2c",	"1-0038"),
 };
 
 PCOM_VREG_CONSUMERS(smps4) = {
@@ -160,6 +161,7 @@
 	REGULATOR_SUPPLY("ldo12",	NULL),
 	REGULATOR_SUPPLY("gp2",		NULL),
 	REGULATOR_SUPPLY("vdd_ana",	"1-004a"),
+	REGULATOR_SUPPLY("vdd",		"1-0038"),
 };
 
 PCOM_VREG_CONSUMERS(ldo13) = {
@@ -215,7 +217,7 @@
 	PCOM_VREG_SMP(smps2,  4, NULL, 1100000, 1100000, 0, -1, 0, 0, 0, 0, s),
 	PCOM_VREG_SMP(smps3,  2, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0, s),
 	PCOM_VREG_SMP(smps4, 24, NULL, 2100000, 2100000, 0, -1, 0, 0, 0, 0, s),
-	PCOM_VREG_LDO(ldo01, 12, NULL, 2100000, 2100000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo01, 12, NULL, 1800000, 2100000, 0, -1, 0, 0, 0, 0, p),
 	PCOM_VREG_LDO(ldo02, 13, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0, p),
 	PCOM_VREG_LDO(ldo03, 49, NULL, 1200000, 1200000, 0, -1, 0, 0, 0, 0, n),
 	PCOM_VREG_LDO(ldo04, 50, NULL, 1100000, 1100000, 0, -1, 0, 0, 0, 0, n),
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index a6b29dc..09f44a7 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>
@@ -93,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 =
@@ -153,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
@@ -361,11 +359,97 @@
 	},
 };
 
+u32 msm7627a_power_collapse_latency(enum msm_pm_sleep_mode mode)
+{
+	switch (mode) {
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		return msm7x27a_pm_data
+		[MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN:
+		return msm7x27a_pm_data
+		[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency;
+	case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
+		return msm7x27a_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		return msm7x27a_pm_data
+		[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
+	default:
+		return 0;
+	}
+}
+
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
 	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
 	.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,
@@ -503,7 +587,8 @@
 
 	/* Concurrency 6 */
 	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	0, 0, 0, 0,
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	0, 0, 0,
 
 	/* Concurrency 7 */
 	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
@@ -697,37 +782,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;
@@ -849,21 +948,25 @@
 
 static void __init msm8625_reserve(void)
 {
+	msm7x27a_reserve();
 	memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+	memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
 }
 
-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
 
@@ -878,7 +981,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);
@@ -898,215 +1001,6 @@
 	iounmap(ebi2_cfg_ptr);
 }
 
-#define ATMEL_TS_I2C_NAME "maXTouch"
-
-static struct regulator_bulk_data regs_atmel[] = {
-	{ .supply = "ldo2",  .min_uV = 2850000, .max_uV = 2850000 },
-	{ .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
-};
-
-#define ATMEL_TS_GPIO_IRQ 82
-
-static int atmel_ts_power_on(bool on)
-{
-	int rc = on ?
-		regulator_bulk_enable(ARRAY_SIZE(regs_atmel), regs_atmel) :
-		regulator_bulk_disable(ARRAY_SIZE(regs_atmel), regs_atmel);
-
-	if (rc)
-		pr_err("%s: could not %sable regulators: %d\n",
-				__func__, on ? "en" : "dis", rc);
-	else
-		msleep(50);
-
-	return rc;
-}
-
-static int atmel_ts_platform_init(struct i2c_client *client)
-{
-	int rc;
-	struct device *dev = &client->dev;
-
-	rc = regulator_bulk_get(dev, ARRAY_SIZE(regs_atmel), regs_atmel);
-	if (rc) {
-		dev_err(dev, "%s: could not get regulators: %d\n",
-				__func__, rc);
-		goto out;
-	}
-
-	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_atmel), regs_atmel);
-	if (rc) {
-		dev_err(dev, "%s: could not set voltages: %d\n",
-				__func__, rc);
-		goto reg_free;
-	}
-
-	rc = gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
-				GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
-				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
-	if (rc) {
-		dev_err(dev, "%s: gpio_tlmm_config for %d failed\n",
-			__func__, ATMEL_TS_GPIO_IRQ);
-		goto reg_free;
-	}
-
-	/* configure touchscreen interrupt gpio */
-	rc = gpio_request(ATMEL_TS_GPIO_IRQ, "atmel_maxtouch_gpio");
-	if (rc) {
-		dev_err(dev, "%s: unable to request gpio %d\n",
-			__func__, ATMEL_TS_GPIO_IRQ);
-		goto ts_gpio_tlmm_unconfig;
-	}
-
-	rc = gpio_direction_input(ATMEL_TS_GPIO_IRQ);
-	if (rc < 0) {
-		dev_err(dev, "%s: unable to set the direction of gpio %d\n",
-			__func__, ATMEL_TS_GPIO_IRQ);
-		goto free_ts_gpio;
-	}
-	return 0;
-
-free_ts_gpio:
-	gpio_free(ATMEL_TS_GPIO_IRQ);
-ts_gpio_tlmm_unconfig:
-	gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
-				GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
-				GPIO_CFG_2MA), GPIO_CFG_DISABLE);
-reg_free:
-	regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
-out:
-	return rc;
-}
-
-static int atmel_ts_platform_exit(struct i2c_client *client)
-{
-	gpio_free(ATMEL_TS_GPIO_IRQ);
-	gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
-				GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
-				GPIO_CFG_2MA), GPIO_CFG_DISABLE);
-	regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
-	return 0;
-}
-
-static u8 atmel_ts_read_chg(void)
-{
-	return gpio_get_value(ATMEL_TS_GPIO_IRQ);
-}
-
-static u8 atmel_ts_valid_interrupt(void)
-{
-	return !atmel_ts_read_chg();
-}
-
-#define ATMEL_X_OFFSET 13
-#define ATMEL_Y_OFFSET 0
-
-static struct maxtouch_platform_data atmel_ts_pdata = {
-	.numtouch = 4,
-	.init_platform_hw = atmel_ts_platform_init,
-	.exit_platform_hw = atmel_ts_platform_exit,
-	.power_on = atmel_ts_power_on,
-	.display_res_x = 480,
-	.display_res_y = 864,
-	.min_x = ATMEL_X_OFFSET,
-	.max_x = (505 - ATMEL_X_OFFSET),
-	.min_y = ATMEL_Y_OFFSET,
-	.max_y = (863 - ATMEL_Y_OFFSET),
-	.valid_interrupt = atmel_ts_valid_interrupt,
-	.read_chg = atmel_ts_read_chg,
-};
-
-static struct i2c_board_info atmel_ts_i2c_info[] __initdata = {
-	{
-		I2C_BOARD_INFO(ATMEL_TS_I2C_NAME, 0x4a),
-		.platform_data = &atmel_ts_pdata,
-		.irq = MSM_GPIO_TO_INT(ATMEL_TS_GPIO_IRQ),
-	},
-};
-
-#define KP_INDEX(row, col) ((row)*ARRAY_SIZE(kp_col_gpios) + (col))
-
-static unsigned int kp_row_gpios[] = {31, 32, 33, 34, 35};
-static unsigned int kp_col_gpios[] = {36, 37, 38, 39, 40};
-
-static const unsigned short keymap[ARRAY_SIZE(kp_col_gpios) *
-					  ARRAY_SIZE(kp_row_gpios)] = {
-	[KP_INDEX(0, 0)] = KEY_7,
-	[KP_INDEX(0, 1)] = KEY_DOWN,
-	[KP_INDEX(0, 2)] = KEY_UP,
-	[KP_INDEX(0, 3)] = KEY_RIGHT,
-	[KP_INDEX(0, 4)] = KEY_ENTER,
-
-	[KP_INDEX(1, 0)] = KEY_LEFT,
-	[KP_INDEX(1, 1)] = KEY_SEND,
-	[KP_INDEX(1, 2)] = KEY_1,
-	[KP_INDEX(1, 3)] = KEY_4,
-	[KP_INDEX(1, 4)] = KEY_CLEAR,
-
-	[KP_INDEX(2, 0)] = KEY_6,
-	[KP_INDEX(2, 1)] = KEY_5,
-	[KP_INDEX(2, 2)] = KEY_8,
-	[KP_INDEX(2, 3)] = KEY_3,
-	[KP_INDEX(2, 4)] = KEY_NUMERIC_STAR,
-
-	[KP_INDEX(3, 0)] = KEY_9,
-	[KP_INDEX(3, 1)] = KEY_NUMERIC_POUND,
-	[KP_INDEX(3, 2)] = KEY_0,
-	[KP_INDEX(3, 3)] = KEY_2,
-	[KP_INDEX(3, 4)] = KEY_SLEEP,
-
-	[KP_INDEX(4, 0)] = KEY_BACK,
-	[KP_INDEX(4, 1)] = KEY_HOME,
-	[KP_INDEX(4, 2)] = KEY_MENU,
-	[KP_INDEX(4, 3)] = KEY_VOLUMEUP,
-	[KP_INDEX(4, 4)] = KEY_VOLUMEDOWN,
-};
-
-/* SURF keypad platform device information */
-static struct gpio_event_matrix_info kp_matrix_info = {
-	.info.func	= gpio_event_matrix_func,
-	.keymap		= keymap,
-	.output_gpios	= kp_row_gpios,
-	.input_gpios	= kp_col_gpios,
-	.noutputs	= ARRAY_SIZE(kp_row_gpios),
-	.ninputs	= ARRAY_SIZE(kp_col_gpios),
-	.settle_time.tv_nsec = 40 * NSEC_PER_USEC,
-	.poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
-	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
-			  GPIOKPF_PRINT_UNMAPPED_KEYS,
-};
-
-static struct gpio_event_info *kp_info[] = {
-	&kp_matrix_info.info
-};
-
-static struct gpio_event_platform_data kp_pdata = {
-	.name		= "7x27a_kp",
-	.info		= kp_info,
-	.info_count	= ARRAY_SIZE(kp_info)
-};
-
-static struct platform_device kp_pdev = {
-	.name	= GPIO_EVENT_DEV_NAME,
-	.id	= -1,
-	.dev	= {
-		.platform_data	= &kp_pdata,
-	},
-};
-
-static struct msm_handset_platform_data hs_platform_data = {
-	.hs_name = "7k_handset",
-	.pwr_key_delay_ms = 500, /* 0 will disable end key */
-};
-
-static struct platform_device hs_pdev = {
-	.name   = "msm-handset",
-	.id     = -1,
-	.dev    = {
-		.platform_data = &hs_platform_data,
-	},
-};
-
 static struct platform_device msm_proccomm_regulator_dev = {
 	.name   = PROCCOMM_REGULATOR_DEV_NAME,
 	.id     = -1,
@@ -1115,6 +1009,29 @@
 	}
 };
 
+static void msm_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_rumi3_init(void)
 {
 	msm7x27a_init_ebi2();
@@ -1125,12 +1042,17 @@
 static void __init msm8625_rumi3_init(void)
 {
 	msm7x2x_misc_init();
-	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
 #define UART1DM_RX_GPIO		45
 
 #if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
@@ -1151,87 +1073,102 @@
 				__func__, rc);
 }
 
+static void __init msm7x27a_add_footswitch_devices(void)
+{
+	platform_add_devices(msm_footswitch_devices,
+			msm_num_footswitch_devices);
+}
+
+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));
+	}
+
+	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_pm_init(void)
+{
+	if (machine_is_msm8625_surf()) {
+		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();
+	} else {
+		msm_pm_set_platform_data(msm7x27a_pm_data,
+				ARRAY_SIZE(msm7x27a_pm_data));
+		BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	}
+
+	msm_pm_register_irqs();
+}
+
 static void __init msm7x2x_init(void)
 {
 	msm7x2x_misc_init();
 
 	/* Initialize regulators first so that other devices can use them */
 	msm7x27a_init_regulators();
-
-	/* Common functions for SURF/FFA/RUMI3 */
-	msm_device_i2c_init();
+	msm_adsp_add_pdev();
+	if (cpu_is_msm8625())
+		msm8625_device_i2c_init();
+	else
+		msm7x27a_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
+	msm7x27a_uartdm_config();
 
-#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_otg_gadget();
 	msm7x27a_cfg_smsc911x();
-	platform_add_devices(msm_footswitch_devices,
-			msm_num_footswitch_devices);
-	platform_add_devices(surf_ffa_devices,
-			ARRAY_SIZE(surf_ffa_devices));
+
+	msm7x27a_add_footswitch_devices();
+	msm7x27a_add_platform_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));
-
-#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
+	msm7x27a_pm_init();
 	register_i2c_devices();
-#endif
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
 	msm7627a_bt_power_init();
-#endif
-	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
-		atmel_ts_pdata.min_x = 0;
-		atmel_ts_pdata.max_x = 480;
-		atmel_ts_pdata.min_y = 0;
-		atmel_ts_pdata.max_y = 320;
-	}
-
-	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
-	platform_device_register(&kp_pdev);
-	platform_device_register(&hs_pdev);
-
-	/* 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))
-		pr_err("%s: gpio_tlmm_config for %d failed\n",
-			__func__, LED_GPIO_PDM);
-	else
-		platform_device_register(&led_pdev);
-
-#ifdef CONFIG_MSM_RPC_VIBRATOR
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_init_pmic_vibrator();
-#endif
+	msm7627a_add_io_devices();
 	/*7x25a kgsl initializations*/
 	msm7x25a_kgsl_3d0_init();
+	/*8x25 kgsl initializations*/
+	msm8x25_kgsl_3d0_init();
 }
 
 static void __init msm7x2x_init_early(void)
@@ -1298,3 +1235,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 47a4605..972cb22 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -91,6 +91,7 @@
 #include <linux/bma150.h>
 
 #include "board-msm7x30-regulator.h"
+#include "pm.h"
 
 #define MSM_PMEM_SF_SIZE	0x1700000
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
@@ -98,6 +99,11 @@
 #else
 #define MSM_FB_SIZE            0x500000
 #endif
+/*
+ * Reserve space for double buffered full screen
+ * res V4L2 video overlay - i.e. 1280x720x1.5x2
+ */
+#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 2764800
 #define MSM_PMEM_ADSP_SIZE      0x1E00000
 #define MSM_FLUID_PMEM_ADSP_SIZE	0x2800000
 #define PMEM_KERNEL_EBI0_SIZE   0x600000
@@ -118,6 +124,7 @@
 #define OPTNAV_I2C_SLAVE_ADDR	(0xB0 >> 1)
 #define OPTNAV_IRQ		20
 #define OPTNAV_CHIP_SELECT	19
+#define PMIC_GPIO_SDC4_PWR_EN_N 24  /* PMIC GPIO Number 25 */
 
 /* Macros assume PMIC GPIOs start at 0 */
 #define PM8058_GPIO_PM_TO_SYS(pm_gpio)     (pm_gpio + NR_GPIO_IRQS)
@@ -167,6 +174,19 @@
 		},
 	};
 
+	struct pm8xxx_gpio_init_info sdc4_pwr_en = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.vin_sel        = PM8058_GPIO_VIN_L5,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+			.out_strength   = PM_GPIO_STRENGTH_LOW,
+			.output_value   = 0,
+		},
+	};
+
 	struct pm8xxx_gpio_init_info haptics_enable = {
 		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
 		{
@@ -294,6 +314,23 @@
 		}
 		gpio_set_value_cansleep(sdc4_en.gpio, 0);
 	}
+	/* FFA -> gpio_25 controls vdd of sdcc4 */
+	else {
+		/* SCD4 gpio_25 */
+		rc = pm8xxx_gpio_config(sdc4_pwr_en.gpio, &sdc4_pwr_en.config);
+		if (rc) {
+			pr_err("%s PMIC_GPIO_SDC4_PWR_EN_N config failed: %d\n",
+			       __func__, rc);
+			return rc;
+		}
+
+		rc = gpio_request(sdc4_pwr_en.gpio, "sdc4_pwr_en");
+		if (rc) {
+			pr_err("PMIC_GPIO_SDC4_PWR_EN_N gpio_req failed: %d\n",
+			       rc);
+			return rc;
+		}
+	}
 
 	return 0;
 }
@@ -2956,6 +2993,26 @@
 	},
 };
 
+u32 msm7x30_power_collapse_latency(enum msm_pm_sleep_mode mode)
+{
+	switch (mode) {
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		return msm_pm_data
+		[MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN:
+		return msm_pm_data
+		[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency;
+	case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
+		return msm_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		return msm_pm_data
+		[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
+	default:
+	return 0;
+	}
+}
+
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
 	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
 	.v_addr = (uint32_t *)PAGE_OFFSET,
@@ -3718,6 +3775,14 @@
 	}
 };
 
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct resource msm_v4l2_video_overlay_resources[] = {
+	{
+	   .flags = IORESOURCE_DMA,
+	}
+};
+#endif
+
 static int msm_fb_detect_panel(const char *name)
 {
 	if (machine_is_msm7x30_fluid()) {
@@ -3751,6 +3816,16 @@
 	}
 };
 
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+
+static struct platform_device msm_v4l2_video_overlay_device = {
+	.name   = "msm_v4l2_overlay_pd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_v4l2_video_overlay_resources),
+	.resource       = msm_v4l2_video_overlay_resources,
+};
+#endif
+
 static struct platform_device msm_migrate_pages_device = {
 	.name   = "msm_migrate_pages",
 	.id     = -1,
@@ -4243,11 +4318,24 @@
 
 static int msm_fb_mddi_client_power(u32 client_id)
 {
+	int rc;
 	printk(KERN_NOTICE "\n client_id = 0x%x", client_id);
 	/* Check if it is Quicklogic client */
 	if (client_id == 0xc5835800) {
 		printk(KERN_NOTICE "\n Quicklogic MDDI client");
 		other_mddi_client = 0;
+		if (IS_ERR(mddi_ldo16)) {
+			rc = PTR_ERR(mddi_ldo16);
+			pr_err("%s: gp10 vreg get failed (%d)\n", __func__, rc);
+			return rc;
+		}
+		rc = regulator_disable(mddi_ldo16);
+		if (rc) {
+			pr_err("%s: LDO16 vreg enable failed (%d)\n",
+							__func__, rc);
+			return rc;
+		}
+
 	} else {
 		printk(KERN_NOTICE "\n Non-Quicklogic MDDI client");
 		quickvx_mddi_client = 0;
@@ -5127,6 +5215,9 @@
 #endif
 	&android_pmem_device,
 	&msm_fb_device,
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	&msm_v4l2_video_overlay_device,
+#endif
 	&msm_migrate_pages_device,
 	&mddi_toshiba_device,
 	&lcdc_toshiba_panel_device,
@@ -5205,7 +5296,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[] = {
@@ -5478,9 +5570,24 @@
 	if (test_bit(dev_id, &vreg_sts) == enable)
 		return rc;
 
-	if (!enable || enabled_once[dev_id - 1])
-		return 0;
+	if (dev_id == 4) {
+		if (enable) {
+			pr_debug("Enable Vdd dev_%d\n", dev_id);
+			gpio_set_value_cansleep(
+				PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+						0);
+			set_bit(dev_id, &vreg_sts);
+		} else {
+			pr_debug("Disable Vdd dev_%d\n", dev_id);
+			gpio_set_value_cansleep(
+				PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+				1);
+			clear_bit(dev_id, &vreg_sts);
+		}
+	}
 
+	if (!enable || enabled_once[dev_id - 1])
+			return 0;
 	if (!curr)
 		return -ENODEV;
 
@@ -6112,6 +6219,8 @@
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
 	if (mmc_regulator_init(1, "s3", 1800000))
 		goto out1;
+	msm7x30_sdc1_data.swfi_latency = msm7x30_power_collapse_latency(
+		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
 
 	if (machine_is_msm7x30_fluid()) {
 		msm7x30_sdc1_data.ocr_mask =  MMC_VDD_27_28 | MMC_VDD_28_29;
@@ -6127,6 +6236,8 @@
 #ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
 	if (mmc_regulator_init(2, "s3", 1800000))
 		goto out2;
+	msm7x30_sdc2_data.swfi_latency = msm7x30_power_collapse_latency(
+		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
 
 	if (machine_is_msm8x55_svlte_surf())
 		msm7x30_sdc2_data.msmsdcc_fmax =  24576000;
@@ -6142,6 +6253,8 @@
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
 	if (mmc_regulator_init(3, "s3", 1800000))
 		goto out3;
+	msm7x30_sdc3_data.swfi_latency = msm7x30_power_collapse_latency(
+		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
 
 	msm_sdcc_setup_gpio(3, 1);
 	msm_add_sdcc(3, &msm7x30_sdc3_data);
@@ -6150,6 +6263,8 @@
 #ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
 	if (mmc_regulator_init(4, "mmc", 2850000))
 		return;
+	msm7x30_sdc4_data.swfi_latency = msm7x30_power_collapse_latency(
+		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
 
 	msm_add_sdcc(4, &msm7x30_sdc4_data);
 #endif
@@ -6228,7 +6343,7 @@
 }
 
 static struct msm_spm_platform_data msm_spm_data __initdata = {
-	.reg_base_addr = MSM_SAW_BASE,
+	.reg_base_addr = MSM_SAW0_BASE,
 
 	.reg_init_values[MSM_SPM_REG_SAW_CFG] = 0x05,
 	.reg_init_values[MSM_SPM_REG_SAW_SPM_CTL] = 0x18,
@@ -6731,6 +6846,7 @@
 	msm_fb_add_devices();
 	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_register_irqs();
 	msm_device_i2c_init();
 	msm_device_i2c_2_init();
 	qup_device_i2c_init();
@@ -6935,6 +7051,16 @@
 	msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
 	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
 		size, addr, __pa(addr));
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	size = MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE;
+	addr = alloc_bootmem_align(size, 0x1000);
+	msm_v4l2_video_overlay_resources[0].start = __pa(addr);
+	msm_v4l2_video_overlay_resources[0].end =
+		msm_v4l2_video_overlay_resources[0].start + size - 1;
+	pr_debug("allocating %lu bytes at %p (%lx physical) for v4l2\n",
+		size, addr, __pa(addr));
+#endif
 }
 
 static void __init msm7x30_map_io(void)
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index c31e6d9..b9050cd 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"
@@ -434,7 +433,7 @@
 			.name = "8901_s0",
 			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
 			.min_uV = 800000,
-			.max_uV = 1250000,
+			.max_uV = 1325000,
 		},
 		.consumer_supplies = vreg_consumers_8901_S0,
 		.num_consumer_supplies = ARRAY_SIZE(vreg_consumers_8901_S0),
@@ -445,7 +444,7 @@
 			.name = "8901_s1",
 			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
 			.min_uV = 800000,
-			.max_uV = 1250000,
+			.max_uV = 1325000,
 		},
 		.consumer_supplies = vreg_consumers_8901_S1,
 		.num_consumer_supplies = ARRAY_SIZE(vreg_consumers_8901_S1),
@@ -925,7 +924,7 @@
 		[MSM_RPMRS_VDD_MEM_RET_LOW]     = 500,
 		[MSM_RPMRS_VDD_MEM_RET_HIGH]    = 750,
 		[MSM_RPMRS_VDD_MEM_ACTIVE]      = 1000,
-		[MSM_RPMRS_VDD_MEM_MAX]         = 1250,
+		[MSM_RPMRS_VDD_MEM_MAX]         = 1325,
 	},
 	.vdd_dig_levels = {
 		[MSM_RPMRS_VDD_DIG_RET_LOW]     = 500,
@@ -1024,7 +1023,7 @@
 };
 #endif
 
-#if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
 static struct msm_otg_platform_data msm_otg_pdata;
 static struct regulator *ldo6_3p3;
 static struct regulator *ldo7_1p8;
@@ -1456,7 +1455,7 @@
 }
 #endif
 
-#if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
 static struct msm_otg_platform_data msm_otg_pdata = {
 	/* if usb link is in sps there is no need for
 	 * usb pclk as dayatona fabric clock will be
@@ -1486,7 +1485,7 @@
 };
 #endif
 
-#ifdef CONFIG_USB_GADGET_MSM_72K
+#ifdef CONFIG_USB_MSM_72K
 static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
 	.is_phy_status_timer_on = 1,
 };
@@ -2630,10 +2629,12 @@
 	if (machine_is_msm8x60_fluid()) {
 		/* fluid has different firmware, gpios */
 		pdata->pil_name = DSPS_PIL_FLUID_NAME;
+		msm_pil_dsps.dev.platform_data = DSPS_PIL_FLUID_NAME;
 		pdata->gpios = dsps_fluid_gpios;
 		pdata->gpios_num = ARRAY_SIZE(dsps_fluid_gpios);
 	} else {
 		pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+		msm_pil_dsps.dev.platform_data = DSPS_PIL_GENERIC_NAME;
 		pdata->gpios = dsps_surf_gpios;
 		pdata->gpios_num = ARRAY_SIZE(dsps_surf_gpios);
 	}
@@ -2660,19 +2661,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 0x8000000 /* 128 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
@@ -2687,9 +2686,9 @@
 #define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
 #endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
 
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x600000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x3BC000
 #define MSM_PMEM_ADSP_SIZE         0x2000000
-#define MSM_PMEM_AUDIO_SIZE        0x28B000
+#define MSM_PMEM_AUDIO_SIZE        0x4CF000
 
 #define MSM_SMI_BASE          0x38000000
 #define MSM_SMI_SIZE          0x4000000
@@ -2706,11 +2705,19 @@
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		0x3600000 /* (54MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_ION_WB_SIZE		0xC00000 /* 12MB */
+#else
 #define MSM_ION_WB_SIZE		0x600000 /* 6MB */
-#define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
+#endif
+
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_ION_HEAP_NUM	8
+#define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
+#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
@@ -2765,6 +2772,8 @@
 	}
 };
 
+static void set_mdp_clocks_for_wuxga(void);
+
 static int msm_fb_detect_panel(const char *name)
 {
 	if (machine_is_msm8x60_fluid()) {
@@ -2819,8 +2828,11 @@
 
 	if (!strncmp(name, HDMI_PANEL_NAME,
 			strnlen(HDMI_PANEL_NAME,
-				PANEL_NAME_MAX_LEN)))
+				PANEL_NAME_MAX_LEN))) {
+		if (hdmi_is_primary)
+			set_mdp_clocks_for_wuxga();
 		return 0;
+	}
 
 	if (!strncmp(name, TVOUT_PANEL_NAME,
 			strnlen(TVOUT_PANEL_NAME,
@@ -3158,7 +3170,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;
@@ -3167,6 +3183,31 @@
 
 }
 
+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;
+			set_mdp_clocks_for_wuxga();
+		}
+	}
+	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 */
@@ -3951,8 +3992,8 @@
 
 #define RPM_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
 		      _default_uV, _peak_uA, _avg_uA, _pull_down, _pin_ctrl, \
-		      _freq, _pin_fn, _force_mode, _state, _sleep_selectable, \
-		      _always_on) \
+		      _freq, _pin_fn, _force_mode, _sleep_set_force_mode, \
+		      _state, _sleep_selectable, _always_on) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -3977,6 +4018,7 @@
 		.freq			= RPM_VREG_FREQ_##_freq, \
 		.pin_fn			= _pin_fn, \
 		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
 		.state			= _state, \
 		.sleep_selectable	= _sleep_selectable, \
 	}
@@ -4017,6 +4059,7 @@
 		      REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
 		      _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
 		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
 		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
 		      _sleep_selectable, _always_on)
 
@@ -4029,6 +4072,7 @@
 		      REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
 		      _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, _freq, \
 		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
 		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
 		      _sleep_selectable, _always_on)
 
@@ -4037,6 +4081,7 @@
 		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE, 0, 0, \
 		      1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
 		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
 		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
 		      _sleep_selectable, _always_on)
 
@@ -4045,6 +4090,7 @@
 		      REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, \
 		      _min_uV, 1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
 		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
 		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
 		      _sleep_selectable, _always_on)
 
@@ -4057,7 +4103,7 @@
 /* RPM early regulator constraints */
 static struct rpm_regulator_init_data rpm_regulator_early_init_data[] = {
 	/*	 ID       a_on pd ss min_uV   max_uV   init_ip    freq */
-	RPM_SMPS(PM8058_S0, 0, 1, 1,  500000, 1250000, SMPS_HMIN, 1p60),
+	RPM_SMPS(PM8058_S0, 0, 1, 1,  500000, 1325000, SMPS_HMIN, 1p60),
 	RPM_SMPS(PM8058_S1, 0, 1, 1,  500000, 1250000, SMPS_HMIN, 1p60),
 };
 
@@ -5103,6 +5149,7 @@
 	&msm_pil_q6v3,
 	&msm_pil_modem,
 	&msm_pil_tzapps,
+	&msm_pil_dsps,
 #ifdef CONFIG_I2C_QUP
 	&msm_gsbi3_qup_i2c_device,
 	&msm_gsbi4_qup_i2c_device,
@@ -5131,10 +5178,10 @@
 	&asoc_mvs_dai1,
 #endif
 
-#if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
 	&msm_device_otg,
 #endif
-#ifdef CONFIG_USB_GADGET_MSM_72K
+#ifdef CONFIG_USB_MSM_72K
 	&msm_device_gadget_peripheral,
 #endif
 #ifdef CONFIG_USB_G_ANDROID
@@ -5352,6 +5399,14 @@
 			.extra_data = (void *) &cp_wb_ion_pdata,
 		},
 		{
+			.id	= ION_QSECOM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_QSECOM_HEAP_NAME,
+			.size	= MSM_ION_QSECOM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+		{
 			.id	= ION_AUDIO_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_AUDIO_HEAP_NAME,
@@ -5401,13 +5456,28 @@
 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;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
 #endif
 }
 
@@ -5417,6 +5487,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;
@@ -5466,8 +5539,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();
 }
@@ -7349,7 +7441,7 @@
 #endif
 	}
 
-#if defined(CONFIG_USB_GADGET_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
 	/*
 	 * We can not put USB regulators (8058_l6 and 8058_l7) in LPM
 	 * when we depend on USB PHY for VBUS/ID notifications. VBUS
@@ -7364,7 +7456,7 @@
 	msm_device_otg.dev.platform_data = &msm_otg_pdata;
 #endif
 
-#ifdef CONFIG_USB_GADGET_MSM_72K
+#ifdef CONFIG_USB_MSM_72K
 	msm_device_gadget_peripheral.dev.platform_data = &msm_gadget_pdata;
 #endif
 
@@ -9147,51 +9239,6 @@
 	},
 };
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
-	/* If HDMI is used as primary */
-	 {
-		.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 mdp_bus_scale_usecases[] = {
-	{
-		ARRAY_SIZE(mdp_init_vectors),
-		mdp_init_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-	{
-		ARRAY_SIZE(hdmi_as_primary_vectors),
-		hdmi_as_primary_vectors,
-	},
-};
-#else
 #ifdef CONFIG_FB_MSM_LCDC_DSUB
 static struct msm_bus_vectors mdp_sd_smi_vectors[] = {
 	/* Default case static display/UI/2d/3d if FB SMI */
@@ -9386,7 +9433,6 @@
 		mdp_1080p_vectors,
 	},
 };
-#endif
 static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
 	mdp_bus_scale_usecases,
 	ARRAY_SIZE(mdp_bus_scale_usecases),
@@ -9413,26 +9459,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
@@ -9451,7 +9478,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),
@@ -9462,6 +9508,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),
@@ -9471,6 +9518,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
 
 
@@ -9592,13 +9660,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,
@@ -9610,11 +9671,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
@@ -9622,7 +9679,7 @@
 #endif
 	.mdp_rev = MDP_REV_41,
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	.mem_hid = ION_CP_WB_HEAP_ID,
+	.mem_hid = BIT(ION_CP_WB_HEAP_ID),
 #else
 	.mem_hid = MEMTYPE_EBI1,
 #endif
@@ -9720,7 +9777,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);
@@ -9728,6 +9788,45 @@
 #endif
 }
 
+/**
+ * Set MDP clocks to high frequency to avoid underflow when
+ * using high resolution 1200x1920 WUXGA/HDMI as primary panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+	int i;
+
+	mdp_sd_smi_vectors[0].ab = 2000000000;
+	mdp_sd_smi_vectors[0].ib = 2000000000;
+	mdp_sd_smi_vectors[1].ab = 2000000000;
+	mdp_sd_smi_vectors[1].ib = 2000000000;
+
+	mdp_sd_ebi_vectors[0].ab = 2000000000;
+	mdp_sd_ebi_vectors[0].ib = 2000000000;
+	mdp_sd_ebi_vectors[1].ab = 2000000000;
+	mdp_sd_ebi_vectors[1].ib = 2000000000;
+
+	mdp_vga_vectors[0].ab = 2000000000;
+	mdp_vga_vectors[0].ib = 2000000000;
+	mdp_vga_vectors[1].ab = 2000000000;
+	mdp_vga_vectors[1].ib = 2000000000;
+
+	mdp_720p_vectors[0].ab = 2000000000;
+	mdp_720p_vectors[0].ib = 2000000000;
+	mdp_720p_vectors[1].ab = 2000000000;
+	mdp_720p_vectors[1].ib = 2000000000;
+
+	mdp_1080p_vectors[0].ab = 2000000000;
+	mdp_1080p_vectors[0].ib = 2000000000;
+	mdp_1080p_vectors[1].ab = 2000000000;
+	mdp_1080p_vectors[1].ib = 2000000000;
+
+	mdp_pdata.mdp_core_clk_rate = 200000000;
+
+	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+		mdp_core_clk_rate_table[i] = 200000000;
+}
+
 #if (defined(CONFIG_MARIMBA_CORE)) && \
 	(defined(CONFIG_MSM_BT_POWER) || defined(CONFIG_MSM_BT_POWER_MODULE))
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 0427632..60457cc 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -28,9 +28,12 @@
 #include <linux/input/rmi_i2c.h>
 #include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/regulator/consumer.h>
+#include <linux/memblock.h>
+#include <linux/input/ft5x06_ts.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>
@@ -124,139 +127,9 @@
 
 #ifdef CONFIG_ARCH_MSM7X27A
 #define MSM_PMEM_MDP_SIZE       0x1DD1000
-#define MSM_PMEM_ADSP_SIZE      0x1000000
+#define MSM_PMEM_ADSP_SIZE      0x1100000
 #endif
 
-#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
-defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
-
-#ifndef CLEARPAD3000_ATTEN_GPIO
-#define CLEARPAD3000_ATTEN_GPIO (48)
-#endif
-
-#ifndef CLEARPAD3000_RESET_GPIO
-#define CLEARPAD3000_RESET_GPIO (26)
-#endif
-
-static int synaptics_touchpad_setup(void);
-
-static struct msm_gpio clearpad3000_cfg_data[] = {
-	{GPIO_CFG(CLEARPAD3000_ATTEN_GPIO, 0, GPIO_CFG_INPUT,
-			GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "rmi4_attn"},
-	{GPIO_CFG(CLEARPAD3000_RESET_GPIO, 0, GPIO_CFG_OUTPUT,
-			GPIO_CFG_PULL_DOWN, GPIO_CFG_8MA), "rmi4_reset"},
-};
-
-static struct rmi_XY_pair rmi_offset = {.x = 0, .y = 0};
-static struct rmi_range rmi_clipx = {.min = 48, .max = 980};
-static struct rmi_range rmi_clipy = {.min = 7, .max = 1647};
-static struct rmi_f11_functiondata synaptics_f11_data = {
-	.swap_axes = false,
-	.flipX = false,
-	.flipY = false,
-	.offset = &rmi_offset,
-	.button_height = 113,
-	.clipX = &rmi_clipx,
-	.clipY = &rmi_clipy,
-};
-
-#define MAX_LEN		100
-
-static ssize_t clearpad3000_virtual_keys_register(struct kobject *kobj,
-		     struct kobj_attribute *attr, char *buf)
-{
-	char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
-			     ":60:830:120:60" ":" __stringify(EV_KEY) \
-			     ":" __stringify(KEY_HOME)   ":180:830:120:60" \
-				":" __stringify(EV_KEY) ":" \
-				__stringify(KEY_SEARCH) ":300:830:120:60" \
-				":" __stringify(EV_KEY) ":" \
-			__stringify(KEY_BACK)   ":420:830:120:60" "\n";
-
-	return snprintf(buf, strnlen(virtual_keys, MAX_LEN) + 1 , "%s",
-			virtual_keys);
-}
-
-static struct kobj_attribute clearpad3000_virtual_keys_attr = {
-	.attr = {
-		.name = "virtualkeys.sensor00fn11",
-		.mode = S_IRUGO,
-	},
-	.show = &clearpad3000_virtual_keys_register,
-};
-
-static struct attribute *virtual_key_properties_attrs[] = {
-	&clearpad3000_virtual_keys_attr.attr,
-	NULL
-};
-
-static struct attribute_group virtual_key_properties_attr_group = {
-	.attrs = virtual_key_properties_attrs,
-};
-
-struct kobject *virtual_key_properties_kobj;
-
-static struct rmi_functiondata synaptics_functiondata[] = {
-	{
-		.function_index = RMI_F11_INDEX,
-		.data = &synaptics_f11_data,
-	},
-};
-
-static struct rmi_functiondata_list synaptics_perfunctiondata = {
-	.count = ARRAY_SIZE(synaptics_functiondata),
-	.functiondata = synaptics_functiondata,
-};
-
-static struct rmi_sensordata synaptics_sensordata = {
-	.perfunctiondata = &synaptics_perfunctiondata,
-	.rmi_sensor_setup	= synaptics_touchpad_setup,
-};
-
-static struct rmi_i2c_platformdata synaptics_platformdata = {
-	.i2c_address = 0x2c,
-	.irq_type = IORESOURCE_IRQ_LOWLEVEL,
-	.sensordata = &synaptics_sensordata,
-};
-
-static struct i2c_board_info synaptic_i2c_clearpad3k[] = {
-	{
-	I2C_BOARD_INFO("rmi4_ts", 0x2c),
-	.platform_data = &synaptics_platformdata,
-	},
-};
-
-static int synaptics_touchpad_setup(void)
-{
-	int retval = 0;
-
-	virtual_key_properties_kobj =
-		kobject_create_and_add("board_properties", NULL);
-	if (virtual_key_properties_kobj)
-		retval = sysfs_create_group(virtual_key_properties_kobj,
-				&virtual_key_properties_attr_group);
-	if (!virtual_key_properties_kobj || retval)
-		pr_err("failed to create ft5202 board_properties\n");
-
-	retval = msm_gpios_request_enable(clearpad3000_cfg_data,
-		    sizeof(clearpad3000_cfg_data)/sizeof(struct msm_gpio));
-	if (retval) {
-		pr_err("%s:Failed to obtain touchpad GPIO %d. Code: %d.",
-				__func__, CLEARPAD3000_ATTEN_GPIO, retval);
-		retval = 0; /* ignore the err */
-	}
-	synaptics_platformdata.irq = gpio_to_irq(CLEARPAD3000_ATTEN_GPIO);
-
-	gpio_set_value(CLEARPAD3000_RESET_GPIO, 0);
-	usleep(10000);
-	gpio_set_value(CLEARPAD3000_RESET_GPIO, 1);
-	usleep(50000);
-
-	return retval;
-}
-#endif
-
-
 static struct android_usb_platform_data android_usb_pdata = {
 	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
 };
@@ -437,6 +310,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,
@@ -659,7 +598,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 +620,25 @@
 	&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_uart_dm1,
+	&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)
 {
@@ -760,26 +711,51 @@
 {
 	reserve_info = &msm7627a_reserve_info;
 	msm_reserve();
+	memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
 }
 
-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 struct msm_handset_platform_data hs_platform_data = {
-	.hs_name = "7k_handset",
-	.pwr_key_delay_ms = 500, /* 0 will disable end key */
-};
-
-static struct platform_device hs_pdev = {
-	.name   = "msm-handset",
-	.id     = -1,
-	.dev    = {
-		.platform_data = &hs_platform_data,
-	},
-};
+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 platform_device msm_proccomm_regulator_dev = {
 	.name   = PROCCOMM_REGULATOR_DEV_NAME,
@@ -797,258 +773,98 @@
 				__func__, rc);
 }
 
-/* 8625 keypad device information */
-static unsigned int kp_row_gpios_8625[] = {31};
-static unsigned int kp_col_gpios_8625[] = {36, 37};
-
-static const unsigned short keymap_8625[] = {
-	KEY_VOLUMEUP,
-	KEY_VOLUMEDOWN,
-};
-
-static struct gpio_event_matrix_info kp_matrix_info_8625 = {
-	.info.func      = gpio_event_matrix_func,
-	.keymap         = keymap_8625,
-	.output_gpios   = kp_row_gpios_8625,
-	.input_gpios    = kp_col_gpios_8625,
-	.noutputs       = ARRAY_SIZE(kp_row_gpios_8625),
-	.ninputs        = ARRAY_SIZE(kp_col_gpios_8625),
-	.settle_time.tv_nsec = 40 * NSEC_PER_USEC,
-	.poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
-	.flags          = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
-			  GPIOKPF_PRINT_UNMAPPED_KEYS,
-};
-
-static struct gpio_event_info *kp_info_8625[] = {
-	&kp_matrix_info_8625.info,
-};
-static struct gpio_event_platform_data kp_pdata_8625 = {
-	.name           = "8625_kp",
-	.info           = kp_info_8625,
-	.info_count     = ARRAY_SIZE(kp_info_8625)
-};
-
-static struct platform_device kp_pdev_8625 = {
-	.name   = GPIO_EVENT_DEV_NAME,
-	.id     = -1,
-	.dev    = {
-		.platform_data  = &kp_pdata_8625,
-	},
-};
-
-#define LED_RED_GPIO_8625 49
-#define LED_GREEN_GPIO_8625 34
-
-static struct gpio_led gpio_leds_config_8625[] = {
-	{
-		.name = "green",
-		.gpio = LED_GREEN_GPIO_8625,
-	},
-	{
-		.name = "red",
-		.gpio = LED_RED_GPIO_8625,
-	},
-};
-
-static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
-	.num_leds = ARRAY_SIZE(gpio_leds_config_8625),
-	.leds = gpio_leds_config_8625,
-};
-
-static struct platform_device gpio_leds_8625 = {
-	.name          = "leds-gpio",
-	.id            = -1,
-	.dev           = {
-		.platform_data = &gpio_leds_pdata_8625,
-	},
-};
-
-#define MXT_TS_IRQ_GPIO         48
-#define MXT_TS_RESET_GPIO       26
-
-static const u8 mxt_config_data[] = {
-	/* T6 Object */
-	0, 0, 0, 0, 0, 0,
-	/* T38 Object */
-	16, 0, 0, 0, 0, 0, 0, 0,
-	/* T7 Object */
-	255, 255, 10,
-	/* T8 Object */
-	30, 0, 20, 20, 0, 0, 20, 0, 50, 0,
-	/* T9 Object */
-	3, 0, 0, 18, 11, 0, 32, 75, 3, 3,
-	0, 1, 1, 0, 10, 10, 10, 10, 31, 3,
-	223, 1, 11, 11, 15, 15, 151, 43, 145, 80,
-	100, 15, 0, 0, 0,
-	/* T15 Object */
-	131, 0, 11, 11, 1, 1, 0, 45, 3, 0,
-	0,
-	/* T18 Object */
-	0, 0,
-	/* T19 Object */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0,
-	/* T23 Object */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0,
-	/* T25 Object */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0,
-	/* T40 Object */
-	0, 0, 0, 0, 0,
-	/* T42 Object */
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* T46 Object */
-	0, 2, 32, 48, 0, 0, 0, 0, 0,
-	/* T47 Object */
-	1, 20, 60, 5, 2, 50, 40, 0, 0, 40,
-	/* T48 Object */
-	1, 12, 80, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 6, 6, 0, 0, 100, 4, 64,
-	10, 0, 20, 5, 0, 38, 0, 20, 0, 0,
-	0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
-	10, 10, 10, 0, 0, 15, 15, 154, 58, 145,
-	80, 100, 15, 3,
-};
-
-static struct mxt_config_info mxt_config_array[] = {
-	{
-		.config		= mxt_config_data,
-		.config_length	= ARRAY_SIZE(mxt_config_data),
-		.family_id	= 0x81,
-		.variant_id	= 0x01,
-		.version	= 0x10,
-		.build		= 0xAA,
-	},
-};
-
-static int mxt_key_codes[MXT_KEYARRAY_MAX_KEYS] = {
-	[0] = KEY_HOME,
-	[1] = KEY_MENU,
-	[9] = KEY_BACK,
-	[10] = KEY_SEARCH,
-};
-
-static struct mxt_platform_data mxt_platform_data = {
-	.config_array		= mxt_config_array,
-	.config_array_size	= ARRAY_SIZE(mxt_config_array),
-	.x_size                 = 479,
-	.y_size                 = 799,
-	.irqflags               = IRQF_TRIGGER_FALLING,
-	.i2c_pull_up            = true,
-	.reset_gpio		= MXT_TS_RESET_GPIO,
-	.irq_gpio		= MXT_TS_IRQ_GPIO,
-	.key_codes		= mxt_key_codes,
-};
-
-static struct i2c_board_info mxt_device_info[] __initdata = {
-	{
-		I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
-		.platform_data = &mxt_platform_data,
-		.irq = MSM_GPIO_TO_INT(MXT_TS_IRQ_GPIO),
-	},
-};
-
-static void msm7627a_add_io_devices(void)
-{
-	int rc;
-
-	/* touchscreen */
-	if (machine_is_msm7627a_qrd1()) {
-		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
-					synaptic_i2c_clearpad3k,
-					ARRAY_SIZE(synaptic_i2c_clearpad3k));
-	} else if (machine_is_msm7627a_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);
-		if (rc) {
-			pr_err("%s: gpio_tlmm_config for %d failed\n",
-				__func__, MXT_TS_IRQ_GPIO);
-		}
-
-		rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_RESET_GPIO, 0,
-				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
-				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
-		if (rc) {
-			pr_err("%s: gpio_tlmm_config for %d failed\n",
-				__func__, MXT_TS_RESET_GPIO);
-		}
-
-		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
-					mxt_device_info,
-					ARRAY_SIZE(mxt_device_info));
-	}
-
-	/* headset */
-	platform_device_register(&hs_pdev);
-
-	/* vibrator */
-#ifdef CONFIG_MSM_RPC_VIBRATOR
-	msm_init_pmic_vibrator();
-#endif
-
-	/* keypad */
-	if (machine_is_msm7627a_evb())
-		platform_device_register(&kp_pdev_8625);
-
-	/* leds */
-	if (machine_is_msm7627a_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);
-		if (rc) {
-			pr_err("%s: gpio_tlmm_config for %d failed\n",
-				__func__, LED_RED_GPIO_8625);
-		}
-
-		rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
-				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
-				GPIO_CFG_16MA), GPIO_CFG_ENABLE);
-		if (rc) {
-			pr_err("%s: gpio_tlmm_config for %d failed\n",
-				__func__, LED_GREEN_GPIO_8625);
-		}
-
-		platform_device_register(&gpio_leds_8625);
-	}
-}
-
 static int __init msm_qrd_init_ar6000pm(void)
 {
 	msm_wlan_ar6000_pm_device.dev.platform_data = &ar600x_wlan_power;
 	return platform_device_register(&msm_wlan_ar6000_pm_device);
 }
 
+static void __init msm_add_footswitch_devices(void)
+{
+	platform_add_devices(msm_footswitch_devices,
+				msm_num_footswitch_devices);
+}
+
 static void add_platform_devices(void)
 {
-	platform_add_devices(qrd_common_devices,
-			ARRAY_SIZE(qrd_common_devices));
+	if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()) {
+		platform_add_devices(msm8625_evb_devices,
+				ARRAY_SIZE(msm8625_evb_devices));
+		platform_add_devices(qrd3_devices,
+				ARRAY_SIZE(qrd3_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));
+			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_pm_init(void)
+{
+
+	if (!cpu_is_msm8625()) {
+		msm_pm_set_platform_data(msm7627a_pm_data,
+				ARRAY_SIZE(msm7627a_pm_data));
+		BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	} else {
+		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();
+	}
+}
+
 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();
+
+	msm_add_footswitch_devices();
 	add_platform_devices();
 
 	/* Ensure ar6000pm device is registered before MMC/SDC */
@@ -1058,10 +874,9 @@
 #ifdef CONFIG_USB_EHCI_MSM_72K
 	msm7627a_init_host();
 #endif
-	msm_pm_set_platform_data(msm7627a_pm_data,
-				ARRAY_SIZE(msm7627a_pm_data));
-	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init();
 
+	msm_pm_register_irqs();
 	msm_fb_add_devices();
 
 #if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
@@ -1069,8 +884,9 @@
 #endif
 
 	msm7627a_camera_init();
-
-	msm7627a_add_io_devices();
+	qrd7627a_add_io_devices();
+	msm7x25a_kgsl_3d0_init();
+	msm8x25_kgsl_3d0_init();
 }
 
 static void __init qrd7627a_init_early(void)
@@ -1108,3 +924,23 @@
 	.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
+MACHINE_START(MSM8625_QRD7, "QRD MSM8625 QRD7")
+	.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/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 5a77333..239896a 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -55,6 +55,7 @@
 #include "msm-keypad-devices.h"
 #include "acpuclock.h"
 #include "pm.h"
+#include "irq.h"
 #include "pm-boot.h"
 #include "proc_comm.h"
 #ifdef CONFIG_USB_ANDROID
@@ -2442,6 +2443,7 @@
 				ARRAY_SIZE(msm_spi_board_info));
 	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_register_irqs();
 
 #ifdef CONFIG_SURF_FFA_GPIO_KEYPAD
 	if (machine_is_qsd8x50_ffa())
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
new file mode 100644
index 0000000..3c317e9
--- /dev/null
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -0,0 +1,475 @@
+/* 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/cpu.h>
+#include <mach/msm-krait-l2-accessors.h>
+
+#define CESR_DCTPE		BIT(0)
+#define CESR_DCDPE		BIT(1)
+#define CESR_ICTPE		BIT(2)
+#define CESR_ICDPE		BIT(3)
+#define CESR_DCTE		(BIT(4) | BIT(5))
+#define CESR_ICTE		(BIT(6) | BIT(7))
+#define CESR_TLBMH		BIT(16)
+#define CESR_I_MASK		0x000000CC
+
+#define L2ESR_IND_ADDR		0x204
+#define L2ESYNR0_IND_ADDR	0x208
+#define L2ESYNR1_IND_ADDR	0x209
+#define L2EAR0_IND_ADDR		0x20C
+#define L2EAR1_IND_ADDR		0x20D
+
+#define L2ESR_MPDCD		BIT(0)
+#define L2ESR_MPSLV             BIT(1)
+#define L2ESR_TSESB             BIT(2)
+#define L2ESR_TSEDB             BIT(3)
+#define L2ESR_DSESB             BIT(4)
+#define L2ESR_DSEDB             BIT(5)
+#define L2ESR_MSE		BIT(6)
+#define L2ESR_MPLDREXNOK	BIT(8)
+
+#define L2ESR_CPU_MASK		0x0F
+#define L2ESR_CPU_SHIFT		16
+
+#ifdef CONFIG_MSM_L1_ERR_PANIC
+#define ERP_L1_ERR(a) panic(a)
+#else
+#define ERP_L1_ERR(a) do { } while (0)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC
+#define ERP_PORT_ERR(a) panic(a)
+#else
+#define ERP_PORT_ERR(a) WARN(1, a)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_1BIT_PANIC
+#define ERP_1BIT_ERR(a) panic(a)
+#else
+#define ERP_1BIT_ERR(a) do { } while (0)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_2BIT_PANIC
+#define ERP_2BIT_ERR(a) panic(a)
+#else
+#define ERP_2BIT_ERR(a) do { } while (0)
+#endif
+
+#define MODULE_NAME "msm_cache_erp"
+
+struct msm_l1_err_stats {
+	unsigned int dctpe;
+	unsigned int dcdpe;
+	unsigned int ictpe;
+	unsigned int icdpe;
+	unsigned int dcte;
+	unsigned int icte;
+	unsigned int tlbmh;
+};
+
+struct msm_l2_err_stats {
+	unsigned int mpdcd;
+	unsigned int mpslv;
+	unsigned int tsesb;
+	unsigned int tsedb;
+	unsigned int dsesb;
+	unsigned int dsedb;
+	unsigned int mse;
+	unsigned int mplxrexnok;
+};
+
+static DEFINE_PER_CPU(struct msm_l1_err_stats, msm_l1_erp_stats);
+static struct msm_l2_err_stats msm_l2_erp_stats;
+
+static int l1_erp_irq, l2_erp_irq;
+static struct proc_dir_entry *procfs_entry;
+
+static inline unsigned int read_cesr(void)
+{
+	unsigned int cesr;
+	asm volatile ("mrc p15, 7, %0, c15, c0, 1" : "=r" (cesr));
+	return cesr;
+}
+
+static inline void write_cesr(unsigned int cesr)
+{
+	asm volatile ("mcr p15, 7, %[cesr], c15, c0, 1" : : [cesr]"r" (cesr));
+}
+
+static inline unsigned int read_cesynr(void)
+{
+	unsigned int cesynr;
+	asm volatile ("mrc p15, 7, %0, c15, c0, 3" : "=r" (cesynr));
+	return cesynr;
+}
+
+static int proc_read_status(char *page, char **start, off_t off, int count,
+			    int *eof, void *data)
+{
+	struct msm_l1_err_stats *l1_stats;
+	char *p = page;
+	int len, cpu, ret, bytes_left = PAGE_SIZE;
+
+	for_each_present_cpu(cpu) {
+		l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
+
+		ret = snprintf(p, bytes_left,
+			"CPU %d:\n"	\
+			"\tD-cache tag parity errors:\t%u\n"	\
+			"\tD-cache data parity errors:\t%u\n"	\
+			"\tI-cache tag parity errors:\t%u\n"	\
+			"\tI-cache data parity errors:\t%u\n"	\
+			"\tD-cache timing errors:\t\t%u\n"	\
+			"\tI-cache timing errors:\t\t%u\n"	\
+			"\tTLB multi-hit errors:\t\t%u\n\n",	\
+			cpu,
+			l1_stats->dctpe,
+			l1_stats->dcdpe,
+			l1_stats->ictpe,
+			l1_stats->icdpe,
+			l1_stats->dcte,
+			l1_stats->icte,
+			l1_stats->tlbmh);
+		p += ret;
+		bytes_left -= ret;
+	}
+
+	p += snprintf(p, bytes_left,
+			"L2 master port decode errors:\t\t%u\n"	\
+			"L2 master port slave errors:\t\t%u\n"		\
+			"L2 tag soft errors, single-bit:\t\t%u\n"	\
+			"L2 tag soft errors, double-bit:\t\t%u\n"	\
+			"L2 data soft errors, single-bit:\t%u\n"	\
+			"L2 data soft errors, double-bit:\t%u\n"	\
+			"L2 modified soft errors:\t\t%u\n"		\
+			"L2 master port LDREX NOK errors:\t%u\n",
+			msm_l2_erp_stats.mpdcd,
+			msm_l2_erp_stats.mpslv,
+			msm_l2_erp_stats.tsesb,
+			msm_l2_erp_stats.tsedb,
+			msm_l2_erp_stats.dsesb,
+			msm_l2_erp_stats.dsedb,
+			msm_l2_erp_stats.mse,
+			msm_l2_erp_stats.mplxrexnok);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
+{
+	struct msm_l1_err_stats *l1_stats = dev_id;
+	unsigned int cesr = read_cesr();
+	unsigned int i_cesynr, d_cesynr;
+
+	pr_alert("L1 Error detected on CPU %d!\n", smp_processor_id());
+	pr_alert("\tCESR    = 0x%08x\n", cesr);
+
+	if (cesr & CESR_DCTPE) {
+		pr_alert("D-cache tag parity error\n");
+		l1_stats->dctpe++;
+	}
+
+	if (cesr & CESR_DCDPE) {
+		pr_alert("D-cache data parity error\n");
+		l1_stats->dcdpe++;
+	}
+
+	if (cesr & CESR_ICTPE) {
+		pr_alert("I-cache tag parity error\n");
+		l1_stats->ictpe++;
+	}
+
+	if (cesr & CESR_ICDPE) {
+		pr_alert("I-cache data parity error\n");
+		l1_stats->icdpe++;
+	}
+
+	if (cesr & CESR_DCTE) {
+		pr_alert("D-cache timing error\n");
+		l1_stats->dcte++;
+	}
+
+	if (cesr & CESR_ICTE) {
+		pr_alert("I-cache timing error\n");
+		l1_stats->icte++;
+	}
+
+	if (cesr & CESR_TLBMH) {
+		pr_alert("TLB multi-hit error\n");
+		l1_stats->tlbmh++;
+	}
+
+	if (cesr & (CESR_ICTPE | CESR_ICDPE | CESR_ICTE)) {
+		i_cesynr = read_cesynr();
+		pr_alert("I-side CESYNR = 0x%08x\n", i_cesynr);
+		write_cesr(CESR_I_MASK);
+
+		/*
+		 * Clear the I-side bits from the captured CESR value so that we
+		 * don't accidentally clear any new I-side errors when we do
+		 * the CESR write-clear operation.
+		 */
+		cesr &= ~CESR_I_MASK;
+	}
+
+	if (cesr & (CESR_DCTPE | CESR_DCDPE | CESR_DCTE)) {
+		d_cesynr = read_cesynr();
+		pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
+	}
+
+	/* Clear the interrupt bits we processed */
+	write_cesr(cesr);
+
+	ERP_L1_ERR("L1 cache / TLB error detected");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t msm_l2_erp_irq(int irq, void *dev_id)
+{
+	unsigned int l2esr;
+	unsigned int l2esynr0;
+	unsigned int l2esynr1;
+	unsigned int l2ear0;
+	unsigned int l2ear1;
+	int soft_error = 0;
+	int port_error = 0;
+	int unrecoverable = 0;
+
+	l2esr = get_l2_indirect_reg(L2ESR_IND_ADDR);
+	l2esynr0 = get_l2_indirect_reg(L2ESYNR0_IND_ADDR);
+	l2esynr1 = get_l2_indirect_reg(L2ESYNR1_IND_ADDR);
+	l2ear0 = get_l2_indirect_reg(L2EAR0_IND_ADDR);
+	l2ear1 = get_l2_indirect_reg(L2EAR1_IND_ADDR);
+
+	pr_alert("L2 Error detected!\n");
+	pr_alert("\tL2ESR    = 0x%08x\n", l2esr);
+	pr_alert("\tL2ESYNR0 = 0x%08x\n", l2esynr0);
+	pr_alert("\tL2ESYNR1 = 0x%08x\n", l2esynr1);
+	pr_alert("\tL2EAR0   = 0x%08x\n", l2ear0);
+	pr_alert("\tL2EAR1   = 0x%08x\n", l2ear1);
+	pr_alert("\tCPU bitmap = 0x%x\n", (l2esr >> L2ESR_CPU_SHIFT) &
+						    L2ESR_CPU_MASK);
+
+	if (l2esr & L2ESR_MPDCD) {
+		pr_alert("L2 master port decode error\n");
+		port_error++;
+		msm_l2_erp_stats.mpdcd++;
+	}
+
+	if (l2esr & L2ESR_MPSLV) {
+		pr_alert("L2 master port slave error\n");
+		port_error++;
+		msm_l2_erp_stats.mpslv++;
+	}
+
+	if (l2esr & L2ESR_TSESB) {
+		pr_alert("L2 tag soft error, single-bit\n");
+		soft_error++;
+		msm_l2_erp_stats.tsesb++;
+	}
+
+	if (l2esr & L2ESR_TSEDB) {
+		pr_alert("L2 tag soft error, double-bit\n");
+		soft_error++;
+		unrecoverable++;
+		msm_l2_erp_stats.tsedb++;
+	}
+
+	if (l2esr & L2ESR_DSESB) {
+		pr_alert("L2 data soft error, single-bit\n");
+		soft_error++;
+		msm_l2_erp_stats.dsesb++;
+	}
+
+	if (l2esr & L2ESR_DSEDB) {
+		pr_alert("L2 data soft error, double-bit\n");
+		soft_error++;
+		unrecoverable++;
+		msm_l2_erp_stats.dsedb++;
+	}
+
+	if (l2esr & L2ESR_MSE) {
+		pr_alert("L2 modified soft error\n");
+		soft_error++;
+		msm_l2_erp_stats.mse++;
+	}
+
+	if (l2esr & L2ESR_MPLDREXNOK) {
+		pr_alert("L2 master port LDREX received Normal OK response\n");
+		port_error++;
+		msm_l2_erp_stats.mplxrexnok++;
+	}
+
+	if (port_error)
+		ERP_PORT_ERR("L2 master port error detected");
+
+	if (soft_error && !unrecoverable)
+		ERP_1BIT_ERR("L2 single-bit error detected");
+
+	if (unrecoverable)
+		ERP_2BIT_ERR("L2 double-bit error detected, trouble ahead");
+
+	set_l2_indirect_reg(L2ESR_IND_ADDR, l2esr);
+	return IRQ_HANDLED;
+}
+
+static void enable_erp_irq_callback(void *info)
+{
+	enable_percpu_irq(l1_erp_irq, IRQ_TYPE_LEVEL_HIGH);
+}
+
+static void disable_erp_irq_callback(void *info)
+{
+	disable_percpu_irq(l1_erp_irq);
+}
+
+static int cache_erp_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		enable_erp_irq_callback(NULL);
+		break;
+
+	case CPU_DYING:
+		disable_erp_irq_callback(NULL);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cache_erp_cpu_notifier = {
+	.notifier_call = cache_erp_cpu_callback,
+};
+
+static int msm_cache_erp_probe(struct platform_device *pdev)
+{
+	struct resource *r;
+	int ret, cpu;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l1_irq");
+
+	if (!r) {
+		pr_err("Could not get L1 resource\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	l1_erp_irq = r->start;
+
+	ret = request_percpu_irq(l1_erp_irq, msm_l1_erp_irq, "MSM_L1",
+				 &msm_l1_erp_stats);
+
+	if (ret) {
+		pr_err("Failed to request the L1 cache error interrupt\n");
+		goto fail;
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l2_irq");
+
+	if (!r) {
+		pr_err("Could not get L2 resource\n");
+		ret = -ENODEV;
+		goto fail_l1;
+	}
+
+	l2_erp_irq = r->start;
+	ret = request_irq(l2_erp_irq, msm_l2_erp_irq, 0, "MSM_L2", NULL);
+
+	if (ret) {
+		pr_err("Failed to request the L2 cache error interrupt\n");
+		goto fail_l1;
+	}
+
+	procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
+
+	if (!procfs_entry) {
+		pr_err("Failed to create procfs node for cache error reporting\n");
+		ret = -ENODEV;
+		goto fail_l2;
+	}
+
+	get_online_cpus();
+	register_hotcpu_notifier(&cache_erp_cpu_notifier);
+	for_each_cpu(cpu, cpu_online_mask)
+		smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
+	put_online_cpus();
+
+	procfs_entry->read_proc = proc_read_status;
+	return 0;
+
+fail_l2:
+	free_irq(l2_erp_irq, NULL);
+fail_l1:
+	free_percpu_irq(l1_erp_irq, NULL);
+fail:
+	return  ret;
+}
+
+static int msm_cache_erp_remove(struct platform_device *pdev)
+{
+	int cpu;
+	if (procfs_entry)
+		remove_proc_entry("cpu/msm_cache_erp", NULL);
+
+	get_online_cpus();
+	unregister_hotcpu_notifier(&cache_erp_cpu_notifier);
+	for_each_cpu(cpu, cpu_online_mask)
+		smp_call_function_single(cpu, disable_erp_irq_callback, NULL,
+					 1);
+	put_online_cpus();
+
+	free_percpu_irq(l1_erp_irq, NULL);
+
+	disable_irq(l2_erp_irq);
+	free_irq(l2_erp_irq, NULL);
+	return 0;
+}
+
+static struct platform_driver msm_cache_erp_driver = {
+	.probe = msm_cache_erp_probe,
+	.remove = msm_cache_erp_remove,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_cache_erp_init(void)
+{
+	return platform_driver_register(&msm_cache_erp_driver);
+}
+
+static void __exit msm_cache_erp_exit(void)
+{
+	platform_driver_unregister(&msm_cache_erp_driver);
+}
+
+
+module_init(msm_cache_erp_init);
+module_exit(msm_cache_erp_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM cache error reporting driver");
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index bd7ec87..b4b2855 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -234,6 +234,7 @@
 		.rate = 19200000,
 		.ops = &clk_ops_tcxo,
 		CLK_INIT(tcxo_clk.c),
+		.warned = true,
 	},
 };
 
@@ -259,6 +260,7 @@
 		.rate = 24576000,
 		.ops = &clk_ops_lpxo,
 		CLK_INIT(lpxo_clk.c),
+		.warned = true,
 	},
 };
 
@@ -272,6 +274,7 @@
 		.rate = 768000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll1_clk.c),
+		.warned = true,
 	},
 };
 
@@ -285,6 +288,7 @@
 		.rate = 806400000, /* TODO: Support scaling */
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll2_clk.c),
+		.warned = true,
 	},
 };
 
@@ -311,6 +315,7 @@
 		.rate = 891000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
@@ -2593,7 +2598,7 @@
 	u64 raw_count_short, raw_count_full;
 	unsigned ret;
 
-	clk_enable(&tcxo_clk.c);
+	clk_prepare_enable(&tcxo_clk.c);
 
 	spin_lock_irqsave(&local_clock_reg_lock, flags);
 
@@ -2629,7 +2634,7 @@
 		ret = raw_count_full;
 	}
 
-	clk_disable(&tcxo_clk.c);
+	clk_disable_unprepare(&tcxo_clk.c);
 
 	return ret;
 }
@@ -2648,7 +2653,6 @@
 static struct clk_ops measure_clk_ops = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
-	.is_local = local_clk_is_local,
 };
 
 static struct clk measure_clk = {
@@ -2960,8 +2964,7 @@
 	{USBH3_NS_REG, BIT(6), BIT(6)},
 };
 
-/* Local clock driver initialization. */
-static void __init msm7x30_clock_init(void)
+static void __init msm7x30_clock_pre_init(void)
 {
 	int i;
 	uint32_t val;
@@ -2974,15 +2977,17 @@
 	 * function is a NOP since writes to shadow regions that we don't own
 	 * are ignored. */
 
-	clk_set_rate(&usb_hs_src_clk.c, clk_tbl_usb[1].freq_hz);
-
 	for (i = 0; i < ARRAY_SIZE(ri_list); i++) {
 		val = readl_relaxed(ri_list[i].reg);
 		val &= ~ri_list[i].mask;
 		val |= ri_list[i].val;
 		writel_relaxed(val, ri_list[i].reg);
 	}
+}
 
+static void __init msm7x30_clock_post_init(void)
+{
+	clk_set_rate(&usb_hs_src_clk.c, 60000000);
 	clk_set_rate(&i2c_clk.c, 19200000);
 	clk_set_rate(&i2c_2_clk.c, 19200000);
 	clk_set_rate(&qup_i2c_clk.c, 19200000);
@@ -3001,7 +3006,8 @@
 struct clock_init_data msm7x30_clock_init_data __initdata = {
 	.table = msm_clocks_7x30,
 	.size = ARRAY_SIZE(msm_clocks_7x30),
-	.init = msm7x30_clock_init,
+	.pre_init = msm7x30_clock_pre_init,
+	.post_init = msm7x30_clock_post_init,
 };
 
 /*
@@ -3012,13 +3018,11 @@
 	.disable = rcg_clk_disable,
 	.auto_off = rcg_clk_disable,
 	.set_rate = rcg_clk_set_rate,
-	.get_rate = rcg_clk_get_rate,
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
 	.reset = msm7x30_clk_reset,
 	.set_flags = soc_clk_set_flags,
-	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 };
 
@@ -3029,7 +3033,5 @@
 	.is_enabled = branch_clk_is_enabled,
 	.reset = soc_branch_clk_reset,
 	.set_flags = soc_clk_set_flags,
-	.is_local = local_clk_is_local,
 	.get_parent = branch_clk_get_parent,
-	.set_parent = branch_clk_set_parent,
 };
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 8188e08..af8f0af 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -26,7 +26,6 @@
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
 #include <mach/rpm-regulator.h>
-#include <mach/msm_xo.h>
 #include <mach/socinfo.h>
 
 #include "clock-local.h"
@@ -365,9 +364,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 +371,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 +379,25 @@
 		[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_corner[] = {
+		[VDD_DIG_NONE]    = RPM_VREG_CORNER_NONE,
+		[VDD_DIG_LOW]     = RPM_VREG_CORNER_LOW,
+		[VDD_DIG_NOMINAL] = RPM_VREG_CORNER_NOMINAL,
+		[VDD_DIG_HIGH]    = RPM_VREG_CORNER_HIGH,
+	};
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+					RPM_VREG_VOTER3,
+					vdd_corner[level],
+					RPM_VREG_CORNER_HIGH, 1);
+}
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
 	.vdd_class = &vdd_dig, \
@@ -407,105 +417,60 @@
 	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
  */
 
-static struct msm_xo_voter *xo_pxo, *xo_cxo;
-
-static int pxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_ON);
-}
-
-static void pxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_pxo = {
-	.enable = pxo_clk_enable,
-	.disable = pxo_clk_disable,
-	.is_local = local_clk_is_local,
-};
-
-static struct fixed_clk pxo_clk = {
-	.c = {
-		.dbg_name = "pxo_clk",
-		.rate = 27000000,
-		.ops = &clk_ops_pxo,
-		CLK_INIT(pxo_clk.c),
-	},
-};
-
-static int cxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_ON);
-}
-
-static void cxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_cxo = {
-	.enable = cxo_clk_enable,
-	.disable = cxo_clk_disable,
-	.is_local = local_clk_is_local,
-};
-
-static struct fixed_clk cxo_clk = {
-	.c = {
-		.dbg_name = "cxo_clk",
-		.rate = 19200000,
-		.ops = &clk_ops_cxo,
-		CLK_INIT(cxo_clk.c),
-	},
-};
+DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
 
 static struct pll_clk pll2_clk = {
 	.mode_reg = MM_PLL1_MODE_REG,
@@ -515,6 +480,7 @@
 		.rate = 800000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll2_clk.c),
+		.warned = true,
 	},
 };
 
@@ -528,6 +494,7 @@
 		.vdd_class = &vdd_sr2_pll,
 		.fmax[VDD_SR2_PLL_ON] = ULONG_MAX,
 		CLK_INIT(pll3_clk.c),
+		.warned = true,
 	},
 };
 
@@ -541,6 +508,7 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
@@ -554,6 +522,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
+		.warned = true,
 	},
 };
 
@@ -567,6 +536,7 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
+		.warned = true,
 	},
 };
 
@@ -578,6 +548,7 @@
 		.rate = 975000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll15_clk.c),
+		.warned = true,
 	},
 };
 
@@ -590,12 +561,10 @@
 	.auto_off = rcg_clk_disable,
 	.handoff = rcg_clk_handoff,
 	.set_rate = rcg_clk_set_rate,
-	.get_rate = rcg_clk_get_rate,
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
 	.reset = rcg_clk_reset,
-	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 	.set_flags = rcg_clk_set_flags,
 };
@@ -609,16 +578,13 @@
 	.auto_off = branch_clk_disable,
 	.is_enabled = branch_clk_is_enabled,
 	.reset = branch_clk_reset,
-	.is_local = local_clk_is_local,
 	.get_parent = branch_clk_get_parent,
-	.set_parent = branch_clk_set_parent,
 	.handoff = branch_clk_handoff,
 	.set_flags = branch_clk_set_flags,
 };
 
 static struct clk_ops clk_ops_reset = {
 	.reset = branch_clk_reset,
-	.is_local = local_clk_is_local,
 };
 
 /* AXI Interfaces */
@@ -841,8 +807,8 @@
 	},
 };
 
-/* For 8064, gfx3d_axi_clk is set as a dependency of gmem_axi_clk at runtime */
-static struct branch_clk gfx3d_axi_clk = {
+/* gfx3d_axi_clk is set as a dependency of gmem_axi_clk at runtime */
+static struct branch_clk gfx3d_axi_clk_8064 = {
 	.b = {
 		.ctl_reg = MAXI_EN5_REG,
 		.en_mask = BIT(25),
@@ -854,7 +820,23 @@
 	.c = {
 		.dbg_name = "gfx3d_axi_clk",
 		.ops = &clk_ops_branch,
-		CLK_INIT(gfx3d_axi_clk.c),
+		CLK_INIT(gfx3d_axi_clk_8064.c),
+	},
+};
+
+static struct branch_clk gfx3d_axi_clk_8930 = {
+	.b = {
+		.ctl_reg = MAXI_EN5_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(16),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "gfx3d_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx3d_axi_clk_8930.c),
 	},
 };
 
@@ -2880,16 +2862,22 @@
 	return -ENXIO;
 }
 
-static int pix_rdi_clk_handoff(struct clk *c)
+static enum handoff pix_rdi_clk_handoff(struct clk *c)
 {
 	u32 reg;
 	struct pix_rdi_clk *clk = to_pix_rdi_clk(c);
+	enum handoff ret;
+
+	ret = branch_handoff(&clk->b, &clk->c);
+	if (ret == HANDOFF_DISABLED_CLK)
+		return ret;
 
 	reg = readl_relaxed(clk->s_reg);
 	clk->cur_rate = reg & clk->s_mask ? 1 : 0;
 	reg = readl_relaxed(clk->s2_reg);
 	clk->cur_rate = reg & clk->s2_mask ? 2 : clk->cur_rate;
-	return 0;
+
+	return HANDOFF_ENABLED_CLK;
 }
 
 static struct clk_ops clk_ops_pix_rdi_8960 = {
@@ -2901,7 +2889,6 @@
 	.get_rate = pix_rdi_clk_get_rate,
 	.list_rate = pix_rdi_clk_list_rate,
 	.reset = pix_rdi_clk_reset,
-	.is_local = local_clk_is_local,
 	.get_parent = pix_rdi_clk_get_parent,
 };
 
@@ -3352,12 +3339,41 @@
 	F_END
 };
 
+static struct clk_freq_tbl clk_tbl_gfx3d_8930[] = {
+	F_GFX3D(        0, gnd,   0,  0),
+	F_GFX3D( 27000000, pxo,   0,  0),
+	F_GFX3D( 48000000, pll8,  1,  8),
+	F_GFX3D( 54857000, pll8,  1,  7),
+	F_GFX3D( 64000000, pll8,  1,  6),
+	F_GFX3D( 76800000, pll8,  1,  5),
+	F_GFX3D( 96000000, pll8,  1,  4),
+	F_GFX3D(128000000, pll8,  1,  3),
+	F_GFX3D(145455000, pll2,  2, 11),
+	F_GFX3D(160000000, pll2,  1,  5),
+	F_GFX3D(177778000, pll2,  2,  9),
+	F_GFX3D(192000000, pll8,  1,  2),
+	F_GFX3D(200000000, pll2,  1,  4),
+	F_GFX3D(228571000, pll2,  2,  7),
+	F_GFX3D(266667000, pll2,  1,  3),
+	F_GFX3D(300000000, pll3,  1,  4),
+	F_GFX3D(320000000, pll2,  2,  5),
+	F_GFX3D(400000000, pll2,  1,  2),
+	F_GFX3D(450000000, pll15, 1,  2),
+	F_END
+};
+
 static unsigned long fmax_gfx3d_8064[MAX_VDD_LEVELS] __initdata = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 325000000,
 	[VDD_DIG_HIGH]    = 400000000
 };
 
+static unsigned long fmax_gfx3d_8930[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 192000000,
+	[VDD_DIG_NOMINAL] = 320000000,
+	[VDD_DIG_HIGH]    = 450000000
+};
+
 static struct bank_masks bmnd_info_gfx3d = {
 	.bank_sel_mask =		BIT(11),
 	.bank0_mask = {
@@ -3803,7 +3819,6 @@
 	.enable = hdmi_pll_clk_enable,
 	.disable = hdmi_pll_clk_disable,
 	.get_rate = hdmi_pll_clk_get_rate,
-	.is_local = local_clk_is_local,
 	.get_parent = hdmi_pll_clk_get_parent,
 };
 
@@ -4461,6 +4476,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);
@@ -4473,6 +4491,10 @@
 static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_tzcom_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c);
 
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
 static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
@@ -4674,10 +4696,11 @@
 	{ TEST_MM_HS(0x32), &csi_rdi2_clk.c },
 	{ TEST_MM_HS(0x33), &vcap_clk.c },
 	{ TEST_MM_HS(0x34), &vcap_npl_clk.c },
+	{ TEST_MM_HS(0x34), &gfx3d_axi_clk_8930.c },
 	{ TEST_MM_HS(0x35), &vcap_axi_clk.c },
 	{ TEST_MM_HS(0x36), &rgb_tv_clk.c },
 	{ TEST_MM_HS(0x37), &npl_tv_clk.c },
-	{ TEST_MM_HS(0x38), &gfx3d_axi_clk.c },
+	{ TEST_MM_HS(0x38), &gfx3d_axi_clk_8064.c },
 
 	{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
 	{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
@@ -4805,7 +4828,7 @@
 	struct measure_clk *clk = to_measure_clk(c);
 	unsigned ret;
 
-	ret = clk_enable(&cxo_clk.c);
+	ret = clk_prepare_enable(&cxo_clk.c);
 	if (ret) {
 		pr_warning("CXO clock failed to enable. Can't measure\n");
 		return 0;
@@ -4848,7 +4871,7 @@
 	writel_relaxed(0x38F8, PLLTEST_PAD_CFG_REG);
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 
-	clk_disable(&cxo_clk.c);
+	clk_disable_unprepare(&cxo_clk.c);
 
 	return ret;
 }
@@ -4867,7 +4890,6 @@
 static struct clk_ops measure_clk_ops = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
-	.is_local = local_clk_is_local,
 };
 
 static struct measure_clk measure_clk = {
@@ -4880,13 +4902,16 @@
 };
 
 static struct clk_lookup msm_clocks_8064[] = {
-	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_otg"),
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
 	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_gss"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -4897,17 +4922,17 @@
 	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"),
 	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 
 	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		""),
-	CLK_LOOKUP("dfab_clk",		dfab_clk.c,		""),
-	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,		""),
 	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		""),
 	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,		"clock-8960"),
 	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,		"clock-8960"),
@@ -4981,6 +5006,8 @@
 	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
 	CLK_LOOKUP("core_clk",		amp_clk.c,		""),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0034"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-0048"),
 	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-006c"),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
@@ -5014,7 +5041,8 @@
 
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
-	CLK_LOOKUP("bus_clk",		gfx3d_axi_clk.c, "footswitch-8x60.2"),
+	CLK_LOOKUP("bus_clk",
+			    gfx3d_axi_clk_8064.c, "footswitch-8x60.2"),
 	CLK_LOOKUP("iface_clk",         vcap_p_clk.c,           ""),
 	CLK_LOOKUP("iface_clk",         vcap_p_clk.c,	"footswitch-8x60.10"),
 	CLK_LOOKUP("bus_clk",		vcap_axi_clk.c,	"footswitch-8x60.10"),
@@ -5034,15 +5062,16 @@
 	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
-	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		""),
-	CLK_LOOKUP("tv_src_div_clk",	tv_src_div_clk.c,	""),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
+	CLK_LOOKUP("tv_src_div_clk",	tv_src_div_clk.c,	NULL),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,		"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
-	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		""),
+	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
 	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("hdmi_clk",		hdmi_tv_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,		"hdmi_msm.1"),
+	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"),
@@ -5064,8 +5093,8 @@
 	CLK_LOOKUP("dsi_s_pclk",	dsi2_s_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
-	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,		""),
-	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,		""),
+	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,		"hdmi_msm.1"),
+	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,		"hdmi_msm.1"),
 	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		""),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		""),
@@ -5079,8 +5108,8 @@
 	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("iface_pclk",	vpe_p_clk.c,	"footswitch-8x60.9"),
+	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"),
 	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.6"),
@@ -5101,6 +5130,7 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.4"),
 	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.2"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.3"),
 	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	""),
 	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
 	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	""),
@@ -5112,7 +5142,7 @@
 	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		""),
 	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	""),
 	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	""),
-	CLK_LOOKUP("core_clk",		gfx3d_axi_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8064.c,	""),
 
 	CLK_LOOKUP("dfab_dsps_clk",	dfab_dsps_clk.c, NULL),
 	CLK_LOOKUP("core_clk",		dfab_usb_hs_clk.c,	"msm_otg"),
@@ -5125,6 +5155,8 @@
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
+	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
+	CLK_LOOKUP("bus_clk",		dfab_tzcom_clk.c,	"tzcom"),
 
 	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
 	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
@@ -5141,8 +5173,8 @@
 	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		"msm_iommu.6"),
 	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	"msm_iommu.7"),
 	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	"msm_iommu.8"),
-	CLK_LOOKUP("core_clk",		gfx3d_axi_clk.c,	"msm_iommu.9"),
-	CLK_LOOKUP("core_clk",		gfx3d_axi_clk.c,	"msm_iommu.10"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8064.c,	"msm_iommu.9"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8064.c,	"msm_iommu.10"),
 	CLK_LOOKUP("core_clk",		vcap_axi_clk.c,		"msm_iommu.11"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
@@ -5155,12 +5187,15 @@
 };
 
 static struct clk_lookup msm_clocks_8960[] = {
-	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_otg"),
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
 	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -5171,17 +5206,17 @@
 	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"),
 	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 
 	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		NULL),
-	CLK_LOOKUP("dfab_clk",		dfab_clk.c,		NULL),
-	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,		NULL),
 	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		NULL),
 	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,		"clock-8960"),
 	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,		"clock-8960"),
@@ -5275,6 +5310,7 @@
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0048"),
 	CLK_LOOKUP("cam_clk",		cam2_clk.c,		NULL),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0020"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0034"),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		"msm_csid.2"),
@@ -5398,6 +5434,7 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.4"),
 	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.2"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.3"),
 	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	NULL),
 	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
 	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	"msm_iommu.0"),
@@ -5429,6 +5466,8 @@
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
+	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
+	CLK_LOOKUP("bus_clk",		dfab_tzcom_clk.c,	"tzcom"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
@@ -5440,6 +5479,276 @@
 	CLK_LOOKUP("q6_func_clk",	q6_func_clk,  ""),
 };
 
+static struct clk_lookup msm_clocks_8930[] = {
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
+	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
+	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
+	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
+	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	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_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"),
+	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
+
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,		"clock-8960"),
+	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,		"clock-8960"),
+
+	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp2_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gsbi1_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi2_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c, "msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		gsbi7_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi8_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi9_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi10_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi11_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi12_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c,	"spi_qsd.0"),
+	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_qup_clk.c,	"qup_i2c.3"),
+	CLK_LOOKUP("core_clk",		gsbi4_qup_clk.c,	"qup_i2c.4"),
+	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi6_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi7_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi8_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi9_qup_clk.c,	"qup_i2c.0"),
+	CLK_LOOKUP("core_clk",		gsbi10_qup_clk.c,	"qup_i2c.10"),
+	CLK_LOOKUP("core_clk",		gsbi11_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi12_qup_clk.c,	"qup_i2c.12"),
+	CLK_LOOKUP("core_clk",		pdm_clk.c,		""),
+	CLK_LOOKUP("mem_clk",		pmem_clk.c,		"msm_sps"),
+	CLK_LOOKUP("core_clk",		prng_clk.c,		"msm_rng.0"),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		sdc5_clk.c,		"msm_sdcc.5"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		""),
+	CLK_LOOKUP("core_clk",		tssc_clk.c,		""),
+	CLK_LOOKUP("alt_core_clk",	usb_hs1_xcvr_clk.c,	"msm_otg"),
+	CLK_LOOKUP("phy_clk",		usb_phy0_clk.c,		"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_fs1_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs1_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs1_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",	usb_fs2_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs2_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs2_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk",	      usb_hsic_hsio_cal_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("core_clk",	      usb_hsic_system_clk.c,   "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",	      usb_hsic_p_clk.c,        "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("dma_bam_pclk",	dma_bam_p_clk.c,	NULL),
+	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,		"spi_qsd.0"),
+	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c,		"qup_i2c.3"),
+	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		"qup_i2c.4"),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,	"msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,  "msm_serial_hs.0"),
+	CLK_LOOKUP("iface_clk",		gsbi7_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi8_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi9_p_clk.c,		"qup_i2c.0"),
+	CLK_LOOKUP("iface_clk",		gsbi10_p_clk.c,		"qup_i2c.10"),
+	CLK_LOOKUP("iface_clk",		gsbi11_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi12_p_clk.c,		"qup_i2c.12"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		usb_fs1_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_fs2_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_hs1_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc5_p_clk.c,		"msm_sdcc.5"),
+	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		pmic_arb1_p_clk.c,	""),
+	CLK_LOOKUP("core_clk",		pmic_ssbi2_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
+	CLK_LOOKUP("core_clk",		amp_clk.c,		""),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-006c"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0048"),
+	CLK_LOOKUP("cam_clk",		cam2_clk.c,		NULL),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0020"),
+	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		NULL),
+	CLK_LOOKUP("csi_pix1_clk",	csi_pix1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi1_clk",	csi_rdi1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi2_clk",	csi_rdi2_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		NULL),
+	CLK_LOOKUP("csi2phy_timer_clk",	csi2phy_timer_clk.c,	NULL),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.2"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi0phy_timer_clk.c,	"msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi1phy_timer_clk.c,	"msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi2phy_timer_clk.c,	"msm_csiphy.2"),
+	CLK_LOOKUP("dsi_byte_div_clk",	dsi1_byte_clk.c,	NULL),
+	CLK_LOOKUP("dsi_esc_clk",	dsi1_esc_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("bus_clk",
+			    gfx3d_axi_clk_8930.c, "footswitch-8x60.2"),
+	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
+	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		NULL),
+	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,            NULL),
+	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,	NULL),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("lut_mdp",		lut_mdp_clk.c,		NULL),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
+	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"),
+	CLK_LOOKUP("csi_vfe_clk",	csi_vfe_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("bus_clk",		vfe_axi_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("bus_clk",		mdp_axi_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("bus_clk",		rot_axi_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("bus_clk",		vcodec_axi_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_a_clk",	       vcodec_axi_a_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_b_clk",        vcodec_axi_b_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_clk",		vpe_axi_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("amp_pclk",		amp_p_clk.c,		NULL),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("dsi_m_pclk",	dsi1_m_p_clk.c,		NULL),
+	CLK_LOOKUP("dsi_s_pclk",	dsi1_s_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("mdp_pclk",		mdp_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
+	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,		"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"),
+	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.6"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.2"),
+	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		"msm_iommu.1"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.2"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.3"),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		"msm_iommu.4"),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		"msm_iommu.6"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8930.c,	"msm_iommu.9"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8930.c,	"msm_iommu.10"),
+
+	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_a_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_b_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"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc3_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc4_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc5_clk.c, "msm_sdcc.5"),
+	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
+	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
+	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
+
+	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+
+	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
+	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
+	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
+	CLK_LOOKUP("q6sw_clk",		q6sw_clk,     ""),
+	CLK_LOOKUP("q6fw_clk",		q6fw_clk,     ""),
+	CLK_LOOKUP("q6_func_clk",	q6_func_clk,  ""),
+};
 /*
  * Miscellaneous clock register initializations
  */
@@ -5483,8 +5792,8 @@
 	writel_relaxed(0, SW_RESET_ALL_REG);
 
 	/*
-	 * Some bits are only used on either 8960 or 8064 and are marked as
-	 * reserved bits on the other SoC. Writing to these reserved bits
+	 * Some bits are only used on 8960 or 8064 or 8930 and are marked as
+	 * reserved bits on the other SoCs. Writing to these reserved bits
 	 * should have no effect.
 	 */
 	/*
@@ -5524,6 +5833,8 @@
 	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
 	if (cpu_is_apq8064())
 		rmwreg(0x009FE4FF, MAXI_EN5_REG, 0x01FFEFFF);
+	if (cpu_is_msm8930())
+		rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
 	if (cpu_is_msm8960())
 		rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
 	else
@@ -5542,12 +5853,9 @@
 	rmwreg(0x00000000, CSI0_CC_REG,       0x00000410);
 	rmwreg(0x00000000, CSI1_CC_REG,       0x00000410);
 	rmwreg(0x80FF0000, DSI1_BYTE_CC_REG,  0xE0FF0010);
-	rmwreg(0x80FF0000, DSI2_BYTE_CC_REG,  0xE0FF0010);
 	rmwreg(0x80FF0000, DSI_PIXEL_CC_REG,  0xE0FF0010);
-	rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
 	rmwreg(0xC0FF0000, GFX3D_CC_REG,      0xE0FF0010);
 	rmwreg(0x80FF0000, IJPEG_CC_REG,      0xE0FF0010);
-	rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
 	rmwreg(0x80FF0000, MDP_CC_REG,        0xE1FF0010);
 	rmwreg(0x80FF0000, MDP_LUT_CC_REG,    0xE0FF0010);
 	rmwreg(0x80FF0000, ROT_CC_REG,        0xE0FF0010);
@@ -5556,10 +5864,17 @@
 	rmwreg(0x80FF0000, VFE_CC_REG,        0xE0FF4010);
 	rmwreg(0x800000FF, VFE_CC2_REG,       0xE00000FF);
 	rmwreg(0x80FF0000, VPE_CC_REG,        0xE0FF0010);
-	if (cpu_is_msm8960() || cpu_is_msm8930()) {
+	if (cpu_is_msm8960() || cpu_is_apq8064()) {
+		rmwreg(0x80FF0000, DSI2_BYTE_CC_REG,  0xE0FF0010);
+		rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+		rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
+	}
+	if (cpu_is_msm8960() || cpu_is_msm8930())
+		rmwreg(0x80FF0000, TV_CC_REG,         0xE1FFC010);
+
+	if (cpu_is_msm8960()) {
 		rmwreg(0x80FF0000, GFX2D0_CC_REG,     0xE0FF0010);
 		rmwreg(0x80FF0000, GFX2D1_CC_REG,     0xE0FF0010);
-		rmwreg(0x80FF0000, TV_CC_REG,         0xE1FFC010);
 	}
 	if (cpu_is_apq8064()) {
 		rmwreg(0x00000000, TV_CC_REG,         0x00004010);
@@ -5584,29 +5899,18 @@
 	writel_relaxed(0, SW_RESET_CORE_REG);
 	writel_relaxed(0, SW_RESET_CORE2_REG);
 
-	/* Reset 3D core once more, with its clock enabled. This can
-	 * eventually be done as part of the GDFS footswitch driver. */
-	clk_set_rate(&gfx3d_clk.c, 27000000);
-	clk_enable(&gfx3d_clk.c);
-	writel_relaxed(BIT(12), SW_RESET_CORE_REG);
-	mb();
-	udelay(5);
-	writel_relaxed(0, SW_RESET_CORE_REG);
-	/* Make sure reset is de-asserted before clock is disabled. */
-	mb();
-	clk_disable(&gfx3d_clk.c);
-
 	/* Enable TSSC and PDM PXO sources. */
 	writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
 	writel_relaxed(BIT(15), PDM_CLK_NS_REG);
 
 	/* Source SLIMBus xo src from slimbus reference clock */
-	if (cpu_is_msm8960() || cpu_is_msm8930())
+	if (cpu_is_msm8960())
 		writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
 
 	/* Source the dsi_byte_clks from the DSI PHY PLLs */
 	rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
-	rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+	if (cpu_is_msm8960() || cpu_is_apq8064())
+		rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
 
 	/* Source the sata_phy_ref_clk from PXO */
 	if (cpu_is_apq8064())
@@ -5666,33 +5970,28 @@
 		if (!readl_relaxed(PRNG_CLK_NS_REG))
 			writel_relaxed(0x2B, PRNG_CLK_NS_REG);
 	}
+
+	/*
+	 * Program PLL15 to 900MHz with ref clk = 27MHz and
+	 * only enable PLL main output.
+	 */
+	if (cpu_is_msm8930()) {
+		writel_relaxed(0x30021, MM_PLL3_L_VAL_REG);
+		writel_relaxed(0x1,	MM_PLL3_M_VAL_REG);
+		writel_relaxed(0x3,	MM_PLL3_N_VAL_REG);
+
+		writel_relaxed(0xC20000, MM_PLL3_CONFIG_REG);
+		writel_relaxed(0,	 MM_PLL3_TEST_CTL_REG);
+	}
 }
 
-/* Local clock driver initialization. */
-static void __init msm8960_clock_init(void)
+static void __init msm8960_clock_pre_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();
-	}
-
-	xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8960");
-	if (IS_ERR(xo_pxo)) {
-		pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
-		BUG();
-	}
-	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8960");
-	if (IS_ERR(xo_cxo)) {
-		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
-		BUG();
+		vdd_dig.set_vdd = set_vdd_dig_8930;
+		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
 	}
 
 	/*
@@ -5713,7 +6012,21 @@
 		memcpy(vfe_clk.c.fmax, fmax_vfe_8064,
 		       sizeof(vfe_clk.c.fmax));
 
-		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8064.c;
+	}
+
+	/*
+	 * Change the freq tables and voltage requirements for
+	 * clocks which differ between 8960 and 8930.
+	 */
+	if (cpu_is_msm8930()) {
+		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
+
+		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
+		       sizeof(gfx3d_clk.c.fmax));
+
+		pll15_clk.c.rate = 900000000;
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
 	}
 
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
@@ -5722,6 +6035,20 @@
 
 	/* Initialize clock registers. */
 	reg_init();
+}
+
+static void __init msm8960_clock_post_init(void)
+{
+	/* Keep PXO on whenever APPS cpu is active */
+	clk_prepare_enable(&pxo_a_clk.c);
+
+	/* Reset 3D core while clocked to ensure it resets completely. */
+	clk_set_rate(&gfx3d_clk.c, 27000000);
+	clk_prepare_enable(&gfx3d_clk.c);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_ASSERT);
+	udelay(5);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_DEASSERT);
+	clk_disable_unprepare(&gfx3d_clk.c);
 
 	/* Initialize rates for clocks that only support one. */
 	clk_set_rate(&pdm_clk.c, 27000000);
@@ -5757,8 +6084,16 @@
 	rcg_clk_disable(&pdm_clk.c);
 	rcg_clk_enable(&tssc_clk.c);
 	rcg_clk_disable(&tssc_clk.c);
-	clk_enable(&usb_hsic_hsic_clk.c);
-	clk_disable(&usb_hsic_hsic_clk.c);
+	clk_prepare_enable(&usb_hsic_hsic_clk.c);
+	clk_disable_unprepare(&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_prepare_enable(&sfab_tmr_a_clk.c);
 }
 
 static int __init msm8960_clock_late_init(void)
@@ -5774,7 +6109,7 @@
 	rc = clk_set_rate(mmfpb_a_clk, 76800000);
 	if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
 		return rc;
-	rc = clk_enable(mmfpb_a_clk);
+	rc = clk_prepare_enable(mmfpb_a_clk);
 	if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
 		return rc;
 
@@ -5785,7 +6120,7 @@
 	rc = clk_set_rate(cfpb_a_clk, 64000000);
 	if (WARN(rc, "cfpb_a_clk rate was not set (%d)\n", rc))
 		return rc;
-	rc = clk_enable(cfpb_a_clk);
+	rc = clk_prepare_enable(cfpb_a_clk);
 	if (WARN(rc, "cfpb_a_clk not enabled (%d)\n", rc))
 		return rc;
 
@@ -5795,13 +6130,23 @@
 struct clock_init_data msm8960_clock_init_data __initdata = {
 	.table = msm_clocks_8960,
 	.size = ARRAY_SIZE(msm_clocks_8960),
-	.init = msm8960_clock_init,
+	.pre_init = msm8960_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
 	.late_init = msm8960_clock_late_init,
 };
 
 struct clock_init_data apq8064_clock_init_data __initdata = {
 	.table = msm_clocks_8064,
 	.size = ARRAY_SIZE(msm_clocks_8064),
-	.init = msm8960_clock_init,
+	.pre_init = msm8960_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
+	.late_init = msm8960_clock_late_init,
+};
+
+struct clock_init_data msm8930_clock_init_data __initdata = {
+	.table = msm_clocks_8930,
+	.size = ARRAY_SIZE(msm_clocks_8930),
+	.pre_init = msm8960_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
 	.late_init = msm8960_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index d3f5396..c724414 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -24,7 +24,6 @@
 
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
-#include <mach/msm_xo.h>
 #include <mach/scm-io.h>
 #include <mach/rpm.h>
 #include <mach/rpm-regulator.h>
@@ -298,62 +297,8 @@
 	.fmax[VDD_DIG_##l2] = (f2), \
 	.fmax[VDD_DIG_##l3] = (f3)
 
-static struct msm_xo_voter *xo_pxo, *xo_cxo;
-
-static bool xo_clk_is_local(struct clk *clk)
-{
-	return false;
-}
-
-static int pxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_ON);
-}
-
-static void pxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_pxo = {
-	.enable = pxo_clk_enable,
-	.disable = pxo_clk_disable,
-	.is_local = xo_clk_is_local,
-};
-
-static struct fixed_clk pxo_clk = {
-	.c = {
-		.dbg_name = "pxo_clk",
-		.rate = 27000000,
-		.ops = &clk_ops_pxo,
-		CLK_INIT(pxo_clk.c),
-	},
-};
-
-static int cxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_ON);
-}
-
-static void cxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_cxo = {
-	.enable = cxo_clk_enable,
-	.disable = cxo_clk_disable,
-	.is_local = xo_clk_is_local,
-};
-
-static struct fixed_clk cxo_clk = {
-	.c = {
-		.dbg_name = "cxo_clk",
-		.rate = 19200000,
-		.ops = &clk_ops_cxo,
-		CLK_INIT(cxo_clk.c),
-	},
-};
+DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
 
 static struct pll_vote_clk pll8_clk = {
 	.en_reg = BB_PLL_ENA_SC0_REG,
@@ -365,6 +310,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
+		.warned = true,
 	},
 };
 
@@ -376,6 +322,7 @@
 		.rate = 800000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll2_clk.c),
+		.warned = true,
 	},
 };
 
@@ -387,6 +334,7 @@
 		.rate = 0, /* TODO: Detect rate dynamically */
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll3_clk.c),
+		.warned = true,
 	},
 };
 
@@ -425,6 +373,7 @@
 		.rate = 540672000,
 		.ops = &clk_ops_pll4,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
@@ -486,12 +435,10 @@
 	.auto_off = rcg_clk_disable,
 	.handoff = rcg_clk_handoff,
 	.set_rate = rcg_clk_set_rate,
-	.get_rate = rcg_clk_get_rate,
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
 	.reset = rcg_clk_reset,
-	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 	.set_flags = rcg_clk_set_flags,
 };
@@ -502,15 +449,12 @@
 	.auto_off = branch_clk_disable,
 	.is_enabled = branch_clk_is_enabled,
 	.reset = branch_clk_reset,
-	.is_local = local_clk_is_local,
 	.get_parent = branch_clk_get_parent,
-	.set_parent = branch_clk_set_parent,
 	.set_flags = branch_clk_set_flags,
 };
 
 static struct clk_ops clk_ops_reset = {
 	.reset = branch_clk_reset,
-	.is_local = local_clk_is_local,
 };
 
 /*
@@ -3534,7 +3478,6 @@
 static struct clk_ops measure_clk_ops = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
-	.is_local = local_clk_is_local,
 };
 
 static struct measure_clk measure_clk = {
@@ -3548,7 +3491,9 @@
 };
 
 static struct clk_lookup msm_clocks_8x60[] = {
-	CLK_LOOKUP("cxo",		cxo_clk.c,	NULL),
+	CLK_LOOKUP("xo",		cxo_clk.c,	""),
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_modem"),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	"pil_qdsp6v3"),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
@@ -3765,6 +3710,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"),
@@ -3795,8 +3746,10 @@
 	writel_relaxed(regval, reg);
 }
 
-static void __init reg_init(void)
+static void __init msm8660_clock_pre_init(void)
 {
+	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+
 	/* Setup MM_PLL2 (PLL3), but turn it off. Rate set by set_rate_tv(). */
 	rmwreg(0, MM_PLL2_MODE_REG, BIT(0)); /* Disable output */
 	/* Set ref, bypass, assert reset, disable output, disable test mode */
@@ -3860,18 +3813,6 @@
 	/* Deassert all MM core resets. */
 	writel_relaxed(0, SW_RESET_CORE_REG);
 
-	/* Reset 3D core once more, with its clock enabled. This can
-	 * eventually be done as part of the GDFS footswitch driver. */
-	clk_set_rate(&gfx3d_clk.c, 27000000);
-	clk_enable(&gfx3d_clk.c);
-	writel_relaxed(BIT(12), SW_RESET_CORE_REG);
-	mb();
-	udelay(5);
-	writel_relaxed(0, SW_RESET_CORE_REG);
-	/* Make sure reset is de-asserted before clock is disabled. */
-	mb();
-	clk_disable(&gfx3d_clk.c);
-
 	/* Enable TSSC and PDM PXO sources. */
 	writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
 	writel_relaxed(BIT(15), PDM_CLK_NS_REG);
@@ -3880,23 +3821,18 @@
 	rmwreg(0x400001, MISC_CC2_REG, 0x424003);
 }
 
-/* Local clock driver initialization. */
-static void __init msm8660_clock_init(void)
+static void __init msm8660_clock_post_init(void)
 {
-	xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8x60");
-	if (IS_ERR(xo_pxo)) {
-		pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
-		BUG();
-	}
-	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8x60");
-	if (IS_ERR(xo_cxo)) {
-		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
-		BUG();
-	}
+	/* Keep PXO on whenever APPS cpu is active */
+	clk_prepare_enable(&pxo_a_clk.c);
 
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	/* Initialize clock registers. */
-	reg_init();
+	/* Reset 3D core while clocked to ensure it resets completely. */
+	clk_set_rate(&gfx3d_clk.c, 27000000);
+	clk_prepare_enable(&gfx3d_clk.c);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_ASSERT);
+	udelay(5);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_DEASSERT);
+	clk_disable_unprepare(&gfx3d_clk.c);
 
 	/* Initialize rates for clocks that only support one. */
 	clk_set_rate(&pdm_clk.c, 27000000);
@@ -3928,7 +3864,7 @@
 	rc = clk_set_rate(mmfpb_a_clk, 64000000);
 	if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
 		return rc;
-	rc = clk_enable(mmfpb_a_clk);
+	rc = clk_prepare_enable(mmfpb_a_clk);
 	if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
 		return rc;
 
@@ -3938,6 +3874,7 @@
 struct clock_init_data msm8x60_clock_init_data __initdata = {
 	.table = msm_clocks_8x60,
 	.size = ARRAY_SIZE(msm_clocks_8x60),
-	.init = msm8660_clock_init,
+	.pre_init = msm8660_clock_pre_init,
+	.post_init = msm8660_clock_post_init,
 	.late_init = msm8660_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index df9c152..89e3036 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -25,7 +25,6 @@
 
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
-#include <mach/msm_xo.h>
 #include <mach/rpm-9615.h>
 #include <mach/rpm-regulator.h>
 
@@ -208,32 +207,7 @@
  * Clock Descriptions
  */
 
-static struct msm_xo_voter *xo_cxo;
-
-static int cxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_ON);
-}
-
-static void cxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_cxo = {
-	.enable = cxo_clk_enable,
-	.disable = cxo_clk_disable,
-	.is_local = local_clk_is_local,
-};
-
-static struct fixed_clk cxo_clk = {
-	.c = {
-		.dbg_name = "cxo_clk",
-		.rate = 19200000,
-		.ops = &clk_ops_cxo,
-		CLK_INIT(cxo_clk.c),
-	},
-};
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
 
 static DEFINE_SPINLOCK(soft_vote_lock);
 
@@ -274,7 +248,6 @@
 	.auto_off = pll_acpu_vote_clk_disable,
 	.is_enabled = pll_vote_clk_is_enabled,
 	.get_parent = pll_vote_clk_get_parent,
-	.is_local = local_clk_is_local,
 };
 
 #define PLL_SOFT_VOTE_PRIMARY	BIT(0)
@@ -294,6 +267,7 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_clk.c),
+		.warned = true,
 	},
 };
 
@@ -308,6 +282,7 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_acpu_clk.c),
+		.warned = true,
 	},
 };
 
@@ -321,6 +296,7 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
@@ -338,6 +314,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_clk.c),
+		.warned = true,
 	},
 };
 
@@ -352,6 +329,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_acpu_clk.c),
+		.warned = true,
 	},
 };
 
@@ -362,6 +340,7 @@
 		.rate = 440000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll9_acpu_clk.c),
+		.warned = true,
 	},
 };
 
@@ -375,6 +354,7 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
+		.warned = true,
 	},
 };
 
@@ -387,12 +367,10 @@
 	.in_hwcg_mode = rcg_clk_in_hwcg_mode,
 	.handoff = rcg_clk_handoff,
 	.set_rate = rcg_clk_set_rate,
-	.get_rate = rcg_clk_get_rate,
 	.list_rate = rcg_clk_list_rate,
 	.is_enabled = rcg_clk_is_enabled,
 	.round_rate = rcg_clk_round_rate,
 	.reset = rcg_clk_reset,
-	.is_local = local_clk_is_local,
 	.get_parent = rcg_clk_get_parent,
 };
 
@@ -406,9 +384,7 @@
 	.handoff = branch_clk_handoff,
 	.is_enabled = branch_clk_is_enabled,
 	.reset = branch_clk_reset,
-	.is_local = local_clk_is_local,
 	.get_parent = branch_clk_get_parent,
-	.set_parent = branch_clk_set_parent,
 };
 
 /*
@@ -663,7 +639,7 @@
 		.c = { \
 			.dbg_name = #name, \
 			.ops = &clk_ops_rcg_9615, \
-			VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000), \
+			VDD_DIG_FMAX_MAP2(LOW, 26000000, NOMINAL, 52000000), \
 			CLK_INIT(name.c), \
 		}, \
 	}
@@ -682,7 +658,10 @@
 	F_SDC( 17070000, pll8,  1, 2,  45),
 	F_SDC( 20210000, pll8,  1, 1,  19),
 	F_SDC( 24000000, pll8,  4, 1,   4),
+	F_SDC( 38400000, pll8,  2, 1,   5),
 	F_SDC( 48000000, pll8,  4, 1,   2),
+	F_SDC( 64000000, pll8,  3, 1,   2),
+	F_SDC( 76800000, pll8,  1, 1,   5),
 	F_END
 };
 
@@ -1377,13 +1356,10 @@
 static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c);
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
-
-/*
- * TODO: replace dummy_clk below with ebi1_clk.c once the
- * bus driver starts voting on ebi1 rates.
- */
-static DEFINE_CLK_VOTER(ebi1_adm_clk,    &dummy_clk);
+static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
 
 #ifdef CONFIG_DEBUG_FS
 struct measure_sel {
@@ -1608,7 +1584,6 @@
 static struct clk_ops measure_clk_ops = {
 	.set_parent = measure_clk_set_parent,
 	.get_rate = measure_clk_get_rate,
-	.is_local = local_clk_is_local,
 };
 
 static struct measure_clk measure_clk = {
@@ -1621,7 +1596,9 @@
 };
 
 static struct clk_lookup msm_clocks_9615[] = {
-	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_otg"),
+	CLK_LOOKUP("xo",	cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",	cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_xo"),
 	CLK_LOOKUP("pll0",	pll0_clk.c,	NULL),
 	CLK_LOOKUP("pll8",	pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
@@ -1636,14 +1613,14 @@
 	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,		"msm_sys_fab"),
 	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 
 	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	NULL),
 	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,	NULL),
 	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	NULL),
 	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,	NULL),
 	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
-	CLK_LOOKUP("dfab_clk",		dfab_clk.c,	NULL),
-	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,	NULL),
 
 	CLK_LOOKUP("core_clk",		gp0_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,	""),
@@ -1712,6 +1689,7 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.4"),
 	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	"msm-dai-q6.2"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	"msm-dai-q6.3"),
 
 	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	NULL),
 	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
@@ -1730,11 +1708,6 @@
 	CLK_LOOKUP("q6sw_clk",		q6sw_clk, NULL),
 	CLK_LOOKUP("q6fw_clk",		q6fw_clk, NULL),
 	CLK_LOOKUP("q6_func_clk",	q6_func_clk, NULL),
-
-	/* TODO: Make this real when RPM's ready. */
-	CLK_DUMMY("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL, OFF),
-	CLK_DUMMY("mem_clk",		ebi1_adm_clk.c, "msm_dmov", OFF),
-
 };
 
 static void set_fsm_mode(void __iomem *mode_reg)
@@ -1763,10 +1736,14 @@
 /*
  * Miscellaneous clock register initializations
  */
-static void __init reg_init(void)
+static void __init msm9615_clock_pre_init(void)
 {
 	u32 regval, is_pll_enabled, pll9_lval;
 
+	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+
+	clk_ops_pll.enable = sr_pll_clk_enable;
+
 	/* Enable PDM CXO source. */
 	regval = readl_relaxed(PDM_CLK_NS_REG);
 	writel_relaxed(BIT(13) | regval, PDM_CLK_NS_REG);
@@ -1855,21 +1832,10 @@
 	writel_relaxed(regval, DMA_BAM_HCLK_CTL);
 }
 
-/* Local clock driver initialization. */
-static void __init msm9615_clock_init(void)
+static void __init msm9615_clock_post_init(void)
 {
-	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-9615");
-	if (IS_ERR(xo_cxo)) {
-		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
-		BUG();
-	}
-
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-
-	clk_ops_pll.enable = sr_pll_clk_enable;
-
-	/* Initialize clock registers. */
-	reg_init();
+	/* Keep CXO on whenever APPS cpu is active */
+	clk_prepare_enable(&cxo_a_clk.c);
 
 	/* Initialize rates for clocks that only support one. */
 	clk_set_rate(&pdm_clk.c, 19200000);
@@ -1896,6 +1862,7 @@
 struct clock_init_data msm9615_clock_init_data __initdata = {
 	.table = msm_clocks_9615,
 	.size = ARRAY_SIZE(msm_clocks_9615),
-	.init = msm9615_clock_init,
+	.pre_init = msm9615_clock_pre_init,
+	.post_init = msm9615_clock_post_init,
 	.late_init = msm9615_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 411a272..54b13e6 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-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
@@ -92,9 +92,9 @@
 	int rc = 0;
 
 	if (val)
-		rc = clk_enable(clock);
+		rc = clk_prepare_enable(clock);
 	else
-		clk_disable(clock);
+		clk_disable_unprepare(clock);
 
 	return rc;
 }
@@ -120,7 +120,10 @@
 {
 	struct clk *clock = data;
 
-	*val = clock->ops->is_local(clock);
+	if (!clock->ops->is_local)
+		*val = true;
+	else
+		*val = clock->ops->is_local(clock);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
index dfd4a67..54c9de8 100644
--- a/arch/arm/mach-msm/clock-dummy.c
+++ b/arch/arm/mach-msm/clock-dummy.c
@@ -42,11 +42,6 @@
 	return rate;
 }
 
-static bool dummy_clk_is_local(struct clk *clk)
-{
-	return true;
-}
-
 static struct clk_ops clk_ops_dummy = {
 	.reset = dummy_clk_reset,
 	.set_rate = dummy_clk_set_rate,
@@ -54,7 +49,6 @@
 	.set_flags = dummy_clk_set_flags,
 	.get_rate = dummy_clk_get_rate,
 	.round_rate = dummy_clk_round_rate,
-	.is_local = dummy_clk_is_local,
 };
 
 struct clk dummy_clk = {
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 4f68fb4..84aa086 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -526,27 +526,6 @@
 	return rc;
 }
 
-/* Get the currently-set rate of a clock in Hz. */
-unsigned long rcg_clk_get_rate(struct clk *c)
-{
-	struct rcg_clk *clk = to_rcg_clk(c);
-	unsigned long flags;
-	unsigned ret = 0;
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	ret = clk->current_freq->freq_hz;
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
-	/*
-	 * Return 0 if the rate has never been set. Might not be correct,
-	 * but it's good enough.
-	 */
-	if (ret == FREQ_END)
-		ret = 0;
-
-	return ret;
-}
-
 /* Check if a clock is currently enabled. */
 int rcg_clk_is_enabled(struct clk *clk)
 {
@@ -566,11 +545,6 @@
 	return -EPERM;
 }
 
-bool local_clk_is_local(struct clk *clk)
-{
-	return true;
-}
-
 /* Return the nth supported frequency for a given clock. */
 int rcg_clk_list_rate(struct clk *c, unsigned n)
 {
@@ -588,34 +562,36 @@
 }
 
 /* Disable hw clock gating if not set at boot */
-static void branch_handoff(struct branch *clk, struct clk *c)
+enum handoff branch_handoff(struct branch *clk, struct clk *c)
 {
 	if (!branch_in_hwcg_mode(clk)) {
 		clk->hwcg_mask = 0;
 		c->flags &= ~CLKFLAG_HWCG;
+		if (readl_relaxed(clk->ctl_reg) & clk->en_mask)
+			return HANDOFF_ENABLED_CLK;
 	} else {
 		c->flags |= CLKFLAG_HWCG;
 	}
+	return HANDOFF_DISABLED_CLK;
 }
 
-int branch_clk_handoff(struct clk *c)
+enum handoff branch_clk_handoff(struct clk *c)
 {
 	struct branch_clk *clk = to_branch_clk(c);
-	branch_handoff(&clk->b, &clk->c);
-	return 0;
+	return branch_handoff(&clk->b, &clk->c);
 }
 
-int rcg_clk_handoff(struct clk *c)
+enum handoff rcg_clk_handoff(struct clk *c)
 {
 	struct rcg_clk *clk = to_rcg_clk(c);
 	uint32_t ctl_val, ns_val, md_val, ns_mask;
 	struct clk_freq_tbl *freq;
-
-	branch_handoff(&clk->b, &clk->c);
+	enum handoff ret;
 
 	ctl_val = readl_relaxed(clk->b.ctl_reg);
-	if (!(ctl_val & clk->root_en_mask))
-		return 0;
+	ret = branch_handoff(&clk->b, &clk->c);
+	if (ret == HANDOFF_DISABLED_CLK)
+		return HANDOFF_DISABLED_CLK;
 
 	if (clk->bank_info) {
 		const struct bank_masks *bank_masks = clk->bank_info;
@@ -632,7 +608,8 @@
 		ns_mask = clk->ns_mask;
 		md_val = clk->md_reg ? readl_relaxed(clk->md_reg) : 0;
 	}
-
+	if (!ns_mask)
+		return HANDOFF_UNKNOWN_RATE;
 	ns_val = readl_relaxed(clk->ns_reg) & ns_mask;
 	for (freq = clk->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
 		if ((freq->ns_val & ns_mask) == ns_val &&
@@ -642,11 +619,12 @@
 		}
 	}
 	if (freq->freq_hz == FREQ_END)
-		return 0;
+		return HANDOFF_UNKNOWN_RATE;
 
 	clk->current_freq = freq;
+	c->rate = freq->freq_hz;
 
-	return 1;
+	return HANDOFF_ENABLED_CLK;
 }
 
 int pll_vote_clk_enable(struct clk *clk)
@@ -699,7 +677,6 @@
 	.auto_off = pll_vote_clk_disable,
 	.is_enabled = pll_vote_clk_is_enabled,
 	.get_parent = pll_vote_clk_get_parent,
-	.is_local = local_clk_is_local,
 };
 
 static int pll_clk_enable(struct clk *clk)
@@ -800,11 +777,9 @@
 	.disable = pll_clk_disable,
 	.auto_off = pll_clk_disable,
 	.get_parent = pll_clk_get_parent,
-	.is_local = local_clk_is_local,
 };
 
 struct clk_ops clk_ops_gnd = {
-	.is_local = local_clk_is_local,
 };
 
 struct fixed_clk gnd_clk = {
@@ -816,7 +791,6 @@
 };
 
 struct clk_ops clk_ops_measure = {
-	.is_local = local_clk_is_local,
 };
 
 int branch_clk_enable(struct clk *clk)
@@ -849,19 +823,6 @@
 	return branch->parent;
 }
 
-int branch_clk_set_parent(struct clk *clk, struct clk *parent)
-{
-	/*
-	 * We setup the parent pointer at init time in msm_clock_init().
-	 * This check is to make sure drivers can't change the parent.
-	 */
-	if (parent && list_empty(&clk->siblings)) {
-		list_add(&clk->siblings, &parent->children);
-		return 0;
-	}
-	return -EINVAL;
-}
-
 int branch_clk_is_enabled(struct clk *clk)
 {
 	struct branch_clk *branch = to_branch_clk(clk);
@@ -1078,12 +1039,15 @@
 	return n > clk->max_div ? -ENXIO : n;
 }
 
-static int cdiv_clk_handoff(struct clk *c)
+static enum handoff cdiv_clk_handoff(struct clk *c)
 {
 	struct cdiv_clk *clk = to_cdiv_clk(c);
+	enum handoff ret;
 	u32 reg_val;
 
-	branch_handoff(&clk->b, &clk->c);
+	ret = branch_handoff(&clk->b, &clk->c);
+	if (ret == HANDOFF_DISABLED_CLK)
+		return ret;
 
 	reg_val = readl_relaxed(clk->ns_reg);
 	if (reg_val & clk->ext_mask) {
@@ -1093,7 +1057,7 @@
 		clk->cur_div = (reg_val & (clk->max_div - 1)) + 1;
 	}
 
-	return 0;
+	return HANDOFF_ENABLED_CLK;
 }
 
 static void cdiv_clk_enable_hwcg(struct clk *c)
@@ -1126,5 +1090,4 @@
 	.get_rate = cdiv_clk_get_rate,
 	.list_rate = cdiv_clk_list_rate,
 	.round_rate = cdiv_clk_round_rate,
-	.is_local = local_clk_is_local,
 };
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index c587b43..3dd849a 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -171,7 +171,8 @@
 int branch_reset(struct branch *b, enum clk_reset_action action);
 void __branch_clk_enable_reg(const struct branch *clk, const char *name);
 u32 __branch_clk_disable_reg(const struct branch *clk, const char *name);
-int branch_clk_handoff(struct clk *c);
+enum handoff branch_clk_handoff(struct clk *c);
+enum handoff branch_handoff(struct branch *clk, struct clk *c);
 int branch_clk_set_flags(struct clk *clk, unsigned flags);
 
 /*
@@ -207,12 +208,11 @@
 int rcg_clk_enable(struct clk *clk);
 void rcg_clk_disable(struct clk *clk);
 int rcg_clk_set_rate(struct clk *clk, unsigned long rate);
-unsigned long rcg_clk_get_rate(struct clk *clk);
 int rcg_clk_list_rate(struct clk *clk, unsigned n);
 int rcg_clk_is_enabled(struct clk *clk);
 long rcg_clk_round_rate(struct clk *clk, unsigned long rate);
 struct clk *rcg_clk_get_parent(struct clk *c);
-int rcg_clk_handoff(struct clk *c);
+enum handoff rcg_clk_handoff(struct clk *c);
 int rcg_clk_reset(struct clk *clk, enum clk_reset_action action);
 void rcg_clk_enable_hwcg(struct clk *clk);
 void rcg_clk_disable_hwcg(struct clk *clk);
@@ -331,7 +331,6 @@
 int branch_clk_enable(struct clk *clk);
 void branch_clk_disable(struct clk *clk);
 struct clk *branch_clk_get_parent(struct clk *clk);
-int branch_clk_set_parent(struct clk *clk, struct clk *parent);
 int branch_clk_is_enabled(struct clk *clk);
 int branch_clk_reset(struct clk *c, enum clk_reset_action action);
 void branch_clk_enable_hwcg(struct clk *clk);
@@ -366,11 +365,6 @@
 extern struct fixed_clk		gnd_clk;
 
 /*
- * Local-clock APIs
- */
-bool local_clk_is_local(struct clk *clk);
-
-/*
  * PLL vote clock APIs
  */
 int pll_vote_clk_enable(struct clk *clk);
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index 200cbfe..ed3b8c2 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,19 +298,30 @@
 	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),
+	.pre_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),
 	CLK_LOOKUP("ahb_s_clk",		ahb_s_clk.c,	NULL),
 	CLK_LOOKUP("cam_m_clk",		cam_m_clk.c,	NULL),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0036"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-001b"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0010"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0078"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-006c"),
 	CLK_LOOKUP("csi_clk",		csi0_clk.c,	"msm_camera_ov9726.0"),
 	CLK_LOOKUP("csi_pclk",		csi0_p_clk.c,	"msm_camera_ov9726.0"),
 	CLK_LOOKUP("csi_vfe_clk",	csi0_vfe_clk.c,	"msm_camera_ov9726.0"),
@@ -340,11 +398,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_pre_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,
+	.pre_init = msm7627a_clock_pre_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..68c390a
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -0,0 +1,196 @@
+/*
+ * 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},
+	{63, 1209600000},
+	{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 enum handoff 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 HANDOFF_ENABLED_CLK;
+}
+
+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/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index fc2e83f..ae87bb7 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -187,12 +187,6 @@
 	return false;
 }
 
-static unsigned long rpm_branch_clk_get_rate(struct clk *clk)
-{
-	struct rpm_clk *r = to_rpm_clk(clk);
-	return r->last_set_khz * 1000;
-}
-
 struct clk_ops clk_ops_rpm = {
 	.enable = rpm_clk_enable,
 	.disable = rpm_clk_disable,
@@ -207,5 +201,4 @@
 	.enable = rpm_clk_enable,
 	.disable = rpm_clk_disable,
 	.is_local = rpm_clk_is_local,
-	.get_rate = rpm_branch_clk_get_rate,
 };
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 27afd6f..b0d5693 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -67,34 +67,38 @@
 		}, \
 	};
 
-#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, rate) \
+#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
 	static struct rpm_clk active; \
 	static struct rpm_clk name = { \
 		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
 		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
 		.peer = &active, \
-		.last_set_khz = ((rate) / 1000), \
-		.last_set_sleep_khz = ((rate) / 1000), \
+		.last_set_khz = ((r) / 1000), \
+		.last_set_sleep_khz = ((r) / 1000), \
 		.branch = true, \
 		.c = { \
 			.ops = &clk_ops_rpm_branch, \
 			.flags = CLKFLAG_SKIP_AUTO_OFF, \
 			.dbg_name = #name, \
+			.rate = (r), \
 			CLK_INIT(name.c), \
+			.warned = true, \
 		}, \
 	}; \
 	static struct rpm_clk active = { \
 		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
 		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
 		.peer = &name, \
-		.last_set_khz = ((rate) / 1000), \
+		.last_set_khz = ((r) / 1000), \
 		.active_only = true, \
 		.branch = true, \
 		.c = { \
 			.ops = &clk_ops_rpm_branch, \
 			.flags = CLKFLAG_SKIP_AUTO_OFF, \
 			.dbg_name = #active, \
+			.rate = (r), \
 			CLK_INIT(active.c), \
+			.warned = true, \
 		}, \
 	};
 
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index ef502b3..9ad653d 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -148,18 +148,6 @@
 	return clk_round_rate(v->parent, rate);
 }
 
-static int voter_clk_set_parent(struct clk *clk, struct clk *parent)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&voter_clk_lock, flags);
-	if (list_empty(&clk->siblings))
-		list_add(&clk->siblings, &parent->children);
-	spin_unlock_irqrestore(&voter_clk_lock, flags);
-
-	return 0;
-}
-
 static struct clk *voter_clk_get_parent(struct clk *clk)
 {
 	struct clk_voter *v = to_clk_voter(clk);
@@ -178,7 +166,6 @@
 	.get_rate = voter_clk_get_rate,
 	.is_enabled = voter_clk_is_enabled,
 	.round_rate = voter_clk_round_rate,
-	.set_parent = voter_clk_set_parent,
 	.get_parent = voter_clk_get_parent,
 	.is_local = voter_clk_is_local,
 };
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 5b89fa9..09bf036 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <trace/events/power.h>
 
 #include "clock.h"
 
@@ -127,6 +128,41 @@
 	unvote_vdd_level(clk->vdd_class, level);
 }
 
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+	struct clk *parent;
+	if (!clk)
+		return 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0) {
+		parent = clk_get_parent(clk);
+
+		ret = clk_prepare(parent);
+		if (ret)
+			goto out;
+		ret = clk_prepare(clk->depends);
+		if (ret)
+			goto err_prepare_depends;
+
+		if (clk->ops->prepare)
+			ret = clk->ops->prepare(clk);
+		if (ret)
+			goto err_prepare_clock;
+	}
+	clk->prepare_count++;
+out:
+	mutex_unlock(&clk->prepare_lock);
+	return ret;
+err_prepare_clock:
+	clk_unprepare(clk->depends);
+err_prepare_depends:
+	clk_unprepare(parent);
+	goto out;
+}
+EXPORT_SYMBOL(clk_prepare);
+
 /*
  * Standard clock functions defined in include/linux/clk.h
  */
@@ -140,6 +176,10 @@
 		return 0;
 
 	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Don't call enable on unprepared clocks\n",
+				clk->dbg_name))
+		clk->warned = true;
 	if (clk->count == 0) {
 		parent = clk_get_parent(clk);
 
@@ -153,6 +193,7 @@
 		ret = vote_rate_vdd(clk, clk->rate);
 		if (ret)
 			goto err_vote_vdd;
+		trace_clock_enable(clk->dbg_name, 1, smp_processor_id());
 		if (clk->ops->enable)
 			ret = clk->ops->enable(clk);
 		if (ret)
@@ -193,11 +234,17 @@
 		return;
 
 	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Never called prepare or calling disable "
+				"after unprepare\n",
+				clk->dbg_name))
+		clk->warned = true;
 	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
 		goto out;
 	if (clk->count == 1) {
 		struct clk *parent = clk_get_parent(clk);
 
+		trace_clock_disable(clk->dbg_name, 0, smp_processor_id());
 		if (clk->ops->disable)
 			clk->ops->disable(clk);
 		unvote_rate_vdd(clk, clk->rate);
@@ -210,6 +257,37 @@
 }
 EXPORT_SYMBOL(clk_disable);
 
+void clk_unprepare(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	mutex_lock(&clk->prepare_lock);
+	if (!clk->prepare_count) {
+		if (WARN(!clk->warned, "%s is unbalanced (prepare)",
+				clk->dbg_name))
+			clk->warned = true;
+		goto out;
+	}
+	if (clk->prepare_count == 1) {
+		struct clk *parent = clk_get_parent(clk);
+
+		if (WARN(!clk->warned && clk->count,
+			"%s: Don't call unprepare when the clock is enabled\n",
+				clk->dbg_name))
+			clk->warned = true;
+
+		if (clk->ops->unprepare)
+			clk->ops->unprepare(clk);
+		clk_unprepare(clk->depends);
+		clk_unprepare(parent);
+	}
+	clk->prepare_count--;
+out:
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL(clk_unprepare);
+
 int clk_reset(struct clk *clk, enum clk_reset_action action)
 {
 	if (!clk->ops->reset)
@@ -237,6 +315,7 @@
 		return -ENOSYS;
 
 	spin_lock_irqsave(&clk->lock, flags);
+	trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
 	if (clk->count) {
 		start_rate = clk->rate;
 		/* Enforce vdd requirements for target frequency. */
@@ -320,27 +399,40 @@
 	unsigned n;
 	struct clk_lookup *clock_tbl;
 	size_t num_clocks;
+	struct clk *clk;
 
 	clk_init_data = data;
-	if (clk_init_data->init)
-		clk_init_data->init();
+	if (clk_init_data->pre_init)
+		clk_init_data->pre_init();
 
 	clock_tbl = data->table;
 	num_clocks = data->size;
 
 	for (n = 0; n < num_clocks; n++) {
-		struct clk *clk = clock_tbl[n].clk;
-		struct clk *parent = clk_get_parent(clk);
-		clk_set_parent(clk, parent);
-		if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE)) {
-			if (clk->ops->handoff(clk)) {
-				clk->flags |= CLKFLAG_HANDOFF_RATE;
-				clk_enable(clk);
-			}
+		struct clk *parent;
+		clk = clock_tbl[n].clk;
+		parent = clk_get_parent(clk);
+		if (parent && list_empty(&clk->siblings))
+			list_add(&clk->siblings, &parent->children);
+	}
+
+	/*
+	 * Detect and preserve initial clock state until clock_late_init() or
+	 * a driver explicitly changes it, whichever is first.
+	 */
+	for (n = 0; n < num_clocks; n++) {
+		clk = clock_tbl[n].clk;
+		if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE) &&
+		    (clk->ops->handoff(clk) == HANDOFF_ENABLED_CLK)) {
+			clk->flags |= CLKFLAG_HANDOFF_RATE;
+			clk_prepare_enable(clk);
 		}
 	}
 
 	clkdev_add_table(clock_tbl, num_clocks);
+
+	if (clk_init_data->post_init)
+		clk_init_data->post_init();
 }
 
 /*
@@ -360,24 +452,24 @@
 		bool handoff = false;
 
 		clock_debug_add(clk);
+		spin_lock_irqsave(&clk->lock, flags);
 		if (!(clk->flags & CLKFLAG_SKIP_AUTO_OFF)) {
-			spin_lock_irqsave(&clk->lock, flags);
 			if (!clk->count && clk->ops->auto_off) {
 				count++;
 				clk->ops->auto_off(clk);
 			}
-			if (clk->flags & CLKFLAG_HANDOFF_RATE) {
-				clk->flags &= ~CLKFLAG_HANDOFF_RATE;
-				handoff = true;
-			}
-			spin_unlock_irqrestore(&clk->lock, flags);
-			/*
-			 * Calling clk_disable() outside the lock is safe since
-			 * it doesn't need to be atomic with the flag change.
-			 */
-			if (handoff)
-				clk_disable(clk);
 		}
+		if (clk->flags & CLKFLAG_HANDOFF_RATE) {
+			clk->flags &= ~CLKFLAG_HANDOFF_RATE;
+			handoff = true;
+		}
+		spin_unlock_irqrestore(&clk->lock, flags);
+		/*
+		 * Calling this outside the lock is safe since
+		 * it doesn't need to be atomic with the flag change.
+		 */
+		if (handoff)
+			clk_disable_unprepare(clk);
 	}
 	pr_info("clock_late_init() disabled %d unused clocks\n", count);
 	if (clk_init_data->late_init)
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 4210bd9..60be654 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 #include <linux/clkdev.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 
 #include <mach/clk.h>
 
@@ -62,14 +63,22 @@
 		.lock = __SPIN_LOCK_UNLOCKED(lock) \
 	}
 
+enum handoff {
+	HANDOFF_ENABLED_CLK,
+	HANDOFF_DISABLED_CLK,
+	HANDOFF_UNKNOWN_RATE,
+};
+
 struct clk_ops {
+	int (*prepare)(struct clk *clk);
 	int (*enable)(struct clk *clk);
 	void (*disable)(struct clk *clk);
+	void (*unprepare)(struct clk *clk);
 	void (*auto_off)(struct clk *clk);
 	void (*enable_hwcg)(struct clk *clk);
 	void (*disable_hwcg)(struct clk *clk);
 	int (*in_hwcg_mode)(struct clk *clk);
-	int (*handoff)(struct clk *clk);
+	enum handoff (*handoff)(struct clk *clk);
 	int (*reset)(struct clk *clk, enum clk_reset_action action);
 	int (*set_rate)(struct clk *clk, unsigned long rate);
 	int (*set_max_rate)(struct clk *clk, unsigned long rate);
@@ -85,11 +94,14 @@
 
 /**
  * struct clk
+ * @prepare_count: prepare refcount
+ * @prepare_lock: protects clk_prepare()/clk_unprepare() path and @prepare_count
  * @count: enable refcount
  * @lock: protects clk_enable()/clk_disable() path and @count
  * @depends: non-direct parent of clock to enable when this clock is enabled
  * @vdd_class: voltage scaling requirement class
  * @fmax: maximum frequency in Hz supported at each voltage level
+ * @warned: true if the clock has warned of incorrect usage, false otherwise
  */
 struct clk {
 	uint32_t flags;
@@ -103,12 +115,16 @@
 	struct list_head children;
 	struct list_head siblings;
 
+	bool warned;
 	unsigned count;
 	spinlock_t lock;
+	unsigned prepare_count;
+	struct mutex prepare_lock;
 };
 
 #define CLK_INIT(name) \
 	.lock = __SPIN_LOCK_UNLOCKED((name).lock), \
+	.prepare_lock = __MUTEX_INITIALIZER((name).prepare_lock), \
 	.children = LIST_HEAD_INIT((name).children), \
 	.siblings = LIST_HEAD_INIT((name).siblings)
 
@@ -116,13 +132,15 @@
  * struct clock_init_data - SoC specific clock initialization data
  * @table: table of lookups to add
  * @size: size of @table
- * @init: called before registering @table
+ * @pre_init: called before initializing the clock driver.
+ * @post_init: called after registering @table. clock APIs can be called inside.
  * @late_init: called during late init
  */
 struct clock_init_data {
 	struct clk_lookup *table;
 	size_t size;
-	void (*init)(void);
+	void (*pre_init)(void);
+	void (*post_init)(void);
 	int (*late_init)(void);
 };
 
@@ -139,6 +157,7 @@
 extern struct clock_init_data msm8x60_clock_init_data;
 extern struct clock_init_data qds8x50_clock_init_data;
 extern struct clock_init_data msm8625_dummy_clock_init_data;
+extern struct clock_init_data msm8930_clock_init_data;
 
 void msm_clock_init(struct clock_init_data *data);
 int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 56778e2..107598a 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -50,21 +50,13 @@
 
 static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
 
-static int override_cpu;
-
 static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
 {
 	int ret = 0;
 	struct cpufreq_freqs freqs;
 
 	freqs.old = policy->cur;
-	if (override_cpu) {
-		if (policy->cur == policy->max)
-			return 0;
-		else
-			freqs.new = policy->max;
-	} else
-		freqs.new = new_freq;
+	freqs.new = new_freq;
 	freqs.cpu = policy->cpu;
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 	ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
@@ -268,25 +260,6 @@
 	}
 }
 
-static ssize_t store_mfreq(struct sysdev_class *class,
-			struct sysdev_class_attribute *attr,
-			const char *buf, size_t count)
-{
-	u64 val;
-
-	if (strict_strtoull(buf, 0, &val) < 0) {
-		pr_err("Invalid parameter to mfreq\n");
-		return 0;
-	}
-	if (val)
-		override_cpu = 1;
-	else
-		override_cpu = 0;
-	return count;
-}
-
-static SYSDEV_CLASS_ATTR(mfreq, 0200, NULL, store_mfreq);
-
 static struct freq_attr *msm_freq_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
 	NULL,
@@ -310,11 +283,6 @@
 {
 	int cpu;
 
-	int err = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
-			&attr_mfreq.attr);
-	if (err)
-		pr_err("Failed to create sysfs mfreq\n");
-
 	for_each_possible_cpu(cpu) {
 		mutex_init(&(per_cpu(cpufreq_suspend, cpu).suspend_mutex));
 		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 6b79fab..7c2fca4 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -23,14 +23,19 @@
 #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 <mach/msm_dcvs.h>
+#include <mach/qdss.h>
 #include <linux/ion.h>
 #include "clock.h"
 #include "devices.h"
+#include "footswitch.h"
 #include "msm_watchdog.h"
 #include "rpm_stats.h"
 #include "rpm_log.h"
@@ -67,6 +72,15 @@
 #define MSM_HSUSB1_PHYS		0x12500000
 #define MSM_HSUSB1_SIZE		SZ_4K
 
+/* Address of HS USB3 */
+#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,
@@ -387,7 +401,7 @@
  * Machine specific data for AUX PCM Interface
  * which the driver will  be unware of.
  */
-struct msm_dai_auxpcm_pdata apq_auxpcm_rx_pdata = {
+struct msm_dai_auxpcm_pdata apq_auxpcm_pdata = {
 	.clk = "pcm_clk",
 	.mode = AFE_PCM_CFG_MODE_PCM,
 	.sync = AFE_PCM_CFG_SYNC_INT,
@@ -402,13 +416,16 @@
 	.name = "msm-dai-q6",
 	.id = 2,
 	.dev = {
-		.platform_data = &apq_auxpcm_rx_pdata,
+		.platform_data = &apq_auxpcm_pdata,
 	},
 };
 
 struct platform_device apq_cpudai_auxpcm_tx = {
 	.name = "msm-dai-q6",
 	.id = 3,
+	.dev = {
+		.platform_data = &apq_auxpcm_pdata,
+	},
 };
 
 struct platform_device apq_cpu_fe = {
@@ -471,6 +488,16 @@
 	.id = -1,
 };
 
+struct platform_device apq_cpudai_slimbus_1_rx = {
+	.name = "msm-dai-q6",
+	.id = 0x4002,
+};
+
+struct platform_device apq_cpudai_slimbus_1_tx = {
+	.name = "msm-dai-q6",
+	.id = 0x4003,
+};
+
 static struct resource resources_ssbi_pmic1[] = {
 	{
 		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
@@ -624,6 +651,12 @@
 		.name	= "peripheral_status_irq",
 		.flags	= IORESOURCE_IRQ,
 	},
+	{
+		.start	= MSM_GPIO_TO_INT(88),
+		.end	= MSM_GPIO_TO_INT(88),
+		.name	= "wakeup_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 static u64 dma_mask = DMA_BIT_MASK(32);
@@ -649,6 +682,54 @@
 	},
 };
 
+static struct resource resources_ehci_host3[] = {
+{
+		.start  = MSM_HSUSB3_PHYS,
+		.end    = MSM_HSUSB3_PHYS + MSM_HSUSB3_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB3_HS_IRQ,
+		.end    = USB3_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_ehci_host3 = {
+	.name           = "msm_ehci_host",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(resources_ehci_host3),
+	.resource       = resources_ehci_host3,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+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[] = {
@@ -1188,9 +1269,162 @@
 	.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_subsystem_restart_config smd_ssr_config = {
+	.disable_smsm_reset_handshake = 1,
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+	.smd_ssr_config = &smd_ssr_config,
+};
+
 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
@@ -1230,6 +1464,17 @@
 	.resource       = msm_gss_resources,
 };
 
+struct platform_device *apq8064_fs_devices[] = {
+	FS_8X60(FS_ROT,    "fs_rot"),
+	FS_8X60(FS_IJPEG,  "fs_ijpeg"),
+	FS_8X60(FS_VFE,    "fs_vfe"),
+	FS_8X60(FS_VPE,    "fs_vpe"),
+	FS_8X60(FS_GFX3D,  "fs_gfx3d"),
+	FS_8X60(FS_VED,    "fs_ved"),
+	FS_8X60(FS_VCAP,   "fs_vcap"),
+};
+unsigned apq8064_num_fs_devices = ARRAY_SIZE(apq8064_fs_devices);
+
 static struct clk_lookup msm_clocks_8064_dummy[] = {
 	CLK_DUMMY("pll2",		PLL2,		NULL, 0),
 	CLK_DUMMY("pll8",		PLL8,		NULL, 0),
@@ -1431,6 +1676,7 @@
 		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
 	},
 	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
 	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
 	.ipc_rpm_val = 4,
 	.target_id =  {
@@ -1712,6 +1958,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),
@@ -1852,3 +2145,108 @@
 	.resource	= mdm_resources,
 };
 
+static int apq8064_LPM_latency = 1000; /* >100 usec for WFI */
+
+struct platform_device apq8064_cpu_idle_device = {
+	.name   = "msm_cpu_idle",
+	.id     = -1,
+	.dev = {
+		.platform_data = &apq8064_LPM_latency,
+	},
+};
+
+static struct msm_dcvs_freq_entry apq8064_freq[] = {
+	{ 384000, 166981,  345600},
+	{ 702000, 213049,  632502},
+	{1026000, 285712,  925613},
+	{1242000, 383945, 1176550},
+	{1458000, 419729, 1465478},
+	{1512000, 434116, 1546674},
+
+};
+
+static struct msm_dcvs_core_info apq8064_core_info = {
+	.freq_tbl = &apq8064_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(apq8064_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 58000,
+		.scale_slack_time = 0,
+		.scale_slack_time_pct = 0,
+		.disable_pc_threshold = 1458000,
+		.em_window_size = 100000,
+		.em_max_util_pct = 97,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+struct platform_device apq8064_msm_gov_device = {
+	.name = "msm_dcvs_gov",
+	.id = -1,
+	.dev = {
+		.platform_data = &apq8064_core_info,
+	},
+};
+
+static struct resource msm_cache_erp_resources[] = {
+	{
+		.name = "l1_irq",
+		.start = SC_SICCPUXEXTFAULTIRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "l2_irq",
+		.start = APCC_QGICL2IRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+struct platform_device apq8064_device_cache_erp = {
+	.name		= "msm_cache_erp",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm_cache_erp_resources),
+	.resource	= msm_cache_erp_resources,
+};
+
+#define MSM_QDSS_PHYS_BASE		0x01A00000
+#define MSM_ETM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
+
+#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
+
+static struct qdss_source msm_qdss_sources[] = {
+	QDSS_SOURCE("msm_etm", 0x33),
+	QDSS_SOURCE("msm_oxili", 0x80),
+};
+
+static struct msm_qdss_platform_data qdss_pdata = {
+	.src_table = msm_qdss_sources,
+	.size = ARRAY_SIZE(msm_qdss_sources),
+	.afamily = 1,
+};
+
+struct platform_device apq8064_qdss_device = {
+	.name          = "msm_qdss",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &qdss_pdata,
+	},
+};
+
+static struct resource msm_etm_resources[] = {
+	{
+		.start = MSM_ETM_PHYS_BASE,
+		.end   = MSM_ETM_PHYS_BASE + (SZ_4K * 4) - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device apq8064_etm_device = {
+	.name          = "msm_etm",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_etm_resources),
+	.resource      = msm_etm_resources,
+};
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index c75a4e3..da3574b 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -13,9 +13,15 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/ion.h>
 #include <mach/msm_iomap.h>
 #include <mach/irqs-8930.h>
 #include <mach/rpm.h>
+#include <mach/msm_dcvs.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/socinfo.h>
 
 #include "devices.h"
 #include "rpm_log.h"
@@ -33,6 +39,7 @@
 		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
 	},
 	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
 	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
 	.ipc_rpm_val = 4,
 	.target_id = {
@@ -58,7 +65,7 @@
 				APPS_FABRIC_CFG_CLKMOD, 3),
 		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_IOCTL,
 				APPS_FABRIC_CFG_IOCTL, 1),
-		MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 12),
+		MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 6),
 		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_HALT_0,
 				SYS_FABRIC_CFG_HALT, 2),
 		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_CLKMOD_0,
@@ -66,14 +73,14 @@
 		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_IOCTL,
 				SYS_FABRIC_CFG_IOCTL, 1),
 		MSM_RPM_MAP(8930, SYSTEM_FABRIC_ARB_0,
-				SYSTEM_FABRIC_ARB, 29),
+				SYSTEM_FABRIC_ARB, 20),
 		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_HALT_0,
 				MMSS_FABRIC_CFG_HALT, 2),
 		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_CLKMOD_0,
 				MMSS_FABRIC_CFG_CLKMOD, 3),
 		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_IOCTL,
 				MMSS_FABRIC_CFG_IOCTL, 1),
-		MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 23),
+		MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 11),
 		MSM_RPM_MAP(8930, PM8038_S1_0, PM8038_S1, 2),
 		MSM_RPM_MAP(8930, PM8038_S2_0, PM8038_S2, 2),
 		MSM_RPM_MAP(8930, PM8038_S3_0, PM8038_S3, 2),
@@ -116,6 +123,7 @@
 		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
 		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
 		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
+		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
 	},
 	.target_status = {
 		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
@@ -219,6 +227,7 @@
 		MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
 		MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
 		MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
 	},
 	.target_ctrl_id = {
 		MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
@@ -272,3 +281,349 @@
 	},
 };
 
+static int msm8930_LPM_latency = 1000; /* >100 usec for WFI */
+
+struct platform_device msm8930_cpu_idle_device = {
+	.name   = "msm_cpu_idle",
+	.id     = -1,
+	.dev = {
+		.platform_data = &msm8930_LPM_latency,
+	},
+};
+
+static struct msm_dcvs_freq_entry msm8930_freq[] = {
+	{ 384000, 166981,  345600},
+	{ 702000, 213049,  632502},
+	{1026000, 285712,  925613},
+	{1242000, 383945, 1176550},
+	{1458000, 419729, 1465478},
+	{1512000, 434116, 1546674},
+
+};
+
+static struct msm_dcvs_core_info msm8930_core_info = {
+	.freq_tbl = &msm8930_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(msm8930_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 58000,
+		.scale_slack_time = 0,
+		.scale_slack_time_pct = 0,
+		.disable_pc_threshold = 1458000,
+		.em_window_size = 100000,
+		.em_max_util_pct = 97,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+struct platform_device msm8930_msm_gov_device = {
+	.name = "msm_dcvs_gov",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm8930_core_info,
+	},
+};
+
+struct platform_device msm_bus_8930_sys_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_SYSTEM,
+};
+struct platform_device msm_bus_8930_apps_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_APPSS,
+};
+struct platform_device msm_bus_8930_mm_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_MMSS,
+};
+struct platform_device msm_bus_8930_sys_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_SYSTEM_FPB,
+};
+struct platform_device msm_bus_8930_cpss_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_CPSS_FPB,
+};
+
+/* MSM Video core device */
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors vidc_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+static struct msm_bus_vectors vidc_venc_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 54525952,
+		.ib  = 436207616,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 72351744,
+		.ib  = 289406976,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 40894464,
+		.ib  = 327155712,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 48234496,
+		.ib  = 192937984,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 163577856,
+		.ib  = 1308622848,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 219152384,
+		.ib  = 876609536,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 121634816,
+		.ib  = 973078528,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 155189248,
+		.ib  = 620756992,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 372244480,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 501219328,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 222298112,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 330301440,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+
+static struct msm_bus_paths vidc_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vidc_init_vectors),
+		vidc_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_vga_vectors),
+		vidc_venc_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_vga_vectors),
+		vidc_vdec_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_720p_vectors),
+		vidc_venc_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_720p_vectors),
+		vidc_vdec_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_1080p_vectors),
+		vidc_venc_1080p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_1080p_vectors),
+		vidc_vdec_1080p_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vidc_bus_client_data = {
+	vidc_bus_client_config,
+	ARRAY_SIZE(vidc_bus_client_config),
+	.name = "vidc",
+};
+#endif
+
+#define MSM_VIDC_BASE_PHYS 0x04400000
+#define MSM_VIDC_BASE_SIZE 0x00100000
+
+static struct resource apq8930_device_vidc_resources[] = {
+	{
+		.start	= MSM_VIDC_BASE_PHYS,
+		.end	= MSM_VIDC_BASE_PHYS + MSM_VIDC_BASE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VCODEC_IRQ,
+		.end	= VCODEC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_vidc_platform_data apq8930_vidc_platform_data = {
+#ifdef CONFIG_MSM_BUS_SCALING
+	.vidc_bus_client_pdata = &vidc_bus_client_data,
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.memtype = ION_CP_MM_HEAP_ID,
+	.enable_ion = 1,
+#else
+	.memtype = MEMTYPE_EBI1,
+	.enable_ion = 0,
+#endif
+	.disable_dmx = 0,
+	.disable_fullhd = 0,
+};
+
+struct platform_device apq8930_msm_device_vidc = {
+	.name = "msm_vidc",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(apq8930_device_vidc_resources),
+	.resource = apq8930_device_vidc_resources,
+	.dev = {
+		.platform_data = &apq8930_vidc_platform_data,
+	},
+};
+
+struct platform_device *vidc_device[] __initdata = {
+	&apq8930_msm_device_vidc
+};
+
+void __init msm8930_add_vidc_device(void)
+{
+	if (cpu_is_msm8627()) {
+		struct msm_vidc_platform_data *pdata;
+		pdata = (struct msm_vidc_platform_data *)
+			apq8930_msm_device_vidc.dev.platform_data;
+		pdata->disable_fullhd = 1;
+	}
+	platform_add_devices(vidc_device, ARRAY_SIZE(vidc_device));
+}
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 4d4b88f..029fc6f3 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -30,8 +30,12 @@
 #include <mach/rpm.h>
 #include <mach/msm_bus_board.h>
 #include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
+#include <mach/msm_dcvs.h>
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
+#include <mach/msm_tsif.h>
+#include <mach/qdss.h>
 #include "clock.h"
 #include "devices.h"
 #include "devices-msm8x60.h"
@@ -41,6 +45,7 @@
 #include "rpm_stats.h"
 #include "pil-q6v4.h"
 #include "scm-pas.h"
+#include <mach/msm_dcvs.h>
 
 #ifdef CONFIG_MSM_MPM
 #include "mpm.h"
@@ -950,9 +955,168 @@
 	.id = -1,
 };
 
+struct platform_device msm_pil_dsps = {
+	.name          = "pil_dsps",
+	.id            = -1,
+	.dev.platform_data = "dsps",
+};
+
+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_subsystem_restart_config smd_ssr_config = {
+	.disable_smsm_reset_handshake = 1,
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+	.smd_ssr_config = &smd_ssr_config,
+};
+
 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 = {
@@ -1077,6 +1241,34 @@
 	.resource	= resources_qup_i2c_gsbi3,
 };
 
+static struct resource resources_qup_i2c_gsbi9[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI9_PHYS,
+		.end	= MSM_GSBI9_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI9_QUP_PHYS,
+		.end	= MSM_GSBI9_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI9_QUP_IRQ,
+		.end	= GSBI9_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_qup_i2c_gsbi9 = {
+	.name		= "qup_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi9),
+	.resource	= resources_qup_i2c_gsbi9,
+};
+
 static struct resource resources_qup_i2c_gsbi10[] = {
 	{
 		.name	= "gsbi_qup_i2c_addr",
@@ -1355,6 +1547,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,
@@ -1497,7 +1794,7 @@
  * Machine specific data for AUX PCM Interface
  * which the driver will  be unware of.
  */
-struct msm_dai_auxpcm_pdata auxpcm_rx_pdata = {
+struct msm_dai_auxpcm_pdata auxpcm_pdata = {
 	.clk = "pcm_clk",
 	.mode = AFE_PCM_CFG_MODE_PCM,
 	.sync = AFE_PCM_CFG_SYNC_INT,
@@ -1512,13 +1809,16 @@
 	.name = "msm-dai-q6",
 	.id = 2,
 	.dev = {
-		.platform_data = &auxpcm_rx_pdata,
+		.platform_data = &auxpcm_pdata,
 	},
 };
 
 struct platform_device msm_cpudai_auxpcm_tx = {
 	.name = "msm-dai-q6",
 	.id = 3,
+	.dev = {
+		.platform_data = &auxpcm_pdata,
+	},
 };
 
 struct platform_device msm_cpu_fe = {
@@ -1594,7 +1894,88 @@
 };
 unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
 
+
 #ifdef CONFIG_MSM_ROTATOR
+static struct msm_bus_vectors rotator_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors rotator_ui_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1024 * 600 * 4 * 2 * 60),
+		.ib  = (1024 * 600 * 4 * 2 * 60 * 1.5),
+	},
+};
+
+static struct msm_bus_vectors rotator_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (640 * 480 * 2 * 2 * 30),
+		.ib  = (640 * 480 * 2 * 2 * 30 * 1.5),
+	},
+};
+static struct msm_bus_vectors rotator_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1280 * 736 * 2 * 2 * 30),
+		.ib  = (1280 * 736 * 2 * 2 * 30 * 1.5),
+	},
+};
+
+static struct msm_bus_vectors rotator_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1920 * 1088 * 2 * 2 * 30),
+		.ib  = (1920 * 1088 * 2 * 2 * 30 * 1.5),
+	},
+};
+
+static struct msm_bus_paths rotator_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(rotator_init_vectors),
+		rotator_init_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_ui_vectors),
+		rotator_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_vga_vectors),
+		rotator_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_720p_vectors),
+		rotator_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_1080p_vectors),
+		rotator_1080p_vectors,
+	},
+};
+
+struct msm_bus_scale_pdata rotator_bus_scale_pdata = {
+	rotator_bus_scale_usecases,
+	ARRAY_SIZE(rotator_bus_scale_usecases),
+	.name = "rotator",
+};
+
+void __init msm_rotator_update_bus_vectors(unsigned int xres,
+	unsigned int yres)
+{
+	rotator_ui_vectors[0].ab = xres * yres * 4 * 2 * 60;
+	rotator_ui_vectors[0].ib = xres * yres * 4 * 2 * 60 * 3 / 2;
+}
+
 #define ROTATOR_HW_BASE         0x04E00000
 static struct resource resources_msm_rotator[] = {
 	{
@@ -1905,7 +2286,7 @@
 	CLK_DUMMY("core_clk",	GSBI6_QUP_CLK,		NULL, OFF),
 	CLK_DUMMY("core_clk",	GSBI7_QUP_CLK,		NULL, OFF),
 	CLK_DUMMY("core_clk",	GSBI8_QUP_CLK,		NULL, OFF),
-	CLK_DUMMY("core_clk",	GSBI9_QUP_CLK,		NULL, OFF),
+	CLK_DUMMY("core_clk",	GSBI9_QUP_CLK,		"qup_i2c.0", OFF),
 	CLK_DUMMY("core_clk",	GSBI10_QUP_CLK,		NULL, OFF),
 	CLK_DUMMY("core_clk",	GSBI11_QUP_CLK,		NULL, OFF),
 	CLK_DUMMY("core_clk",	GSBI12_QUP_CLK,		NULL, OFF),
@@ -1938,7 +2319,7 @@
 	CLK_DUMMY("iface_clk",		GSBI6_P_CLK,		NULL, OFF),
 	CLK_DUMMY("iface_clk",		GSBI7_P_CLK,		NULL, OFF),
 	CLK_DUMMY("iface_clk",		GSBI8_P_CLK,		NULL, OFF),
-	CLK_DUMMY("iface_clk",		GSBI9_P_CLK,		NULL, OFF),
+	CLK_DUMMY("iface_clk",		GSBI9_P_CLK,	 "qup_i2c.0", OFF),
 	CLK_DUMMY("iface_clk",		GSBI10_P_CLK,		NULL, OFF),
 	CLK_DUMMY("iface_clk",		GSBI11_P_CLK,		NULL, OFF),
 	CLK_DUMMY("iface_clk",		GSBI12_P_CLK,		NULL, OFF),
@@ -2104,6 +2485,49 @@
 	},
 };
 
+static struct msm_dcvs_freq_entry grp3d_freq[] = {
+	{0, 0, 333932},
+	{0, 0, 497532},
+	{0, 0, 707610},
+	{0, 0, 844545},
+};
+
+static struct msm_dcvs_freq_entry grp2d_freq[] = {
+	{0, 0, 86000},
+	{0, 0, 200000},
+};
+
+static struct msm_dcvs_core_info grp3d_core_info = {
+	.freq_tbl = &grp3d_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(grp3d_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 39000,
+		.disable_pc_threshold = 86000,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.em_max_util_pct = 97,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+static struct msm_dcvs_core_info grp2d_core_info = {
+	.freq_tbl = &grp2d_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(grp2d_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 39000,
+		.disable_pc_threshold = 90000,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 90,
+		.em_max_util_pct = 95,
+	},
+};
+
 #ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors grp3d_init_vectors[] = {
 	{
@@ -2291,6 +2715,20 @@
 	},
 };
 
+static const char *kgsl_3d0_iommu_ctx_names[] = {
+	"gfx3d_user",
+	/* priv_ctx goes here */
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_3d0_iommu_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu_ctx_names),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+};
+
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
@@ -2319,7 +2757,7 @@
 		},
 	},
 	.init_level = 0,
-	.num_levels = 5,
+	.num_levels = ARRAY_SIZE(grp3d_freq) + 1,
 	.set_grp_async = NULL,
 	.idle_timeout = HZ/20,
 	.nap_allowed = true,
@@ -2327,8 +2765,9 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp3d_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx3d_user",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+	.core_info = &grp3d_core_info,
 };
 
 struct platform_device msm_kgsl_3d0 = {
@@ -2356,6 +2795,19 @@
 	},
 };
 
+static const char *kgsl_2d0_iommu_ctx_names[] = {
+	"gfx2d0_2d0",
+};
+
+static struct kgsl_device_iommu_data kgsl_2d0_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_2d0_iommu_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d0_iommu_ctx_names),
+		.physstart = 0x07D00000,
+		.physend = 0x07D00000 + SZ_1M - 1,
+	},
+};
+
 static struct kgsl_device_platform_data kgsl_2d0_pdata = {
 	.pwrlevel = {
 		{
@@ -2372,7 +2824,7 @@
 		},
 	},
 	.init_level = 0,
-	.num_levels = 3,
+	.num_levels = ARRAY_SIZE(grp2d_freq) + 1,
 	.set_grp_async = NULL,
 	.idle_timeout = HZ/5,
 	.nap_allowed = true,
@@ -2380,8 +2832,9 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp2d0_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx2d0_2d0",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_2d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_2d0_iommu_data),
+	.core_info = &grp2d_core_info,
 };
 
 struct platform_device msm_kgsl_2d0 = {
@@ -2394,6 +2847,19 @@
 	},
 };
 
+static const char *kgsl_2d1_iommu_ctx_names[] = {
+	"gfx2d1_2d1",
+};
+
+static struct kgsl_device_iommu_data kgsl_2d1_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_2d1_iommu_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d1_iommu_ctx_names),
+		.physstart = 0x07E00000,
+		.physend = 0x07E00000 + SZ_1M - 1,
+	},
+};
+
 static struct resource kgsl_2d1_resources[] = {
 	{
 		.name = KGSL_2D1_REG_MEMORY,
@@ -2425,7 +2891,7 @@
 		},
 	},
 	.init_level = 0,
-	.num_levels = 3,
+	.num_levels = ARRAY_SIZE(grp2d_freq) + 1,
 	.set_grp_async = NULL,
 	.idle_timeout = HZ/5,
 	.nap_allowed = true,
@@ -2433,8 +2899,9 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp2d1_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx2d1_2d1",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_2d1_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_2d1_iommu_data),
+	.core_info = &grp2d_core_info,
 };
 
 struct platform_device msm_kgsl_2d1 = {
@@ -2476,6 +2943,7 @@
 		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
 	},
 	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
 	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
 	.ipc_rpm_val = 4,
 	.target_id = {
@@ -2826,7 +3294,27 @@
 #define MSM_ETB_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1000)
 #define MSM_TPIU_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x3000)
 #define MSM_FUNNEL_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x4000)
-#define MSM_PTM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
+#define MSM_ETM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
+
+#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
+
+static struct qdss_source msm_qdss_sources[] = {
+	QDSS_SOURCE("msm_etm", 0x3),
+};
+
+static struct msm_qdss_platform_data qdss_pdata = {
+	.src_table = msm_qdss_sources,
+	.size = ARRAY_SIZE(msm_qdss_sources),
+	.afamily = 1,
+};
+
+struct platform_device msm_qdss_device = {
+	.name          = "msm_qdss",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &qdss_pdata,
+	},
+};
 
 static struct resource msm_etb_resources[] = {
 	{
@@ -2873,19 +3361,86 @@
 	.resource      = msm_funnel_resources,
 };
 
-static struct resource msm_ptm_resources[] = {
+static struct resource msm_etm_resources[] = {
 	{
-		.start = MSM_PTM_PHYS_BASE,
-		.end   = MSM_PTM_PHYS_BASE + (SZ_4K * 2) - 1,
+		.start = MSM_ETM_PHYS_BASE,
+		.end   = MSM_ETM_PHYS_BASE + (SZ_4K * 2) - 1,
 		.flags = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_ptm_device = {
-	.name          = "msm_ptm",
+struct platform_device msm_etm_device = {
+	.name          = "msm_etm",
 	.id            = 0,
-	.num_resources = ARRAY_SIZE(msm_ptm_resources),
-	.resource      = msm_ptm_resources,
+	.num_resources = ARRAY_SIZE(msm_etm_resources),
+	.resource      = msm_etm_resources,
 };
 
 #endif
+
+static int msm8960_LPM_latency = 1000; /* >100 usec for WFI */
+
+struct platform_device msm8960_cpu_idle_device = {
+	.name   = "msm_cpu_idle",
+	.id     = -1,
+	.dev = {
+		.platform_data = &msm8960_LPM_latency,
+	},
+};
+
+static struct msm_dcvs_freq_entry msm8960_freq[] = {
+	{ 384000, 166981,  345600},
+	{ 702000, 213049,  632502},
+	{1026000, 285712,  925613},
+	{1242000, 383945, 1176550},
+	{1458000, 419729, 1465478},
+	{1512000, 434116, 1546674},
+
+};
+
+static struct msm_dcvs_core_info msm8960_core_info = {
+	.freq_tbl = &msm8960_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(msm8960_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 58000,
+		.scale_slack_time = 0,
+		.scale_slack_time_pct = 0,
+		.disable_pc_threshold = 1458000,
+		.em_window_size = 100000,
+		.em_max_util_pct = 97,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+struct platform_device msm8960_msm_gov_device = {
+	.name = "msm_dcvs_gov",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm8960_core_info,
+	},
+};
+
+static struct resource msm_cache_erp_resources[] = {
+	{
+		.name = "l1_irq",
+		.start = SC_SICCPUXEXTFAULTIRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "l2_irq",
+		.start = APCC_QGICL2IRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+struct platform_device msm8960_device_cache_erp = {
+	.name		= "msm_cache_erp",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm_cache_erp_resources),
+	.resource	= msm_cache_erp_resources,
+};
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 18acb36..f7306d2 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -15,9 +15,10 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/msm_tsens.h>
 #include <linux/platform_data/qcom_crypto_device.h>
 #include <linux/dma-mapping.h>
+#include <sound/msm-dai-q6.h>
+#include <sound/apr_audio.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/flash.h>
 #include <mach/board.h>
@@ -63,7 +64,8 @@
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
 	.bark_time = 11000,
-	.has_secure = true,
+	.has_secure = false,
+	.use_kernel_fiq = true,
 };
 
 struct platform_device msm9615_device_watchdog = {
@@ -388,6 +390,127 @@
 	},
 };
 
+struct platform_device msm_pcm = {
+	.name	= "msm-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_multi_ch_pcm = {
+	.name	= "msm-multi-ch-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_pcm_routing = {
+	.name	= "msm-pcm-routing",
+	.id	= -1,
+};
+
+struct platform_device msm_cpudai0 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4000,
+};
+
+struct platform_device msm_cpudai1 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4001,
+};
+
+struct platform_device msm_cpudai_bt_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3000,
+};
+
+struct platform_device msm_cpudai_bt_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3001,
+};
+
+/*
+ * Machine specific data for AUX PCM Interface
+ * which the driver will  be unware of.
+ */
+struct msm_dai_auxpcm_pdata auxpcm_pdata = {
+	.clk = "pcm_clk",
+	.mode = AFE_PCM_CFG_MODE_PCM,
+	.sync = AFE_PCM_CFG_SYNC_INT,
+	.frame = AFE_PCM_CFG_FRM_256BPF,
+	.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+	.slot = 0,
+	.data = AFE_PCM_CFG_CDATAOE_MASTER,
+	.pcm_clk_rate = 2048000,
+};
+
+struct platform_device msm_cpudai_auxpcm_rx = {
+	.name = "msm-dai-q6",
+	.id = 2,
+	.dev = {
+		.platform_data = &auxpcm_pdata,
+	},
+};
+
+struct platform_device msm_cpudai_auxpcm_tx = {
+	.name = "msm-dai-q6",
+	.id = 3,
+	.dev = {
+		.platform_data = &auxpcm_pdata,
+	},
+};
+
+struct platform_device msm_cpu_fe = {
+	.name	= "msm-dai-fe",
+	.id	= -1,
+};
+
+struct platform_device msm_stub_codec = {
+	.name	= "msm-stub-codec",
+	.id	= 1,
+};
+
+struct platform_device msm_voice = {
+	.name	= "msm-pcm-voice",
+	.id	= -1,
+};
+
+struct platform_device msm_voip = {
+	.name	= "msm-voip-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_compr_dsp = {
+	.name	= "msm-compr-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_pcm_hostless = {
+	.name	= "msm-pcm-hostless",
+	.id	= -1,
+};
+
+struct platform_device msm_cpudai_afe_01_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xE0,
+};
+
+struct platform_device msm_cpudai_afe_01_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xF0,
+};
+
+struct platform_device msm_cpudai_afe_02_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xF1,
+};
+
+struct platform_device msm_cpudai_afe_02_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xE1,
+};
+
+struct platform_device msm_pcm_afe = {
+	.name	= "msm-pcm-afe",
+	.id	= -1,
+};
+
 static struct resource resources_ssbi_pmic1[] = {
 	{
 		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
@@ -442,21 +565,6 @@
 	.dev.platform_data = &msm_sps_pdata,
 };
 
-static struct tsens_platform_data msm_tsens_pdata = {
-	.slope			= {872, 872, 872, 872, 872},
-	.tsens_factor		= 1000,
-	.hw_type		= MSM_9615,
-	.tsens_num_sensor	= 5,
-};
-
-struct platform_device msm9615_device_tsens = {
-	.name		= "tsens8960-tm",
-	.id		= -1,
-	.dev 		= {
-		.platform_data = &msm_tsens_pdata,
-	},
-};
-
 #define MSM_NAND_PHYS		0x1B400000
 static struct resource resources_nand[] = {
 	[0] = {
@@ -742,6 +850,30 @@
 	return platform_device_register(pdev);
 }
 
+#ifdef CONFIG_FB_MSM_EBI2
+static struct resource msm_ebi2_lcdc_resources[] = {
+	{
+		.name   = "base",
+		.start  = 0x1B300000,
+		.end    = 0x1B300000 + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd01",
+		.start  = 0x1FC00000,
+		.end    = 0x1FC00000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_ebi2_lcdc_device = {
+	.name   = "ebi2_lcd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_ebi2_lcdc_resources),
+	.resource       = msm_ebi2_lcdc_resources,
+};
+#endif
+
 #ifdef CONFIG_CACHE_L2X0
 static int __init l2x0_cache_init(void)
 {
@@ -772,6 +904,7 @@
 		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
 	},
 	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
 	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
 	.ipc_rpm_val = 4,
 	.target_id = {
@@ -921,6 +1054,7 @@
 	[16] = MSM_GPIO_TO_INT(15),
 	[19] = MSM_GPIO_TO_INT(26),
 	[20] = MSM_GPIO_TO_INT(28),
+	[22] = USB_HSIC_IRQ,
 	[23] = MSM_GPIO_TO_INT(19),
 	[24] = MSM_GPIO_TO_INT(23),
 	[26] = MSM_GPIO_TO_INT(3),
@@ -1112,6 +1246,18 @@
 	},
 };
 
+uint32_t __init msm9615_rpm_get_swfi_latency(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_levels); i++) {
+		if (msm_rpmrs_levels[i].sleep_mode ==
+			MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)
+				return msm_rpmrs_levels[i].latency_us;
+	}
+	return 0;
+}
+
 void __init msm9615_device_init(void)
 {
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
@@ -1151,3 +1297,26 @@
 	.name  = "msm_bus_fabric",
 	.id    =  MSM_BUS_FAB_DEFAULT,
 };
+
+#ifdef CONFIG_FB_MSM_EBI2
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+void __init msm_fb_register_device(char *name, void *data)
+{
+	if (!strncmp(name, "ebi2", 4))
+		msm_register_device(&msm_ebi2_lcdc_device, data);
+	else
+		pr_err("%s: unknown device! %s\n", __func__, name);
+}
+#endif
diff --git a/arch/arm/mach-msm/devices-fsm9xxx.c b/arch/arm/mach-msm/devices-fsm9xxx.c
index d46e4d6..777b6d6 100644
--- a/arch/arm/mach-msm/devices-fsm9xxx.c
+++ b/arch/arm/mach-msm/devices-fsm9xxx.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
@@ -22,6 +22,7 @@
 #include "devices.h"
 #include "smd_private.h"
 #include "clock-local.h"
+#include "msm_watchdog.h"
 
 #include <asm/mach/flash.h>
 #include <asm/mach/mmc.h>
@@ -389,3 +390,22 @@
 	.id     = -1,
 };
 
+/*
+ * Watchdog
+ */
+
+static struct msm_watchdog_pdata fsm_watchdog_pdata = {
+	.pet_time = 10000,
+	.bark_time = 11000,
+	.has_secure = false,
+	.has_vic = true,
+};
+
+struct platform_device fsm9xxx_device_watchdog = {
+	.name = "msm_watchdog",
+	.id = -1,
+	.dev = {
+		.platform_data = &fsm_watchdog_pdata,
+	},
+};
+
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 3d2d2e7..29e8180 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.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
@@ -364,11 +364,13 @@
 static struct msm_iommu_dev gfx3d_iommu = {
 	.name = "gfx3d",
 	.ncb = 3,
+	.ttbr_split = 2,
 };
 
 static struct msm_iommu_dev gfx3d1_iommu = {
 	.name = "gfx3d1",
 	.ncb = 3,
+	.ttbr_split = 2,
 };
 
 static struct msm_iommu_dev gfx2d0_iommu = {
@@ -391,6 +393,7 @@
 	.id = 0,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &jpegd_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_jpegd_resources),
 	.resource = msm_iommu_jpegd_resources,
@@ -401,6 +404,7 @@
 	.id = 1,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vpe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vpe_resources),
 	.resource = msm_iommu_vpe_resources,
@@ -411,6 +415,7 @@
 	.id = 2,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &mdp0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp0_resources),
 	.resource = msm_iommu_mdp0_resources,
@@ -421,6 +426,7 @@
 	.id = 3,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &mdp1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp1_resources),
 	.resource = msm_iommu_mdp1_resources,
@@ -431,6 +437,7 @@
 	.id = 4,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &rot_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_rot_resources),
 	.resource = msm_iommu_rot_resources,
@@ -441,6 +448,7 @@
 	.id = 5,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &ijpeg_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_ijpeg_resources),
 	.resource = msm_iommu_ijpeg_resources,
@@ -451,6 +459,7 @@
 	.id = 6,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vfe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vfe_resources),
 	.resource = msm_iommu_vfe_resources,
@@ -461,6 +470,7 @@
 	.id = 7,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcodec_a_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_a_resources),
 	.resource = msm_iommu_vcodec_a_resources,
@@ -471,6 +481,7 @@
 	.id = 8,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcodec_b_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_b_resources),
 	.resource = msm_iommu_vcodec_b_resources,
@@ -481,6 +492,7 @@
 	.id = 9,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx3d_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d_resources),
 	.resource = msm_iommu_gfx3d_resources,
@@ -491,6 +503,7 @@
 	.id = 10,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx3d1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d1_resources),
 	.resource = msm_iommu_gfx3d1_resources,
@@ -501,6 +514,7 @@
 	.id = 10,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx2d0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d0_resources),
 	.resource = msm_iommu_gfx2d0_resources,
@@ -511,6 +525,7 @@
 	.id = 11,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx2d1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d1_resources),
 	.resource = msm_iommu_gfx2d1_resources,
@@ -521,6 +536,7 @@
 	.id = 11,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcap_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcap_resources),
 	.resource = msm_iommu_vcap_resources,
@@ -683,6 +699,7 @@
 	.id = 0,
 	.dev = {
 		.parent = &msm_device_iommu_jpegd.dev,
+		.platform_data = &jpegd_src_ctx,
 	},
 };
 
@@ -691,6 +708,7 @@
 	.id = 1,
 	.dev = {
 		.parent = &msm_device_iommu_jpegd.dev,
+		.platform_data = &jpegd_dst_ctx,
 	},
 };
 
@@ -699,6 +717,7 @@
 	.id = 2,
 	.dev = {
 		.parent = &msm_device_iommu_vpe.dev,
+		.platform_data = &vpe_src_ctx,
 	},
 };
 
@@ -707,6 +726,7 @@
 	.id = 3,
 	.dev = {
 		.parent = &msm_device_iommu_vpe.dev,
+		.platform_data = &vpe_dst_ctx,
 	},
 };
 
@@ -715,6 +735,7 @@
 	.id = 4,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
+		.platform_data = &mdp_vg1_ctx,
 	},
 };
 
@@ -723,6 +744,7 @@
 	.id = 5,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
+		.platform_data = &mdp_rgb1_ctx,
 	},
 };
 
@@ -731,6 +753,7 @@
 	.id = 6,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
+		.platform_data = &mdp_vg2_ctx,
 	},
 };
 
@@ -739,6 +762,7 @@
 	.id = 7,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
+		.platform_data = &mdp_rgb2_ctx,
 	},
 };
 
@@ -747,6 +771,7 @@
 	.id = 8,
 	.dev = {
 		.parent = &msm_device_iommu_rot.dev,
+		.platform_data = &rot_src_ctx,
 	},
 };
 
@@ -755,6 +780,7 @@
 	.id = 9,
 	.dev = {
 		.parent = &msm_device_iommu_rot.dev,
+		.platform_data = &rot_dst_ctx,
 	},
 };
 
@@ -763,6 +789,7 @@
 	.id = 10,
 	.dev = {
 		.parent = &msm_device_iommu_ijpeg.dev,
+		.platform_data = &ijpeg_src_ctx,
 	},
 };
 
@@ -771,6 +798,7 @@
 	.id = 11,
 	.dev = {
 		.parent = &msm_device_iommu_ijpeg.dev,
+		.platform_data = &ijpeg_dst_ctx,
 	},
 };
 
@@ -779,6 +807,7 @@
 	.id = 12,
 	.dev = {
 		.parent = &msm_device_iommu_vfe.dev,
+		.platform_data = &vfe_imgwr_ctx,
 	},
 };
 
@@ -787,6 +816,7 @@
 	.id = 13,
 	.dev = {
 		.parent = &msm_device_iommu_vfe.dev,
+		.platform_data = &vfe_misc_ctx,
 	},
 };
 
@@ -795,6 +825,7 @@
 	.id = 14,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_a.dev,
+		.platform_data = &vcodec_a_stream_ctx,
 	},
 };
 
@@ -803,6 +834,7 @@
 	.id = 15,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_a.dev,
+		.platform_data = &vcodec_a_mm1_ctx,
 	},
 };
 
@@ -811,6 +843,7 @@
 	.id = 16,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_b.dev,
+		.platform_data = &vcodec_b_mm2_ctx,
 	},
 };
 
@@ -819,6 +852,7 @@
 	.id = 17,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d.dev,
+		.platform_data = &gfx3d_user_ctx,
 	},
 };
 
@@ -827,6 +861,7 @@
 	.id = 18,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d.dev,
+		.platform_data = &gfx3d_priv_ctx,
 	},
 };
 
@@ -835,6 +870,7 @@
 	.id = 19,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d1.dev,
+		.platform_data = &gfx3d1_user_ctx,
 	},
 };
 
@@ -843,6 +879,7 @@
 	.id = 20,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d1.dev,
+		.platform_data = &gfx3d1_priv_ctx,
 	},
 };
 
@@ -851,6 +888,7 @@
 	.id = 19,
 	.dev = {
 		.parent = &msm_device_iommu_gfx2d0.dev,
+		.platform_data = &gfx2d0_2d0_ctx,
 	},
 };
 
@@ -859,6 +897,7 @@
 	.id = 20,
 	.dev = {
 		.parent = &msm_device_iommu_gfx2d1.dev,
+		.platform_data = &gfx2d1_2d1_ctx,
 	},
 };
 
@@ -867,6 +906,7 @@
 	.id = 21,
 	.dev = {
 		.parent = &msm_device_iommu_vcap.dev,
+		.platform_data = &vcap_vc_ctx,
 	},
 };
 
@@ -875,11 +915,11 @@
 	.id = 22,
 	.dev = {
 		.parent = &msm_device_iommu_vcap.dev,
+		.platform_data = &vcap_vp_ctx,
 	},
 };
 
 static struct platform_device *msm_iommu_common_devs[] = {
-	&msm_device_iommu_jpegd,
 	&msm_device_iommu_vpe,
 	&msm_device_iommu_mdp0,
 	&msm_device_iommu_mdp1,
@@ -901,32 +941,11 @@
 	&msm_device_iommu_vcap,
 };
 
-static struct msm_iommu_dev *msm_iommu_common_data[] = {
-	&jpegd_iommu,
-	&vpe_iommu,
-	&mdp0_iommu,
-	&mdp1_iommu,
-	&rot_iommu,
-	&ijpeg_iommu,
-	&vfe_iommu,
-	&vcodec_a_iommu,
-	&vcodec_b_iommu,
-	&gfx3d_iommu,
-};
-
-static struct msm_iommu_dev *msm_iommu_gfx2d_data[] = {
-	&gfx2d0_iommu,
-	&gfx2d1_iommu,
-};
-
-static struct msm_iommu_dev *msm_iommu_8064_data[] = {
-	&gfx3d1_iommu,
-	&vcap_iommu,
+static struct platform_device *msm_iommu_jpegd_devs[] = {
+	&msm_device_iommu_jpegd,
 };
 
 static struct platform_device *msm_iommu_common_ctx_devs[] = {
-	&msm_device_jpegd_src_ctx,
-	&msm_device_jpegd_dst_ctx,
 	&msm_device_vpe_src_ctx,
 	&msm_device_vpe_dst_ctx,
 	&msm_device_mdp_vg1_ctx,
@@ -958,102 +977,11 @@
 	&msm_device_vcap_vp_ctx,
 };
 
-static struct msm_iommu_ctx_dev *msm_iommu_common_ctx_data[] = {
-	&jpegd_src_ctx,
-	&jpegd_dst_ctx,
-	&vpe_src_ctx,
-	&vpe_dst_ctx,
-	&mdp_vg1_ctx,
-	&mdp_rgb1_ctx,
-	&mdp_vg2_ctx,
-	&mdp_rgb2_ctx,
-	&rot_src_ctx,
-	&rot_dst_ctx,
-	&ijpeg_src_ctx,
-	&ijpeg_dst_ctx,
-	&vfe_imgwr_ctx,
-	&vfe_misc_ctx,
-	&vcodec_a_stream_ctx,
-	&vcodec_a_mm1_ctx,
-	&vcodec_b_mm2_ctx,
-	&gfx3d_user_ctx,
-	&gfx3d_priv_ctx,
+static struct platform_device *msm_iommu_jpegd_ctx_devs[] = {
+	&msm_device_jpegd_src_ctx,
+	&msm_device_jpegd_dst_ctx,
 };
 
-static struct msm_iommu_ctx_dev *msm_iommu_gfx2d_ctx_data[] = {
-	&gfx2d0_2d0_ctx,
-	&gfx2d1_2d1_ctx,
-};
-
-static struct msm_iommu_ctx_dev *msm_iommu_8064_ctx_data[] = {
-	&gfx3d1_user_ctx,
-	&gfx3d1_priv_ctx,
-	&vcap_vc_ctx,
-	&vcap_vp_ctx,
-};
-
-static int iommu_init_devs(struct platform_device *devs[],
-	struct msm_iommu_dev *data[], int size)
-{
-	int ret, i;
-
-	for (i = 0; i < size; i++) {
-		ret = platform_device_add_data(devs[i],
-			  data[i], sizeof(struct msm_iommu_dev));
-		if (ret != 0) {
-			pr_err("platform_device_add_data failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-
-		ret = platform_device_register(devs[i]);
-
-		if (ret != 0) {
-			pr_err("platform_device_register iommu failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-	}
-	return 0;
-
-failure_unwind:
-	while (--i >= 0)
-		platform_device_unregister(devs[i]);
-
-	return ret;
-}
-
-
-static int iommu_init_ctx_devs(struct platform_device *ctx_devs[],
-	struct msm_iommu_ctx_dev *ctx_data[], int size)
-{
-	int ret, i;
-
-	for (i = 0; i < size; i++) {
-		ret = platform_device_add_data(ctx_devs[i],
-				ctx_data[i], sizeof(struct msm_iommu_ctx_dev));
-		if (ret != 0) {
-			pr_err("platform_device_add_data iommu failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-
-		ret = platform_device_register(ctx_devs[i]);
-		if (ret != 0) {
-			pr_err("platform_device_register ctx failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-	}
-	return 0;
-
-failure_unwind:
-	while (--i >= 0)
-		platform_device_unregister(ctx_devs[i]);
-
-	return ret;
-}
-
 static int __init iommu_init(void)
 {
 	int ret;
@@ -1069,49 +997,45 @@
 	}
 
 	/* Initialize common devs */
-	ret = iommu_init_devs(msm_iommu_common_devs,
-			 msm_iommu_common_data,
-			 ARRAY_SIZE(msm_iommu_common_devs));
-	if (ret != 0)
-		goto failure2;
+	platform_add_devices(msm_iommu_common_devs,
+				ARRAY_SIZE(msm_iommu_common_devs));
 
 	/* Initialize soc-specific devs */
-	if (cpu_is_apq8064()) {
-		ret = iommu_init_devs(msm_iommu_8064_devs,
-				 msm_iommu_8064_data,
-				 ARRAY_SIZE(msm_iommu_8064_devs));
-	} else {
-		ret = iommu_init_devs(msm_iommu_gfx2d_devs,
-					 msm_iommu_gfx2d_data,
-					ARRAY_SIZE(msm_iommu_gfx2d_devs));
+	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+		platform_add_devices(msm_iommu_jpegd_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_devs));
+		platform_add_devices(msm_iommu_gfx2d_devs,
+				ARRAY_SIZE(msm_iommu_gfx2d_devs));
 	}
-	if (ret != 0)
-		goto failure2;
+
+	if (cpu_is_apq8064()) {
+		platform_add_devices(msm_iommu_jpegd_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_devs));
+		platform_add_devices(msm_iommu_8064_devs,
+				ARRAY_SIZE(msm_iommu_8064_devs));
+	}
 
 	/* Initialize common ctx_devs */
-	ret = iommu_init_ctx_devs(msm_iommu_common_ctx_devs,
-				 msm_iommu_common_ctx_data,
-				 ARRAY_SIZE(msm_iommu_common_ctx_devs));
-	if (ret != 0)
-		goto failure2;
+	ret = platform_add_devices(msm_iommu_common_ctx_devs,
+				ARRAY_SIZE(msm_iommu_common_ctx_devs));
 
 	/* Initialize soc-specific ctx_devs */
-	if (cpu_is_apq8064()) {
-		ret = iommu_init_ctx_devs(msm_iommu_8064_ctx_devs,
-				msm_iommu_8064_ctx_data,
-				ARRAY_SIZE(msm_iommu_8064_ctx_devs));
-	} else {
-		ret = iommu_init_ctx_devs(msm_iommu_gfx2d_ctx_devs,
-					msm_iommu_gfx2d_ctx_data,
-					ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs));
+	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+		platform_add_devices(msm_iommu_jpegd_ctx_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
+		platform_add_devices(msm_iommu_gfx2d_ctx_devs,
+				ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs));
 	}
-	if (ret != 0)
-		goto failure2;
+
+	if (cpu_is_apq8064()) {
+		platform_add_devices(msm_iommu_jpegd_ctx_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
+		platform_add_devices(msm_iommu_8064_ctx_devs,
+				ARRAY_SIZE(msm_iommu_8064_ctx_devs));
+	}
 
 	return 0;
 
-failure2:
-	platform_device_unregister(&msm_root_iommu_dev);
 failure:
 	return ret;
 }
@@ -1124,26 +1048,36 @@
 	for (i = 0; i < ARRAY_SIZE(msm_iommu_common_ctx_devs); i++)
 		platform_device_unregister(msm_iommu_common_ctx_devs[i]);
 
-	/* soc-specific ctx_devs. */
-	if (cpu_is_apq8064()) {
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_ctx_devs); i++)
-			platform_device_unregister(msm_iommu_8064_ctx_devs[i]);
-	} else {
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs); i++)
-			platform_device_unregister(msm_iommu_gfx2d_ctx_devs[i]);
-	}
-
 	/* Common devs. */
 	for (i = 0; i < ARRAY_SIZE(msm_iommu_common_devs); ++i)
 		platform_device_unregister(msm_iommu_common_devs[i]);
 
-	/* soc-specific devs. */
-	if (cpu_is_apq8064()) {
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_devs); i++)
-			platform_device_unregister(msm_iommu_8064_devs[i]);
-	} else {
+	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_gfx2d_ctx_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_ctx_devs[i]);
+
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_gfx2d_devs); i++)
 			platform_device_unregister(msm_iommu_gfx2d_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_devs[i]);
+	}
+
+	if (cpu_is_apq8064()) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_8064_ctx_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_ctx_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_devs); i++)
+			platform_device_unregister(msm_iommu_8064_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_devs[i]);
 	}
 
 	platform_device_unregister(&msm_root_iommu_dev);
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index b895870..77314e7 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -35,6 +35,8 @@
 #include <mach/msm_hsusb.h>
 #include <mach/usbdiag.h>
 #include <mach/rpc_hsusb.h>
+#include "irq.h"
+#include "pm.h"
 
 static struct resource resources_uart1[] = {
 	{
@@ -76,6 +78,21 @@
 	.resource	= resources_uart2,
 };
 
+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,
+};
+
 #define MSM_UART1DM_PHYS      0xA0200000
 #define MSM_UART2DM_PHYS      0xA0300000
 static struct resource msm_uart1_dm_resources[] = {
@@ -400,6 +417,21 @@
 	},
 };
 
+static struct msm_pm_irq_calls msm7x27_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+void msm_pm_register_irqs(void)
+{
+	msm_pm_set_irq_extns(&msm7x27_pm_irq_calls);
+}
+
 #define MSM_SDC1_BASE         0xA0400000
 #define MSM_SDC2_BASE         0xA0500000
 #define MSM_SDC3_BASE         0xA0600000
@@ -822,7 +854,7 @@
 	.init_level = 0,
 	.num_levels = 1,
 	.set_grp_async = NULL,
-	.idle_timeout = HZ/5,
+	.idle_timeout = HZ,
 	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
 };
 
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 15d4ae6..4575166 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -33,6 +33,10 @@
 #include "devices-msm7x2xa.h"
 #include "footswitch.h"
 #include "acpuclock.h"
+#include "spm.h"
+#include "mpm-8625.h"
+#include "irq.h"
+#include "pm.h"
 
 /* Address of GSBI blocks */
 #define MSM_GSBI0_PHYS		0xA1200000
@@ -178,17 +182,6 @@
 	&msm_device_hsusb_host,
 };
 
-int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
-{
-	struct platform_device	*pdev;
-
-	pdev = msm_host_devices[host];
-	if (!pdev)
-		return -ENODEV;
-	pdev->dev.platform_data = plat;
-	return platform_device_register(pdev);
-}
-
 static struct resource msm_dmov_resource[] = {
 	{
 		.start = INT_ADM_AARM,
@@ -221,6 +214,78 @@
 	.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,
+		.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[] = {
 	{
 		.start	= INT_UART1,
@@ -362,6 +427,35 @@
 	},
 };
 
+static struct msm_pm_irq_calls msm7x27a_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+static struct msm_pm_irq_calls msm8625_pm_irq_calls = {
+	.irq_pending = msm_gic_spi_ppi_pending,
+	.idle_sleep_allowed = msm_gic_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_gic_irq_enter_sleep1,
+	.enter_sleep2 = msm_gic_irq_enter_sleep2,
+	.exit_sleep1 = msm_gic_irq_exit_sleep1,
+	.exit_sleep2 = msm_gic_irq_exit_sleep2,
+	.exit_sleep3 = msm_gic_irq_exit_sleep3,
+};
+
+void msm_pm_register_irqs(void)
+{
+	if (cpu_is_msm8625())
+		msm_pm_set_irq_extns(&msm8625_pm_irq_calls);
+	else
+		msm_pm_set_irq_extns(&msm7x27a_pm_irq_calls);
+
+}
+
 #define MSM_SDC1_BASE         0xA0400000
 #define MSM_SDC2_BASE         0xA0500000
 #define MSM_SDC3_BASE         0xA0600000
@@ -513,18 +607,6 @@
 	&msm_device_sdc4,
 };
 
-int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
-{
-	struct platform_device	*pdev;
-
-	if (controller < 1 || controller > 4)
-		return -EINVAL;
-
-	pdev = msm_sdcc_devices[controller-1];
-	pdev->dev.platform_data = plat;
-	return platform_device_register(pdev);
-}
-
 #ifdef CONFIG_MSM_CAMERA_V4L2
 static struct resource msm_csic0_resources[] = {
 	{
@@ -592,6 +674,57 @@
 
 #endif
 
+/* Command sequence for simple WFI */
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+	0x04, 0x03, 0x04, 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,
+	0x03, 0x1e, 0x0e, 0x3e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x2E, 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
 
@@ -675,7 +808,7 @@
 	.init_level = 0,
 	.num_levels = 3,
 	.set_grp_async = set_grp_xbar_async,
-	.idle_timeout = HZ/5,
+	.idle_timeout = HZ,
 	.nap_allowed = false,
 	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
 };
@@ -701,6 +834,12 @@
 	}
 }
 
+void __init msm8x25_kgsl_3d0_init(void)
+{
+	if (cpu_is_msm8625())
+		kgsl_3d0_pdata.idle_timeout = HZ/5;
+}
+
 static void __init msm_register_device(struct platform_device *pdev, void *data)
 {
 	int ret;
@@ -715,17 +854,6 @@
 				__func__, ret);
 }
 
-void __init msm_fb_register_device(char *name, void *data)
-{
-	if (!strncmp(name, "mdp", 3))
-		msm_register_device(&msm_mdp_device, data);
-	else if (!strncmp(name, "mipi_dsi", 8))
-		msm_register_device(&msm_mipi_dsi_device, data);
-	else if (!strncmp(name, "lcdc", 4))
-		msm_register_device(&msm_lcdc_device, data);
-	else
-		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
-}
 
 #define PERPH_WEB_BLOCK_ADDR (0xA9D00040)
 #define PDM0_CTL_OFFSET (0x04)
@@ -815,6 +943,83 @@
 	.resource	= msm8625_resources_uart1,
 };
 
+static struct resource msm8625_uart1_dm_resources[] = {
+	{
+		.start	= MSM_UART1DM_PHYS,
+		.end	= MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_UART1DM_IRQ,
+		.end	= MSM8625_INT_UART1DM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM8625_INT_UART1DM_RX,
+		.end	= MSM8625_INT_UART1DM_RX,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= DMOV_HSUART1_TX_CHAN,
+		.end	= DMOV_HSUART1_RX_CHAN,
+		.name	= "uartdm_channels",
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.start	= DMOV_HSUART1_TX_CRCI,
+		.end	= DMOV_HSUART1_RX_CRCI,
+		.name	= "uartdm_crci",
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm8625_device_uart_dm1 = {
+	.name	= "msm_serial_hs",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(msm8625_uart1_dm_resources),
+	.resource	= msm8625_uart1_dm_resources,
+	.dev	= {
+		.dma_mask		= &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm8625_uart2dm_resources[] = {
+	{
+		.start	= MSM_UART2DM_PHYS,
+		.end	= MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_UART2DM_IRQ,
+		.end	= MSM8625_INT_UART2DM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_uart_dm2 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(msm8625_uart2dm_resources),
+	.resource	= msm8625_uart2dm_resources,
+};
+
+static struct resource msm8625_resources_adsp[] = {
+	{
+		.start  = MSM8625_INT_ADSP_A9_A11,
+		.end    = MSM8625_INT_ADSP_A9_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_adsp = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(msm8625_resources_adsp),
+	.resource       = msm8625_resources_adsp,
+};
+
 static struct resource msm8625_dmov_resource[] = {
 	{
 		.start	= MSM8625_INT_ADM_AARM,
@@ -859,7 +1064,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),
@@ -888,7 +1093,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),
@@ -913,6 +1118,391 @@
 	.num_resources	= ARRAY_SIZE(msm8625_gpio_resources),
 };
 
+static struct resource msm8625_resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC1_0,
+		.end	= MSM8625_INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource msm8625_resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC2_0,
+		.end	= MSM8625_INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource msm8625_resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC3_0,
+		.end	= MSM8625_INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource msm8625_resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC4_0,
+		.end	= MSM8625_INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm8625_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc1),
+	.resource	= msm8625_resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm8625_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc2),
+	.resource	= msm8625_resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm8625_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc3),
+	.resource	= msm8625_resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm8625_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc4),
+	.resource	= msm8625_resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm8625_sdcc_devices[] __initdata = {
+	&msm8625_device_sdc1,
+	&msm8625_device_sdc2,
+	&msm8625_device_sdc3,
+	&msm8625_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	if (cpu_is_msm8625())
+		pdev = msm8625_sdcc_devices[controller-1];
+	else
+		pdev = msm_sdcc_devices[controller-1];
+
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+static struct resource msm8625_resources_hsusb_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_USB_HS,
+		.end	= MSM8625_INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_hsusb_otg),
+	.resource	= msm8625_resources_hsusb_otg,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource msm8625_resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_USB_HS,
+		.end	= MSM8625_INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_gadget_peripheral),
+	.resource	= msm8625_resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource msm8625_resources_hsusb_host[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_USB_HS,
+		.end	= MSM8625_INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_hsusb_host),
+	.resource	= msm8625_resources_hsusb_host,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm8625_host_devices[] = {
+	&msm8625_device_hsusb_host,
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (cpu_is_msm8625())
+		pdev = msm8625_host_devices[host];
+	else
+		pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm8625_csic0_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0xA0F00000,
+		.end    = 0xA0F00000 + 0x00100000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = MSM8625_INT_CSI_IRQ_0,
+		.end    = MSM8625_INT_CSI_IRQ_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm8625_csic1_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0xA1000000,
+		.end    = 0xA1000000 + 0x00100000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = MSM8625_INT_CSI_IRQ_1,
+		.end    = MSM8625_INT_CSI_IRQ_1,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_csic0 = {
+	.name           = "msm_csic",
+	.id             = 0,
+	.resource       = msm8625_csic0_resources,
+	.num_resources  = ARRAY_SIZE(msm8625_csic0_resources),
+};
+
+struct platform_device msm8625_device_csic1 = {
+	.name           = "msm_csic",
+	.id             = 1,
+	.resource       = msm8625_csic1_resources,
+	.num_resources  = ARRAY_SIZE(msm8625_csic1_resources),
+};
+#endif
+
+static struct resource msm8625_mipi_dsi_resources[] = {
+	{
+		.name   = "mipi_dsi",
+		.start  = MIPI_DSI_HW_BASE,
+		.end    = MIPI_DSI_HW_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM8625_INT_DSI_IRQ,
+		.end    = MSM8625_INT_DSI_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm8625_mipi_dsi_device = {
+	.name   = "mipi_dsi",
+	.id     = 1,
+	.num_resources  = ARRAY_SIZE(msm8625_mipi_dsi_resources),
+	.resource       = msm8625_mipi_dsi_resources,
+};
+
+static struct resource msm8625_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F1008 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM8625_INT_MDP,
+		.end    = MSM8625_INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm8625_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm8625_mdp_resources),
+	.resource       = msm8625_mdp_resources,
+};
+
+void __init msm_fb_register_device(char *name, void *data)
+{
+	if (!strncmp(name, "mdp", 3)) {
+		if (cpu_is_msm8625())
+			msm_register_device(&msm8625_mdp_device, data);
+		else
+			msm_register_device(&msm_mdp_device, data);
+	} else if (!strncmp(name, "mipi_dsi", 8)) {
+		if (cpu_is_msm8625())
+			msm_register_device(&msm8625_mipi_dsi_device, data);
+		else
+			msm_register_device(&msm_mipi_dsi_device, data);
+	} else if (!strncmp(name, "lcdc", 4)) {
+			msm_register_device(&msm_lcdc_device, data);
+	} else {
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+	}
+}
+
+static struct resource msm8625_kgsl_3d0_resources[] = {
+	{
+		.name  = KGSL_3D0_REG_MEMORY,
+		.start = 0xA0000000,
+		.end = 0xA001ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = MSM8625_INT_GRAPHICS,
+		.end = MSM8625_INT_GRAPHICS,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm8625_kgsl_3d0_resources),
+	.resource = msm8625_kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
 static struct clk_lookup msm_clock_8625_dummy[] = {
 	CLK_DUMMY("core_clk",		adm_clk.c,	"msm_dmov", 0),
 	CLK_DUMMY("adsp_clk",		adsp_clk.c,	NULL, 0),
@@ -980,6 +1570,36 @@
 	.size = ARRAY_SIZE(msm_clock_8625_dummy),
 };
 
+enum {
+	MSM8625,
+	MSM8625A,
+};
+
+static int __init msm8625_cpu_id(void)
+{
+	int raw_id, cpu;
+
+	raw_id = socinfo_get_raw_id();
+	switch (raw_id) {
+	/* Part number for 1GHz part */
+	case 0x770:
+	case 0x771:
+	case 0x780:
+		cpu = MSM8625;
+		break;
+	/* Part number for 1.2GHz part */
+	case 0x773:
+	case 0x774:
+	case 0x781:
+		cpu = MSM8625A;
+		break;
+	default:
+		pr_err("Invalid Raw ID\n");
+		return -ENODEV;
+	}
+	return cpu;
+}
+
 int __init msm7x2x_misc_init(void)
 {
 	if (machine_is_msm8625_rumi3()) {
@@ -990,8 +1610,14 @@
 	msm_clock_init(&msm7x27a_clock_init_data);
 	if (cpu_is_msm7x27aa())
 		acpuclk_init(&acpuclk_7x27aa_soc_data);
-	else
+	else if (cpu_is_msm8625()) {
+		if (msm8625_cpu_id() == MSM8625)
+			acpuclk_init(&acpuclk_7x27aa_soc_data);
+		else if (msm8625_cpu_id() == MSM8625A)
+			acpuclk_init(&acpuclk_8625_soc_data);
+	 } else {
 		acpuclk_init(&acpuclk_7x27a_soc_data);
+	 }
 
 
 	return 0;
@@ -1032,6 +1658,7 @@
 
 void __init msm8625_init_irq(void)
 {
+	msm_gic_irq_extn_init(MSM_QGIC_DIST_BASE, MSM_QGIC_CPU_BASE);
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 			(void *)MSM_QGIC_CPU_BASE);
 }
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index be6a645..407554c 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -23,7 +23,13 @@
 extern struct platform_device msm7x27a_device_csic0;
 extern struct platform_device msm7x27a_device_csic1;
 extern struct platform_device msm7x27a_device_clkctl;
+
+extern struct platform_device msm8625_device_csic0;
+extern struct platform_device msm8625_device_csic1;
+
 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);
+void __init msm8x25_kgsl_3d0_init(void);
 #endif
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index e9b94f6..17e7364 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -40,6 +40,8 @@
 #endif
 #include <mach/dal_axi.h>
 #include <mach/msm_memtypes.h>
+#include "pm.h"
+#include "irq.h"
 
 /* EBI THERMAL DRIVER */
 static struct resource msm_ebi0_thermal_resources[] = {
@@ -74,6 +76,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[] = {
 	{
@@ -82,8 +98,8 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.start	= MSM_UART1_PHYS,
-		.end	= MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
+		.start	= MSM7X30_UART1_PHYS,
+		.end	= MSM7X30_UART1_PHYS + MSM7X30_UART1_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 };
@@ -95,8 +111,8 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.start	= MSM_UART2_PHYS,
-		.end	= MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
+		.start	= MSM7X30_UART2_PHYS,
+		.end	= MSM7X30_UART2_PHYS + MSM7X30_UART2_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 		.name  = "uart_resource"
 	},
@@ -109,8 +125,8 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.start	= MSM_UART3_PHYS,
-		.end	= MSM_UART3_PHYS + MSM_UART3_SIZE - 1,
+		.start	= MSM7X30_UART3_PHYS,
+		.end	= MSM7X30_UART3_PHYS + MSM7X30_UART3_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 };
@@ -581,6 +597,21 @@
 	},
 };
 
+static struct msm_pm_irq_calls msm7x30_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+void msm_pm_register_irqs(void)
+{
+	msm_pm_set_irq_extns(&msm7x30_pm_irq_calls);
+}
+
 static struct resource smd_resource[] = {
 	{
 		.name   = "a9_m2a_0",
@@ -612,7 +643,7 @@
 		.smd_int.dev_id = 0,
 
 		.smd_int.out_bit_pos =  1 << 0,
-		.smd_int.out_base = (void __iomem *)MSM_GCC_BASE,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
 		.smd_int.out_offset = 0x8,
 
 		.smsm_int.irq_name = "a9_m2a_5",
@@ -622,7 +653,7 @@
 		.smsm_int.dev_id = 0,
 
 		.smsm_int.out_bit_pos =  1 << 5,
-		.smsm_int.out_base = (void __iomem *)MSM_GCC_BASE,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
 		.smsm_int.out_offset = 0x8,
 
 	}
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 4670ce8..ba7ac2a 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -220,6 +220,12 @@
 	.id = -1,
 };
 
+struct platform_device msm_pil_dsps = {
+	.name          = "pil_dsps",
+	.id            = -1,
+	.dev.platform_data = "dsps",
+};
+
 static struct resource msm_uart1_dm_resources[] = {
 	{
 		.start = MSM_UART1DM_PHYS,
@@ -325,6 +331,7 @@
 	.config_gpio	= 1,
 	.uart_tx_gpio	= 67,
 	.uart_rx_gpio	= 66,
+	.line		= 1,
 };
 
 static struct resource msm_uart_gsbi9_resources[] = {
@@ -2466,6 +2473,7 @@
 		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
 	},
 	.irq_ack = RPM_SCSS_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_SCSS_CPU0_GP_LOW_IRQ,
 	.ipc_rpm_reg = MSM_GCC_BASE + 0x008,
 	.ipc_rpm_val = 4,
 	.target_id = {
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 05efcdf..a32079b 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 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
@@ -33,6 +33,7 @@
 #include <mach/msm_hsusb.h>
 #include <mach/usbdiag.h>
 #include <mach/rpc_hsusb.h>
+#include "pm.h"
 
 static struct resource resources_uart1[] = {
 	{
@@ -432,6 +433,21 @@
 	},
 };
 
+static struct msm_pm_irq_calls qsd8x50_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+void msm_pm_register_irqs(void)
+{
+	msm_pm_set_irq_extns(&qsd8x50_pm_irq_calls);
+}
+
 struct platform_device msm_device_smd = {
 	.name	= "msm_smd",
 	.id	= -1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index c86d051..5758dc4 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -25,6 +25,8 @@
 void __init msm9615_map_io(void);
 void __init msm_map_msm9615_io(void);
 void __init msm9615_init_irq(void);
+void __init msm_rotator_update_bus_vectors(unsigned int xres,
+	unsigned int yres);
 
 extern struct platform_device asoc_msm_pcm;
 extern struct platform_device asoc_msm_dai0;
@@ -38,6 +40,7 @@
 extern struct platform_device msm_ebi0_thermal;
 extern struct platform_device msm_ebi1_thermal;
 
+extern struct platform_device msm_adsp_device;
 extern struct platform_device msm_device_uart1;
 extern struct platform_device msm_device_uart2;
 extern struct platform_device msm_device_uart3;
@@ -55,6 +58,7 @@
 extern struct platform_device msm8960_device_ssbi_pmic;
 extern struct platform_device msm8960_device_qup_i2c_gsbi3;
 extern struct platform_device msm8960_device_qup_i2c_gsbi4;
+extern struct platform_device msm8960_device_qup_i2c_gsbi9;
 extern struct platform_device msm8960_device_qup_i2c_gsbi10;
 extern struct platform_device msm8960_device_qup_i2c_gsbi12;
 extern struct platform_device msm8960_device_qup_spi_gsbi1;
@@ -69,6 +73,7 @@
 extern struct platform_device msm8960_device_ispif;
 extern struct platform_device msm8960_device_vfe;
 extern struct platform_device msm8960_device_vpe;
+extern struct platform_device msm8960_device_cache_erp;
 
 extern struct platform_device apq8064_device_uart_gsbi1;
 extern struct platform_device apq8064_device_uart_gsbi3;
@@ -80,6 +85,7 @@
 extern struct platform_device apq8064_slim_ctrl;
 extern struct platform_device apq8064_device_ssbi_pmic1;
 extern struct platform_device apq8064_device_ssbi_pmic2;
+extern struct platform_device apq8064_device_cache_erp;
 
 extern struct platform_device msm9615_device_uart_gsbi4;
 extern struct platform_device msm9615_device_qup_i2c_gsbi5;
@@ -110,6 +116,8 @@
 extern struct platform_device apq8064_device_gadget_peripheral;
 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;
 
@@ -126,8 +134,19 @@
 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;
+extern struct platform_device msm8625_device_sdc2;
+extern struct platform_device msm8625_device_sdc3;
+extern struct platform_device msm8625_device_sdc4;
+extern struct platform_device msm8625_device_gadget_peripheral;
+extern struct platform_device msm8625_device_hsusb_host;
+extern struct platform_device msm8625_device_otg;
+extern struct platform_device msm8625_kgsl_3d0;
+extern struct platform_device msm8625_device_adsp;
 
 extern struct platform_device msm_slim_ctrl;
 extern struct platform_device msm_device_sps;
@@ -136,6 +155,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;
@@ -199,6 +219,7 @@
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
 extern struct platform_device msm_pil_tzapps;
+extern struct platform_device msm_pil_dsps;
 extern struct platform_device msm_8960_q6_lpass;
 extern struct platform_device msm_8960_q6_mss_fw;
 extern struct platform_device msm_8960_q6_mss_sw;
@@ -228,9 +249,13 @@
 extern struct platform_device apq_cpudai_afe_02_tx;
 extern struct platform_device apq_pcm_afe;
 extern struct platform_device apq_cpudai_stub;
+extern struct platform_device apq_cpudai_slimbus_1_rx;
+extern struct platform_device apq_cpudai_slimbus_1_tx;
 
 extern struct platform_device *msm_footswitch_devices[];
 extern unsigned msm_num_footswitch_devices;
+extern struct platform_device *apq8064_fs_devices[];
+extern unsigned apq8064_num_fs_devices;
 
 extern struct platform_device fsm_qfp_fuse_device;
 
@@ -244,6 +269,7 @@
 
 extern struct platform_device msm_mipi_dsi1_device;
 extern struct platform_device msm_lvds_device;
+extern struct platform_device msm_ebi2_lcdc_device;
 
 extern struct clk_lookup msm_clocks_fsm9xxx[];
 extern unsigned msm_num_clocks_fsm9xxx;
@@ -293,11 +319,15 @@
 extern struct platform_device msm8660_device_watchdog;
 extern struct platform_device msm8064_device_watchdog;
 extern struct platform_device msm9615_device_watchdog;
+extern struct platform_device fsm9xxx_device_watchdog;
 
+extern struct platform_device apq8064_qdss_device;
+extern struct platform_device msm_qdss_device;
 extern struct platform_device msm_etb_device;
 extern struct platform_device msm_tpiu_device;
 extern struct platform_device msm_funnel_device;
-extern struct platform_device msm_ptm_device;
+extern struct platform_device msm_etm_device;
+extern struct platform_device apq8064_etm_device;
 #endif
 
 extern struct platform_device msm_bus_8064_apps_fabric;
@@ -307,3 +337,20 @@
 extern struct platform_device msm_bus_8064_cpss_fpb;
 
 extern struct platform_device mdm_8064_device;
+extern struct platform_device msm_dsps_device_8064;
+extern struct platform_device *msm_copper_stub_regulator_devices[];
+extern int msm_copper_stub_regulator_devices_len;
+
+extern struct platform_device msm8960_cpu_idle_device;
+extern struct platform_device msm8930_cpu_idle_device;
+extern struct platform_device apq8064_cpu_idle_device;
+
+extern struct platform_device msm8960_msm_gov_device;
+extern struct platform_device msm8930_msm_gov_device;
+extern struct platform_device apq8064_msm_gov_device;
+
+extern struct platform_device msm_bus_8930_apps_fabric;
+extern struct platform_device msm_bus_8930_sys_fabric;
+extern struct platform_device msm_bus_8930_mm_fabric;
+extern struct platform_device msm_bus_8930_sys_fpb;
+extern struct platform_device msm_bus_8930_cpss_fpb;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index ad1aecd..087227c 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/dma.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -286,9 +286,11 @@
 	int ch = DMOV_ID_TO_CHAN(id);
 
 	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
-	if (dmov_conf[adm].clk_ctl == CLK_DIS)
-		msm_dmov_clk_toggle(adm, 1);
-	else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
+	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
+		status = msm_dmov_clk_toggle(adm, 1);
+		if (status != 0)
+			goto error;
+	} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
 		del_timer(&dmov_conf[adm].timer);
 	dmov_conf[adm].clk_ctl = CLK_EN;
 
@@ -316,6 +318,7 @@
 		    "%x\n", id, status);
 		list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
 	}
+error:
 	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
 EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 5c10463..d5a1d3f 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -99,8 +99,8 @@
 					clock->reset_rate : DEFAULT_RATE;
 			rc = clk_set_rate(clock->clk, rate);
 			if (rc && rc != -ENOSYS) {
-				pr_err("Failed to set %s rate to %lu Hz.\n",
-					clock->name, clock->rate);
+				pr_err("Failed to set %s %s rate to %lu Hz.\n",
+				       fs->desc.name, clock->name, clock->rate);
 				for (clock--; clock >= fs->clk_data; clock--) {
 					if (clock->enabled)
 						clk_disable_unprepare(
@@ -131,8 +131,8 @@
 		if (clock->enabled)
 			clk_disable_unprepare(clock->clk);
 		if (clock->rate && clk_set_rate(clock->clk, clock->rate))
-			pr_err("Failed to restore %s rate to %lu Hz.\n",
-				clock->name, clock->rate);
+			pr_err("Failed to restore %s %s rate to %lu Hz.\n",
+			       fs->desc.name, clock->name, clock->rate);
 	}
 }
 
@@ -167,14 +167,14 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 unhalt failed.\n");
+			pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
 	if (fs->bus_port1) {
 		rc = msm_bus_axi_portunhalt(fs->bus_port1);
 		if (rc) {
-			pr_err("Port 1 unhalt failed.\n");
+			pr_err("%s port 1 unhalt failed.\n", fs->desc.name);
 			goto err_port2_halt;
 		}
 	}
@@ -252,14 +252,14 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 halt failed.\n");
+			pr_err("%s port 0 halt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
 	if (fs->bus_port1) {
 		rc = msm_bus_axi_porthalt(fs->bus_port1);
 		if (rc) {
-			pr_err("Port 1 halt failed.\n");
+			pr_err("%s port 1 halt failed.\n", fs->desc.name);
 			goto err_port2_halt;
 		}
 	}
@@ -329,7 +329,7 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 unhalt failed.\n");
+			pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
@@ -404,7 +404,7 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 halt failed.\n");
+			pr_err("%s port 0 halt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
@@ -635,7 +635,8 @@
 		clock->clk = clk_get(&pdev->dev, clock->name);
 		if (IS_ERR(clock->clk)) {
 			rc = PTR_ERR(clock->clk);
-			pr_err("clk_get(%s) failed\n", clock->name);
+			pr_err("%s clk_get(%s) failed\n", fs->desc.name,
+			       clock->name);
 			goto err;
 		}
 		if (!strncmp(clock->name, "core_clk", 8))
@@ -652,7 +653,8 @@
 	regval &= ~RETENTION_BIT;
 	writel_relaxed(regval, fs->gfs_ctl_reg);
 
-	fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
+	fs->rdev = regulator_register(&fs->desc, &pdev->dev,
+							init_data, fs, NULL);
 	if (IS_ERR(footswitches[pdev->id].rdev)) {
 		pr_err("regulator_register(\"%s\") failed\n",
 			fs->desc.name);
diff --git a/arch/arm/mach-msm/footswitch-pcom.c b/arch/arm/mach-msm/footswitch-pcom.c
index 340f19b..73cbab1 100644
--- a/arch/arm/mach-msm/footswitch-pcom.c
+++ b/arch/arm/mach-msm/footswitch-pcom.c
@@ -205,14 +205,14 @@
 		fs->src_clk = clk_get(dev, "core_clk");
 	}
 	if (IS_ERR(fs->src_clk)) {
-		pr_err("clk_get(src_clk) failed\n");
+		pr_err("%s clk_get(src_clk) failed\n", fs->desc.name);
 		rc = PTR_ERR(fs->src_clk);
 		goto err_src_clk;
 	}
 
 	fs->core_clk = clk_get(dev, "core_clk");
 	if (IS_ERR(fs->core_clk)) {
-		pr_err("clk_get(core_clk) failed\n");
+		pr_err("%s clk_get(core_clk) failed\n", fs->desc.name);
 		rc = PTR_ERR(fs->core_clk);
 		goto err_core_clk;
 	}
@@ -220,7 +220,7 @@
 	if (fs->has_ahb_clk) {
 		fs->ahb_clk = clk_get(dev, "iface_clk");
 		if (IS_ERR(fs->ahb_clk)) {
-			pr_err("clk_get(iface_clk) failed\n");
+			pr_err("%s clk_get(iface_clk) failed\n", fs->desc.name);
 			rc = PTR_ERR(fs->ahb_clk);
 			goto err_ahb_clk;
 		}
@@ -266,7 +266,8 @@
 	if (rc)
 		return rc;
 
-	fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
+	fs->rdev = regulator_register(&fs->desc, &pdev->dev,
+							init_data, fs, NULL);
 	if (IS_ERR(fs->rdev)) {
 		pr_err("regulator_register(%s) failed\n", fs->desc.name);
 		rc = PTR_ERR(fs->rdev);
@@ -306,8 +307,6 @@
 	struct footswitch *fs;
 	int ret;
 
-	if (cpu_is_msm8625())
-		return 0;
 	/*
 	 * Enable all footswitches in manual mode (ie. not controlled along
 	 * with pcom clocks).
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
new file mode 100644
index 0000000..3c475d6
--- /dev/null
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -0,0 +1,259 @@
+/* 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/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
+
+#include "smd_private.h"
+#include "modem_notifier.h"
+#include "ramdump.h"
+
+static struct gss_8064_data {
+	struct miscdevice gss_dev;
+	void *pil_handle;
+	void *gss_ramdump_dev;
+	void *smem_ramdump_dev;
+} gss_data;
+
+static int crash_shutdown;
+
+static void gss_fatal_fn(struct work_struct *work)
+{
+	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+	uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
+					SMSM_SYSTEM_PWRDWN_USR;
+	uint32_t gss_state;
+
+	pr_err("Watchdog bite received from GSS!\n");
+
+	gss_state = smsm_get_state(SMSM_MODEM_STATE);
+
+	if (gss_state & panic_smsm_states) {
+
+		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
+			"Probable err_fatal on the GSS. "
+			"Calling subsystem restart...\n");
+		subsystem_restart("gss");
+
+	} else if (gss_state & reset_smsm_states) {
+
+		pr_err("%s: User-invoked system reset/powerdown. "
+			"Resetting the SoC now.\n",
+			__func__);
+		kernel_restart(NULL);
+	} else {
+		/* TODO: Bus unlock code/sequence goes _here_ */
+		subsystem_restart("gss");
+	}
+}
+
+static DECLARE_WORK(gss_fatal_work, gss_fatal_fn);
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
+			"Probable err_fatal on the GSS. "
+			"Calling subsystem restart...\n");
+		subsystem_restart("gss");
+	}
+}
+
+#define Q6_FW_WDOG_ENABLE		0x08882024
+#define Q6_SW_WDOG_ENABLE		0x08982024
+static int gss_shutdown(const struct subsys_data *subsys)
+{
+	pil_force_shutdown("gss");
+	disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
+
+	return 0;
+}
+
+static int gss_powerup(const struct subsys_data *subsys)
+{
+	pil_force_boot("gss");
+	enable_irq(GSS_A5_WDOG_EXPIRED);
+	return 0;
+}
+
+void gss_crash_shutdown(const struct subsys_data *subsys)
+{
+	crash_shutdown = 1;
+	smsm_reset_modem(SMSM_RESET);
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment gss_segments[] = {
+	{0x89000000, 0x00D00000}
+};
+
+static struct ramdump_segment smem_segments[] = {
+	{0x80000000, 0x00200000},
+};
+
+static int gss_ramdump(int enable,
+				const struct subsys_data *crashed_subsys)
+{
+	int ret = 0;
+
+	if (enable) {
+		ret = do_ramdump(gss_data.gss_ramdump_dev, gss_segments,
+			ARRAY_SIZE(gss_segments));
+
+		if (ret < 0) {
+			pr_err("Unable to dump gss memory (rc = %d).\n",
+			       ret);
+			goto out;
+		}
+
+		ret = do_ramdump(gss_data.smem_ramdump_dev, smem_segments,
+			ARRAY_SIZE(smem_segments));
+
+		if (ret < 0) {
+			pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+			goto out;
+		}
+	}
+
+out:
+	return ret;
+}
+
+static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
+{
+	schedule_work(&gss_fatal_work);
+	disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
+
+	return IRQ_HANDLED;
+}
+
+static struct subsys_data gss_8064 = {
+	.name = "gss",
+	.shutdown = gss_shutdown,
+	.powerup = gss_powerup,
+	.ramdump = gss_ramdump,
+	.crash_shutdown = gss_crash_shutdown
+};
+
+static int gss_subsystem_restart_init(void)
+{
+	return ssr_register_subsystem(&gss_8064);
+}
+
+static int gss_open(struct inode *inode, struct file *filep)
+{
+	void *ret;
+	gss_data.pil_handle = ret = pil_get("gss");
+	if (!ret)
+		pr_debug("%s - pil_get returned NULL\n", __func__);
+	return 0;
+}
+
+static int gss_release(struct inode *inode, struct file *filep)
+{
+	pil_put(gss_data.pil_handle);
+	pr_debug("%s pil_put called on GSS\n", __func__);
+	return 0;
+}
+
+const struct file_operations gss_file_ops = {
+	.open = gss_open,
+	.release = gss_release,
+};
+
+static int __init gss_8064_init(void)
+{
+	int ret;
+
+	if (!cpu_is_apq8064())
+		return -ENODEV;
+
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+		smsm_state_cb, 0);
+
+	if (ret < 0)
+		pr_err("%s: Unable to register SMSM callback! (%d)\n",
+				__func__, ret);
+
+	ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
+				__func__, ret);
+		disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
+		goto out;
+	}
+
+	ret = gss_subsystem_restart_init();
+
+	if (ret < 0) {
+		pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
+	gss_data.gss_dev.name = "gss";
+	gss_data.gss_dev.fops = &gss_file_ops;
+	ret = misc_register(&gss_data.gss_dev);
+
+	if (ret) {
+		pr_err("%s: misc_registers failed for %s (%d)", __func__,
+				gss_data.gss_dev.name, ret);
+		goto out;
+	}
+
+	gss_data.gss_ramdump_dev = create_ramdump_device("gss");
+
+	if (!gss_data.gss_ramdump_dev) {
+		pr_err("%s: Unable to create gss ramdump device. (%d)\n",
+				__func__, -ENOMEM);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	gss_data.smem_ramdump_dev = create_ramdump_device("smem");
+
+	if (!gss_data.smem_ramdump_dev) {
+		pr_err("%s: Unable to create smem ramdump device. (%d)\n",
+				__func__, -ENOMEM);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	pr_info("%s: gss fatal driver init'ed.\n", __func__);
+out:
+	return ret;
+}
+
+module_init(gss_8064_init);
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 8d40908..8a1ff35 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -15,10 +15,10 @@
 #include <asm/cacheflush.h>
 #include <asm/vfp.h>
 
+#include <mach/qdss.h>
 #include <mach/msm_rtb.h>
 
 #include "pm.h"
-#include "qdss.h"
 #include "spm.h"
 
 extern volatile int pen_release;
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 32d162d..0028286 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -19,18 +19,31 @@
 #include <linux/threads.h>
 #include <asm/assembler.h>
 
-#ifdef CONFIG_MSM_CPU_AVS
-/* 11 general purpose registers (r4-r14), 10 cp15 registers, 3 AVS registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10 + 4 * 3)
-#else
-/* 11 general purpose registers (r4-r14), 10 cp15 registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
-#endif
+#include "idle.h"
+
 #ifdef CONFIG_ARCH_MSM_KRAIT
 #define SCM_SVC_BOOT 0x1
 #define SCM_CMD_TERMINATE_PC 0x2
 #endif
 
+/* Switch between smp_to_amp/amp_to_smp configuration */
+.macro SET_SMP_COHERENCY, on = 0
+ldr     r0, =target_type
+ldr     r0, [r0]
+mov     r1, #TARGET_IS_8625
+cmp     r0, r1
+bne     skip\@
+mrc	p15, 0, r0, c1, c0, 1	/* read ACTLR register */
+.if     \on
+orr	r0, r0, #(1 << 6)	/* Set the SMP bit in ACTLR */
+.else
+bic	r0, r0, #(1 << 6)	/* Clear the SMP bit */
+.endif
+mcr	p15, 0, r0, c1, c0, 1	/* write ACTLR register */
+isb
+skip\@:
+.endm
+
 ENTRY(msm_arch_idle)
 	wfi
 #ifdef CONFIG_ARCH_MSM8X60
@@ -45,7 +58,8 @@
 	cpsid   f
 #endif
 
-	ldr     r0, =saved_state
+	ldr     r0, =msm_saved_state	/* address of msm_saved_state ptr */
+	ldr	r0, [r0]		/* load ptr */
 #if (NR_CPUS >= 2)
 	mrc	p15, 0, r1, c0, c0, 5	/* MPIDR */
 	ands	r1, r1, #15		/* What CPU am I */
@@ -100,14 +114,7 @@
 	cmp	r1, #1
 	bne	skip
 	bl	v7_flush_dcache_all
-	b skip2
-
-skip:	ldr	r0, =saved_state
-	ldr	r1, =saved_state_end
-	sub	r1, r1, r0
-	bl	v7_flush_kern_dcache_area
-
-skip2:
+skip:
 #ifdef CONFIG_ARCH_MSM_KRAIT
 	ldr	r0, =SCM_SVC_BOOT
 	ldr	r1, =SCM_CMD_TERMINATE_PC
@@ -121,20 +128,21 @@
 	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
 	dsb
 
+	SET_SMP_COHERENCY OFF
 	wfi
 
 	mcr     p15, 0, r4, c1, c0, 0    /* restore d/i cache  */
 	isb
 #endif
-
-
+	SET_SMP_COHERENCY ON
 #if defined(CONFIG_MSM_FIQ_SUPPORT)
 	cpsie   f
 #endif
 #ifdef CONFIG_MSM_JTAG
 	bl	msm_jtag_restore_state
 #endif
-	ldr     r0, =saved_state        /* restore registers */
+	ldr     r0, =msm_saved_state	/* address of msm_saved_state ptr */
+	ldr	r0, [r0]		/* load ptr */
 #if (NR_CPUS >= 2)
 	mrc	p15, 0, r1, c0, c0, 5	/* MPIDR */
 	ands	r1, r1, #15		/* What CPU am I */
@@ -142,8 +150,7 @@
 	mul	r2, r2, r1
 	add	r0, r0, r2
 #endif
-
-	ldmfd   r0, {r4-r14}
+	ldmfd   r0, {r4-r14}		 /* restore registers */
 	mov     r0, #0                   /* return power collapse failed */
 	bx      lr
 
@@ -157,11 +164,12 @@
 	mov     r1, #'A'
 	str     r1, [r0, #0x00C]
 #endif
-	ldr     r1, =saved_state
+	ldr     r1, =msm_saved_state_phys
 	ldr     r2, =msm_pm_collapse_exit
 	adr     r3, msm_pm_collapse_exit
 	add     r1, r1, r3
 	sub     r1, r1, r2
+	ldr	r1, [r1]
 	add	r1, r1, #CPU_SAVED_STATE_SIZE
 #if (NR_CPUS >= 2)
 	mrc	p15, 0, r2, c0, c0, 5	/* MPIDR */
@@ -218,6 +226,8 @@
 	mcr     p15, 0, r3, c7, c5, 6   /* BPIALL */
 	dsb
 	isb
+
+	SET_SMP_COHERENCY ON
 #ifdef CONFIG_ARCH_MSM_KRAIT
 	mrc	p15, 0, r1, c0, c0, 0
 	ldr	r3, =0xff00fc00
@@ -228,12 +238,11 @@
 	biceq	r3, r3, #0x400
 	mcreq	p15, 7, r3, c15, c0, 2
 #endif
-	stmfd   sp!, {lr}
-	bl      v7_flush_kern_cache_all
 #ifdef CONFIG_MSM_JTAG
+	stmfd   sp!, {lr}
 	bl      msm_jtag_restore_state
-#endif
 	ldmfd   sp!, {lr}
+#endif
 	mov     r0, #1
 	bx      lr
 	nop
@@ -256,17 +265,6 @@
 	add     r1, r1, r0, LSL #2       /* locate boot vector for our cpu */
 	ldr     pc, [r1]                 /* jump                           */
 
-ENTRY(msm_pm_write_boot_vector)
-	ldr     r2, =msm_pm_boot_vector
-	add     r2, r2, r0, LSL #2       /* locate boot vector for our cpu */
-	str     r1, [r2]
-	mov	r0, r2
-	ldr	r1, =4
-	stmfd	sp!, {lr}
-	bl	v7_flush_kern_dcache_area
-	ldmfd	sp!, {lr}
-	bx      lr
-
 ENTRY(msm_pm_set_l2_flush_flag)
 	ldr r1, =msm_pm_flush_l2_flag
 	str r0, [r1]
@@ -278,13 +276,22 @@
 msm_pm_pc_pgd:
 	.long	0x0
 
-saved_state:
-	.space	CPU_SAVED_STATE_SIZE * NR_CPUS
-saved_state_end:
+	.globl msm_saved_state
+msm_saved_state:
+	.long	0x0
 
+	.globl msm_saved_state_phys
+msm_saved_state_phys:
+	.long	0x0
+
+	.globl msm_pm_boot_vector
 msm_pm_boot_vector:
 	.space  4 * NR_CPUS
 
+	.globl target_type
+target_type:
+	.long  0x0
+
 /*
  * Default the l2 flush flag to 1 so that caches are flushed during power
  * collapse unless the  L2 driver decides to flush them only during L2
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 830e36b..bfd632f 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
@@ -14,20 +14,46 @@
 #ifndef _ARCH_ARM_MACH_MSM_IDLE_H_
 #define _ARCH_ARM_MACH_MSM_IDLE_H_
 
+#ifdef CONFIG_MSM_CPU_AVS
+/* 11 general purpose registers (r4-r14), 10 cp15 registers, 3 AVS registers */
+#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10 + 4 * 3)
+#else
+/* 11 general purpose registers (r4-r14), 10 cp15 registers */
+#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
+#endif
+
+#define ON	1
+#define OFF	0
+#define TARGET_IS_8625	1
+
+#ifndef __ASSEMBLY__
+
 int msm_arch_idle(void);
 int msm_pm_collapse(void);
 void msm_pm_collapse_exit(void);
+extern void *msm_saved_state;
+extern unsigned long msm_saved_state_phys;
 
 #ifdef CONFIG_CPU_V7
 void msm_pm_boot_entry(void);
-void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address);
 void msm_pm_set_l2_flush_flag(unsigned int flag);
 extern unsigned long msm_pm_pc_pgd;
+extern unsigned long msm_pm_boot_vector[NR_CPUS];
+extern uint32_t target_type;
 #else
 static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
 {
 	/* 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
 #endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 96b0083..f01b0f7 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -99,6 +99,7 @@
 #define MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER	(0x00000001<<2)
 #define MSM_CAMERA_FLASH_SRC_EXT     (0x00000001<<3)
 #define MSM_CAMERA_FLASH_SRC_LED (0x00000001<<3)
+#define MSM_CAMERA_FLASH_SRC_LED1 (0x00000001<<4)
 
 struct msm_camera_sensor_flash_pmic {
 	uint8_t num_of_src;
@@ -172,6 +173,11 @@
 	BACK_CAMERA_INT_3D,
 };
 
+enum msm_sensor_type {
+	BAYER_SENSOR,
+	YUV_SENSOR,
+};
+
 enum camera_vreg_type {
 	REG_LDO,
 	REG_VS,
@@ -191,6 +197,11 @@
 	uint32_t delay;
 };
 
+struct msm_camera_csi_lane_params {
+	uint8_t csi_lane_assign;
+	uint8_t csi_lane_mask;
+};
+
 struct msm_camera_gpio_conf {
 	void *cam_gpiomux_conf_tbl;
 	uint8_t cam_gpiomux_conf_tbl_size;
@@ -200,6 +211,11 @@
 	uint8_t cam_gpio_req_tbl_size;
 	struct msm_gpio_set_tbl *cam_gpio_set_tbl;
 	uint8_t cam_gpio_set_tbl_size;
+	uint32_t gpio_no_mux;
+	uint32_t *camera_off_table;
+	uint8_t camera_off_table_size;
+	uint32_t *camera_on_table;
+	uint8_t camera_on_table_size;
 };
 
 enum msm_camera_i2c_mux_mode {
@@ -222,6 +238,7 @@
 	int32_t (*ext_power_ctrl) (int enable);
 	struct msm_camera_gpio_conf *gpio_conf;
 	struct msm_camera_i2c_conf *i2c_conf;
+	struct msm_camera_csi_lane_params *csi_lane_params;
 };
 
 struct msm_actuator_info {
@@ -250,6 +267,7 @@
 	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
 	char *eeprom_data;
 	enum msm_camera_type camera_type;
+	enum msm_sensor_type sensor_type;
 	struct msm_actuator_info *actuator_info;
 	int pmic_gpio_enable;
 };
@@ -340,6 +358,7 @@
 struct msm_panel_common_pdata {
 	uintptr_t hw_revision_addr;
 	int gpio;
+	bool bl_lock;
 	int (*backlight_level)(int level, int max, int min);
 	int (*pmic_backlight)(int level);
 	int (*panel_num)(void);
@@ -356,6 +375,7 @@
 	u32 ov0_wb_size;  /* overlay0 writeback size */
 	u32 ov1_wb_size;  /* overlay1 writeback size */
 	u32 mem_hid;
+	char cont_splash_enabled;
 };
 
 
@@ -367,6 +387,7 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *bus_scale_table;
 #endif
+	int (*lvds_pixel_remap)(void);
 };
 
 struct tvenc_platform_data {
@@ -411,16 +432,21 @@
 	int *gpio;
 	struct mipi_dsi_phy_ctrl *phy_ctrl_settings;
 	char dlane_swap;
+	void (*dsi_pwm_cfg)(void);
+	char enable_wled_bl_ctrl;
 };
 
 struct lvds_panel_platform_data {
 	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 {
@@ -476,6 +502,7 @@
 #endif
 void msm_add_devices(void);
 void msm_copper_add_devices(void);
+void msm_copper_add_drivers(void);
 void msm_map_common_io(void);
 void msm_map_qsd8x50_io(void);
 void msm_map_msm8x60_io(void);
@@ -496,6 +523,7 @@
 int msm_add_sdcc(unsigned int controller,
 		struct mmc_platform_data *plat);
 
+void msm_pm_register_irqs(void);
 struct msm_usb_host_platform_data;
 int msm_add_host(unsigned int host,
 		struct msm_usb_host_platform_data *plat);
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index ef7be45..ba038cb 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -192,6 +192,7 @@
 struct msm_camera_csiphy_params {
 	uint8_t lane_cnt;
 	uint8_t settle_cnt;
+	uint8_t lane_mask;
 };
 
 struct msm_camera_csi2_params {
@@ -492,8 +493,6 @@
 	unsigned long len;
 	struct file *file;
 	struct msm_pmem_info info;
-	struct msm_mapped_buffer *msm_buffer;
-	int subsys_id;
 	struct ion_handle *handle;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
index 37b8d00..d1561f4 100644
--- a/arch/arm/mach-msm/include/mach/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -15,7 +15,7 @@
 #define __ARCH_ARM_MACH_MSM_CPUIDLE_H
 
 #include <linux/notifier.h>
-#include "pm.h"
+#include "../../pm.h"
 
 struct msm_cpuidle_state {
 	unsigned int cpu;
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/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index d5a2ed4..994150f 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -41,6 +41,7 @@
 struct msm_iommu_dev {
 	const char *name;
 	int ncb;
+	int ttbr_split;
 };
 
 /**
@@ -74,6 +75,7 @@
 	void __iomem *base;
 	int irq;
 	int ncb;
+	int ttbr_split;
 	struct clk *clk;
 	struct clk *pclk;
 	const char *name;
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 2d2d2fb..c17795a 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.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
@@ -14,14 +14,16 @@
 #define _ARCH_IOMMU_DOMAINS_H
 
 enum {
-	GLOBAL_DOMAIN,
+	VIDEO_DOMAIN,
+	CAMERA_DOMAIN,
+	DISPLAY_DOMAIN,
+	ROTATOR_DOMAIN,
 	MAX_DOMAINS
 };
 
 enum {
 	VIDEO_FIRMWARE_POOL,
 	VIDEO_MAIN_POOL,
-	VIDEO_MFC_POOL,
 	GEN_POOL,
 };
 
diff --git a/arch/arm/mach-msm/include/mach/irqs-8930.h b/arch/arm/mach-msm/include/mach/irqs-8930.h
index ed927bd..bfc32f6 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8930.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8930.h
@@ -152,10 +152,10 @@
 #define SPS_MTI_2				(GIC_SPI_START + 109)
 #define SPS_MTI_3				(GIC_SPI_START + 110)
 #define GPS_PPS_OUT				(GIC_SPI_START + 111)
-#define SPS_MTI_5				(GIC_SPI_START + 112)
-#define SPS_MTI_6				(GIC_SPI_START + 113)
-#define SPS_MTI_7				(GIC_SPI_START + 114)
-#define SPS_MTI_8				(GIC_SPI_START + 115)
+/* SPI IRQ 112 is unused */
+/* SPI IRQ 113 is unused */
+/* SPI IRQ 114 is unused */
+/* SPI IRQ 115 is unused */
 #define TLMM_MSM_DIR_CONN_IRQ_11		(GIC_SPI_START + 116)
 #define TLMM_MSM_DIR_CONN_IRQ_10		(GIC_SPI_START + 117)
 #define BAM_DMA1				(GIC_SPI_START + 118)
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
index cd8f2a3..39058a6 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9615.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.h
@@ -21,6 +21,7 @@
  * 32+:   SPI (shared peripheral interrupts)
  */
 
+#define FIQ_START     16
 #define GIC_PPI_START 16
 #define GIC_SPI_START 32
 
@@ -185,7 +186,9 @@
 #define NR_MSM_IRQS 288
 #define NR_GPIO_IRQS 88
 #define NR_PM8018_IRQS 256
-#define NR_BOARD_IRQS NR_PM8018_IRQS
+#define NR_WCD9XXX_IRQS 49
+#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
+#define NR_BOARD_IRQS (NR_PM8018_IRQS + NR_WCD9XXX_IRQS)
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 
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/irqs-fsm9xxx.h b/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h
index a0ec244..721db1d 100644
--- a/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h
+++ b/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.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
@@ -86,6 +86,7 @@
 #define INT_ADSP_A11		INT_Q6_SW_IRQ_0
 #define INT_ADSP_A11_SMSM	INT_ADSP_A11
 #define INT_SIRC_0		INT_PERPH_SUPSS_IRQ
+#define WDT0_ACCSCSSNBARK_INT	INT_WDT0_ACCSCSSBARK
 
 #define NR_MSM_IRQS		128
 #define NR_GPIO_IRQS		0
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 954b673..dcbabfa 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -42,10 +42,11 @@
 #define NR_GPIO_IRQS 152
 #define NR_PM8921_IRQS 256
 #define NR_PM8821_IRQS 64
-#define NR_TABLA_IRQS 49
-#define NR_GPIO_EXPANDER_IRQS 8
+#define NR_WCD9XXX_IRQS 49
+#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
+#define NR_GPIO_EXPANDER_IRQS 16
 #define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
-		NR_TABLA_IRQS + NR_GPIO_EXPANDER_IRQS)
+		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 
diff --git a/arch/arm/mach-msm/include/mach/msm_adsp.h b/arch/arm/mach-msm/include/mach/msm_adsp.h
index bbae6c1..e40c07d 100644
--- a/arch/arm/mach-msm/include/mach/msm_adsp.h
+++ b/arch/arm/mach-msm/include/mach/msm_adsp.h
@@ -1,7 +1,7 @@
 /* include/asm-arm/arch-msm/msm_adsp.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -52,6 +52,14 @@
 		   unsigned queue_id,
 		   void *data, size_t len);
 
+/*Explicitly gererate adsp event */
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg);
+
 #define ADSP_MESSAGE_ID 0xFFFF
 
 /* Command Queue Indexes */
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index fd61c98..f62bc86 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -72,6 +72,13 @@
 
 extern struct msm_bus_fabric_registration msm_bus_9615_sys_fabric_pdata;
 extern struct msm_bus_fabric_registration msm_bus_9615_def_fab_pdata;
+
+extern struct msm_bus_fabric_registration msm_bus_8930_apps_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_sys_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_mm_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_sys_fpb_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_cpss_fpb_pdata;
+
 void msm_bus_rpm_set_mt_mask(void);
 int msm_bus_board_rpm_get_il_ids(uint16_t *id);
 int msm_bus_board_get_iid(int id);
diff --git a/arch/arm/mach-msm/include/mach/msm_cache_dump.h b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
new file mode 100644
index 0000000..6e4f628
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
@@ -0,0 +1,72 @@
+/*
+ * 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 _MACH_MSM_CACHE_DUMP_
+#define _MACH_MSM_CACHE_DUMP_
+
+#include <asm-generic/sizes.h>
+
+
+struct l2_cache_line_dump {
+	unsigned int l2dcrtr0_val;
+	unsigned int l2dcrtr1_val;
+	unsigned int cache_line_data[32];
+	unsigned int ddr_data[32];
+} __packed;
+
+struct l2_cache_dump {
+	unsigned int magic_number;
+	unsigned int version;
+	unsigned int tag_size;
+	unsigned int line_size;
+	unsigned int total_lines;
+	struct l2_cache_line_dump cache[8*1024];
+	unsigned int l2esr;
+} __packed;
+
+
+struct l1_cache_dump {
+	unsigned int magic;
+	unsigned int version;
+	unsigned int flags;
+	unsigned int cpu_count;
+	unsigned int i_tag_size;
+	unsigned int i_line_size;
+	unsigned int i_num_sets;
+	unsigned int i_num_ways;
+	unsigned int d_tag_size;
+	unsigned int d_line_size;
+	unsigned int d_num_sets;
+	unsigned int d_num_ways;
+	unsigned int spare[32];
+	unsigned int lines[];
+} __packed;
+
+
+struct msm_cache_dump_platform_data {
+	unsigned int l1_size;
+	unsigned int l2_size;
+};
+
+#define L1_BUFFER_SIZE	SZ_1M
+#define L2_BUFFER_SIZE	SZ_4M
+
+#define CACHE_BUFFER_DUMP_SIZE (L1_BUFFER_SIZE + L2_BUFFER_SIZE)
+
+#define L1C_SERVICE_ID 3
+#define L1C_BUFFER_SET_COMMAND_ID 4
+#define CACHE_BUFFER_DUMP_COMMAND_ID 5
+#define L1C_BUFFER_GET_SIZE_COMMAND_ID	6
+#define L2C_BUFFER_SET_COMMAND_ID 7
+#define L2C_BUFFER_GET_SIZE_COMMAND_ID 8
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
new file mode 100644
index 0000000..fa7e6f0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -0,0 +1,150 @@
+/* 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 _ARCH_ARM_MACH_MSM_MSM_DCVS_H
+#define _ARCH_ARM_MACH_MSM_MSM_DCVS_H
+
+#include <mach/msm_dcvs_scm.h>
+
+#define CORE_NAME_MAX (32)
+#define CORES_MAX (10)
+
+enum msm_core_idle_state {
+	MSM_DCVS_IDLE_ENTER,
+	MSM_DCVS_IDLE_EXIT,
+};
+
+enum msm_core_control_event {
+	MSM_DCVS_ENABLE_IDLE_PULSE,
+	MSM_DCVS_DISABLE_IDLE_PULSE,
+	MSM_DCVS_ENABLE_HIGH_LATENCY_MODES,
+	MSM_DCVS_DISABLE_HIGH_LATENCY_MODES,
+};
+
+/**
+ * struct msm_dcvs_idle
+ *
+ * API for idle code to register and send idle enter/exit
+ * notifications to msm_dcvs driver.
+ */
+struct msm_dcvs_idle {
+	const char *core_name;
+	/* Enable/Disable idle state/notifications */
+	int (*enable)(struct msm_dcvs_idle *self,
+			enum msm_core_control_event event);
+};
+
+/**
+ * msm_dcvs_idle_source_register
+ * @drv: Pointer to the source driver
+ * @return: Handle to be used for sending idle state notifications.
+ *
+ * Register the idle driver with the msm_dcvs driver to send idle
+ * state notifications for the core.
+ */
+extern int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv);
+
+/**
+ * msm_dcvs_idle_source_unregister
+ * @drv: Pointer to the source driver
+ * @return:
+ *	0 on success
+ *	-EINVAL
+ *
+ * Description: Unregister the idle driver with the msm_dcvs driver
+ */
+extern int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv);
+
+/**
+ * msm_dcvs_idle
+ * @handle: Handle provided back at registration
+ * @state: The enter/exit idle state the core is in
+ * @iowaited: iowait in us
+ * on iMSM_DCVS_IDLE_EXIT.
+ * @return:
+ *	0 on success,
+ *	-ENOSYS,
+ *	-EINVAL,
+ *	SCM return values
+ *
+ * Send idle state notifications to the msm_dcvs driver
+ */
+int msm_dcvs_idle(int handle, enum msm_core_idle_state state,
+		uint32_t iowaited);
+
+/**
+ * struct msm_dcvs_core_info
+ *
+ * Core specific information used by algorithm. Need to provide this
+ * before the sink driver can be registered.
+ */
+struct msm_dcvs_core_info {
+	struct msm_dcvs_freq_entry *freq_tbl;
+	struct msm_dcvs_core_param core_param;
+	struct msm_dcvs_algo_param algo_param;
+};
+
+/**
+ * msm_dcvs_register_core
+ * @core_name: Unique name identifier for the core.
+ * @group_id: Cores that are to be grouped for synchronized frequency scaling
+ * @info: The core specific algorithm parameters.
+ * @return :
+ *	0 on success,
+ *	-ENOSYS,
+ *	-ENOMEM
+ *
+ * Register the core with msm_dcvs driver. Done once at init before calling
+ * msm_dcvs_freq_sink_register
+ * Cores that need to run synchronously must share the same group id.
+ * If a core doesnt care to be in any group, the group_id should be 0.
+ */
+extern int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
+		struct msm_dcvs_core_info *info);
+
+/**
+ * struct msm_dcvs_freq
+ *
+ * API for clock driver code to register and receive frequency change
+ * request for the core from the msm_dcvs driver.
+ */
+struct msm_dcvs_freq {
+	const char *core_name;
+	/* Callback from msm_dcvs to set the core frequency */
+	int (*set_frequency)(struct msm_dcvs_freq *self,
+			unsigned int freq);
+	unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
+};
+
+/**
+ * msm_dcvs_freq_sink_register
+ * @drv: The sink driver
+ * @return: Handle unique to the core.
+ *
+ * Register the clock driver code with the msm_dvs driver to get notified about
+ * frequency change requests.
+ */
+extern int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv);
+
+/**
+ * msm_dcvs_freq_sink_unregister
+ * @drv: The sink driver
+ * @return:
+ *	0 on success,
+ *	-EINVAL
+ *
+ * Unregister the sink driver for the core. This will cause the source driver
+ * for the core to stop sending idle pulses.
+ */
+extern int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
new file mode 100644
index 0000000..c07de44
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
@@ -0,0 +1,168 @@
+/* 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 _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
+#define _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
+
+enum msm_dcvs_scm_event {
+	MSM_DCVS_SCM_IDLE_ENTER,
+	MSM_DCVS_SCM_IDLE_EXIT,
+	MSM_DCVS_SCM_QOS_TIMER_EXPIRED,
+	MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
+	MSM_DCVS_SCM_ENABLE_CORE,
+	MSM_DCVS_SCM_RESET_CORE,
+};
+
+struct msm_dcvs_algo_param {
+	uint32_t slack_time_us;
+	uint32_t scale_slack_time;
+	uint32_t scale_slack_time_pct;
+	uint32_t disable_pc_threshold;
+	uint32_t em_window_size;
+	uint32_t em_max_util_pct;
+	uint32_t ss_window_size;
+	uint32_t ss_util_pct;
+	uint32_t ss_iobusy_conv;
+};
+
+struct msm_dcvs_freq_entry {
+	uint32_t freq; /* Core freq in MHz */
+	uint32_t idle_energy;
+	uint32_t active_energy;
+};
+
+struct msm_dcvs_core_param {
+	uint32_t max_time_us;
+	uint32_t num_freq; /* number of msm_dcvs_freq_entry passed */
+};
+
+
+#ifdef CONFIG_MSM_DCVS
+/**
+ * Initialize DCVS algorithm in TrustZone.
+ * Must call before invoking any other DCVS call into TZ.
+ *
+ * @size: Size of buffer in bytes
+ *
+ * @return:
+ *	0 on success.
+ *	-EEXIST: DCVS algorithm already initialized.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_init(size_t size);
+
+/**
+ * Create an empty core group
+ *
+ * @return:
+ *	0 on success.
+ *	-ENOMEM: Insufficient memory.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_create_group(uint32_t id);
+
+/**
+ * Registers cores as part of a group
+ *
+ * @core_id: The core identifier that will be used for communication with DCVS
+ * @group_id: The group to which this core will be added to.
+ * @param: The core parameters
+ * @freq: Array of frequency and energy values
+ *
+ * @return:
+ *	0 on success.
+ *	-ENOMEM: Insufficient memory.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
+		struct msm_dcvs_core_param *param,
+		struct msm_dcvs_freq_entry *freq);
+
+/**
+ * Set DCVS algorithm parameters
+ *
+ * @core_id: The algorithm parameters specific for the core
+ * @param: The param data structure
+ *
+ * @return:
+ *	0 on success.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_set_algo_params(uint32_t core_id,
+		struct msm_dcvs_algo_param *param);
+
+/**
+ * Do an SCM call.
+ *
+ * @core_id: The core identifier.
+ * @event_id: The event that occured.
+ *	Possible values:
+ *	MSM_DCVS_SCM_IDLE_ENTER
+ *		@param0: unused
+ *		@param1: unused
+ *		@ret0: unused
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_IDLE_EXIT
+ *		@param0: Did the core iowait
+ *		@param1: unused
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_QOS_TIMER_EXPIRED
+ *		@param0: unused
+ *		@param1: unused
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_CLOCK_FREQ_UPDATE
+ *		@param0: active clock frequency of the core in KHz
+ *		@param1: time taken in usec to switch to the frequency
+ *		@ret0: New QoS timer value for the core in usec
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_ENABLE_CORE
+ *		@param0: enable(1) or disable(0) core
+ *		@param1: active clock frequency of the core in KHz
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_RESET_CORE
+ *		@param0: active clock frequency of the core in KHz
+ *		@param1: unused
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: unused
+ * @return:
+ *	0 on success,
+ *	SCM return values
+ */
+extern int msm_dcvs_scm_event(uint32_t core_id,
+		enum msm_dcvs_scm_event event_id,
+		uint32_t param0, uint32_t param1,
+		uint32_t *ret0, uint32_t *ret1);
+
+#else
+static inline int msm_dcvs_scm_init(uint32_t phy, size_t bytes)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_create_group(uint32_t id)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_register_core(uint32_t core_id,
+		uint32_t group_id,
+		struct msm_dcvs_core_param *param,
+		struct msm_dcvs_freq_entry *freq)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_set_algo_params(uint32_t core_id,
+		struct msm_dcvs_algo_param *param)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_event(uint32_t core_id,
+		enum msm_dcvs_scm_event event_id,
+		uint32_t param0, uint32_t param1,
+		uint32_t *ret0, uint32_t *ret1)
+{ return -ENOSYS; }
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_fb.h b/arch/arm/mach-msm/include/mach/msm_fb.h
index 339fa46..3bbaa25 100644
--- a/arch/arm/mach-msm/include/mach/msm_fb.h
+++ b/arch/arm/mach-msm/include/mach/msm_fb.h
@@ -188,5 +188,11 @@
 };
 
 
+struct mdp_v4l2_req;
+int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par);
+int msm_fb_v4l2_update(void *par,
+	unsigned long srcp0_addr, unsigned long srcp0_size,
+	unsigned long srcp1_addr, unsigned long srcp1_size,
+	unsigned long srcp2_addr, unsigned long srcp2_size);
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
index acd668b..10b3374 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -35,68 +35,52 @@
  *
  */
 
-#define MSM_VIC_BASE          IOMEM(0xFA000000)
-#define MSM_VIC_PHYS          0xC0080000
-#define MSM_VIC_SIZE          SZ_4K
+#define MSM7X30_VIC_PHYS		0xC0080000
+#define MSM7X30_VIC_SIZE		SZ_4K
 
-#define MSM_CSR_BASE          IOMEM(0xFA001000)
-#define MSM_CSR_PHYS          0xC0100000
-#define MSM_CSR_SIZE          SZ_4K
+#define MSM7X30_CSR_PHYS		0xC0100000
+#define MSM7X30_CSR_SIZE		SZ_4K
 
-#define MSM_TMR_PHYS          MSM_CSR_PHYS
-#define MSM_TMR_BASE          MSM_CSR_BASE
-#define MSM_TMR_SIZE          SZ_4K
+#define MSM7X30_TMR_PHYS		MSM7X30_CSR_PHYS
+#define MSM7X30_TMR_SIZE		SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xFA003000)
-#define MSM_GPIO1_PHYS        0xAC001000
-#define MSM_GPIO1_SIZE        SZ_4K
+#define MSM7X30_GPIO1_PHYS		0xAC001000
+#define MSM7X30_GPIO1_SIZE		SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xFA004000)
-#define MSM_GPIO2_PHYS        0xAC101000
-#define MSM_GPIO2_SIZE        SZ_4K
+#define MSM7X30_GPIO2_PHYS		0xAC101000
+#define MSM7X30_GPIO2_SIZE		SZ_4K
 
-#define MSM_CLK_CTL_BASE      IOMEM(0xFA005000)
-#define MSM_CLK_CTL_PHYS      0xAB800000
-#define MSM_CLK_CTL_SIZE      SZ_4K
+#define MSM7X30_CLK_CTL_PHYS		0xAB800000
+#define MSM7X30_CLK_CTL_SIZE		SZ_4K
 
-#define MSM_CLK_CTL_SH2_BASE  IOMEM(0xFA006000)
-#define MSM_CLK_CTL_SH2_PHYS  0xABA01000
-#define MSM_CLK_CTL_SH2_SIZE  SZ_4K
+#define MSM7X30_CLK_CTL_SH2_PHYS	0xABA01000
+#define MSM7X30_CLK_CTL_SH2_SIZE	SZ_4K
 
-#define MSM_ACC_BASE          IOMEM(0xFA007000)
-#define MSM_ACC_PHYS          0xC0101000
-#define MSM_ACC_SIZE          SZ_4K
+#define MSM7X30_ACC0_PHYS		0xC0101000
+#define MSM7X30_ACC0_SIZE		SZ_4K
 
-#define MSM_SAW_BASE          IOMEM(0xFA008000)
-#define MSM_SAW_PHYS          0xC0102000
-#define MSM_SAW_SIZE          SZ_4K
+#define MSM7X30_SAW0_PHYS		0xC0102000
+#define MSM7X30_SAW0_SIZE		SZ_4K
 
-#define MSM_GCC_BASE	      IOMEM(0xFA009000)
-#define MSM_GCC_PHYS	      0xC0182000
-#define MSM_GCC_SIZE	      SZ_4K
+#define MSM7X30_APCS_GCC_PHYS		0xC0182000
+#define MSM7X30_APCS_GCC_SIZE		SZ_4K
 
-#define MSM_TCSR_BASE	      IOMEM(0xFA00A000)
-#define MSM_TCSR_PHYS	      0xAB600000
-#define MSM_TCSR_SIZE	      SZ_4K
+#define MSM7X30_TCSR_PHYS		0xAB600000
+#define MSM7X30_TCSR_SIZE		SZ_4K
 
-#define MSM_SHARED_RAM_BASE   IOMEM(0xFA100000)
-#define MSM_SHARED_RAM_SIZE   SZ_1M
+#define MSM7X30_UART1_PHYS		0xACA00000
+#define MSM7X30_UART1_SIZE		SZ_4K
 
-#define MSM_UART1_PHYS        0xACA00000
-#define MSM_UART1_SIZE        SZ_4K
+#define MSM7X30_UART2_PHYS		0xACB00000
+#define MSM7X30_UART2_SIZE		SZ_4K
 
-#define MSM_UART2_PHYS        0xACB00000
-#define MSM_UART2_SIZE        SZ_4K
+#define MSM7X30_UART3_PHYS		0xACC00000
+#define MSM7X30_UART3_SIZE		SZ_4K
 
-#define MSM_UART3_PHYS        0xACC00000
-#define MSM_UART3_SIZE        SZ_4K
+#define MSM7X30_MDC_PHYS		0xAA500000
+#define MSM7X30_MDC_SIZE		SZ_1M
 
-#define MSM_MDC_BASE	      IOMEM(0xFA200000)
-#define MSM_MDC_PHYS	      0xAA500000
-#define MSM_MDC_SIZE	      SZ_1M
-
-#define MSM_AD5_BASE          IOMEM(0xFA300000)
-#define MSM_AD5_PHYS          0xA7000000
-#define MSM_AD5_SIZE          (SZ_1M*13)
+#define MSM7X30_AD5_PHYS		0xA7000000
+#define MSM7X30_AD5_SIZE		(SZ_1M*13)
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8064.h b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
index 7479712..96bc35e 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
@@ -103,4 +103,7 @@
 #define APQ8064_SIC_NON_SECURE_PHYS	0x12100000
 #define APQ8064_SIC_NON_SECURE_SIZE	SZ_64K
 
+#define APQ8064_HDMI_PHYS		0x04A00000
+#define APQ8064_HDMI_SIZE		SZ_4K
+
 #endif
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_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 27965d3..34af610 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -45,11 +45,20 @@
 
 #define MSM_DEBUG_UART_SIZE	SZ_4K
 
+#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) \
+				|| defined(CONFIG_DEBUG_MSM_UART3)
+#define MSM_DEBUG_UART_BASE	0xFC000000
+#define MSM_DEBUG_UART_PHYS	CONFIG_MSM_DEBUG_UART_PHYS
+#endif
+
+#define MSM8625_WARM_BOOT_PHYS  0x0FD00000
+
+
 #if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
 	defined(CONFIG_ARCH_MSM8930) || defined(CONFIG_ARCH_MSM9615) || \
 	defined(CONFIG_ARCH_MSMCOPPER) || defined(CONFIG_ARCH_MSM7X27) || \
 	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
-	defined(CONFIG_ARCH_MSM8625)
+	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30)
 
 /* Unified iomap */
 
@@ -88,6 +97,7 @@
 #define MSM_GPIO2_BASE		IOMEM(0xFA103000)	/*  4K */
 #define MSM_SCU_BASE		IOMEM(0xFA104000)	/*  4K */
 #define MSM_CFG_CTL_BASE	IOMEM(0xFA105000)	/*  4K */
+#define MSM_CLK_CTL_SH2_BASE	IOMEM(0xFA106000)	/*  4K */
 #define MSM_MDC_BASE		IOMEM(0xFA400000)	/*  1M */
 #define MSM_AD5_BASE		IOMEM(0xFA900000)	/*  13M (D00000)
 							  0xFB600000 */
@@ -96,13 +106,15 @@
 #define MSM8625_SECONDARY_PHYS		0x0FE00000
 
 
-#if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27)
+#if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
+	|| defined(CONFIG_ARCH_MSM7X30)
 #define MSM_SHARED_RAM_SIZE	SZ_1M
 #else
 #define MSM_SHARED_RAM_SIZE	SZ_2M
 #endif
 
 #include "msm_iomap-7xxx.h"
+#include "msm_iomap-7x30.h"
 #include "msm_iomap-8625.h"
 #include "msm_iomap-8960.h"
 #include "msm_iomap-8930.h"
@@ -112,10 +124,7 @@
 
 #else
 /* Legacy single-target iomap */
-
-#if defined(CONFIG_ARCH_MSM7X30)
-#include "msm_iomap-7x30.h"
-#elif defined(CONFIG_ARCH_QSD8X50)
+#if defined(CONFIG_ARCH_QSD8X50)
 #include "msm_iomap-8x50.h"
 #elif defined(CONFIG_ARCH_MSM8X60)
 #include "msm_iomap-8x60.h"
@@ -125,17 +134,6 @@
 #error "Target compiled without IO map\n"
 #endif
 
-#if defined(CONFIG_DEBUG_MSM_UART1)
-#define MSM_DEBUG_UART_BASE	0xFB000000
-#define MSM_DEBUG_UART_PHYS	MSM_UART1_PHYS
-#elif defined(CONFIG_DEBUG_MSM_UART2)
-#define MSM_DEBUG_UART_BASE	0xFB000000
-#define MSM_DEBUG_UART_PHYS	MSM_UART2_PHYS
-#elif defined(CONFIG_DEBUG_MSM_UART3)
-#define MSM_DEBUG_UART_BASE	0xFB000000
-#define MSM_DEBUG_UART_PHYS	MSM_UART3_PHYS
-#endif
-
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
index a75ab91..5eea63f 100644
--- a/arch/arm/mach-msm/include/mach/msm_rtb.h
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -13,13 +13,18 @@
 #ifndef __MSM_RTB_H__
 #define __MSM_RTB_H__
 
+/*
+ * These numbers are used from the kernel command line and sysfs
+ * to control filtering. Remove items from here with extreme caution
+ */
 enum logk_event_type {
 	LOGK_NONE = 0,
-	LOGK_READL,
-	LOGK_WRITEL,
-	LOGK_LOGBUF,
-	LOGK_HOTPLUG,
-	LOGK_OTHER,
+	LOGK_READL = 1,
+	LOGK_WRITEL = 2,
+	LOGK_LOGBUF = 3,
+	LOGK_HOTPLUG = 4,
+	LOGK_CTXID = 5,
+	LOGK_OTHER = 31,
 };
 
 struct msm_rtb_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
index e2bdaea..577a097 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
@@ -18,6 +18,7 @@
 	unsigned config_gpio;
 	unsigned uart_tx_gpio;
 	unsigned uart_rx_gpio;
+	int line;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 4be6d9ea..d896013 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -46,6 +46,7 @@
 	SMD_WCNSS = SMSM_WCNSS,
 	SMD_DSPS = SMSM_DSPS,
 	SMD_MODEM_Q6_FW,
+	SMD_RPM,
 	NUM_SMD_SUBSYSTEMS,
 };
 
@@ -65,6 +66,10 @@
 	SMD_QDSP_Q6FW,
 	SMD_DSPS_Q6FW,
 	SMD_WCNSS_Q6FW,
+	SMD_APPS_RPM,
+	SMD_MODEM_RPM,
+	SMD_QDSP_RPM,
+	SMD_WCNSS_RPM,
 	SMD_NUM_TYPE,
 	SMD_LOOPBACK_TYPE = 100,
 
@@ -118,9 +123,19 @@
 
 };
 
+/*
+ * Subsystem Restart Configuration
+ *
+ * @disable_smsm_reset_handshake
+ */
+struct smd_subsystem_restart_config {
+	int disable_smsm_reset_handshake;
+};
+
 struct smd_platform {
 	uint32_t num_ss_configs;
 	struct smd_subsystem_config *smd_ss_configs;
+	struct smd_subsystem_restart_config *smd_ssr_config;
 };
 
 #ifdef CONFIG_MSM_SMD
@@ -236,6 +251,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 +368,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/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 6d45b7d..772c9f6 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.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
@@ -13,6 +13,7 @@
 #ifndef _ARCH_ARM_MACH_MSM_SMSM_H_
 #define _ARCH_ARM_MACH_MSM_SMSM_H_
 
+#include <linux/notifier.h>
 #if defined(CONFIG_MSM_N_WAY_SMSM)
 enum {
 	SMSM_APPS_STATE,
@@ -108,6 +109,8 @@
 	void *data);
 int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
 	void (*notify)(void *, uint32_t, uint32_t), void *data);
+int smsm_driver_state_notifier_register(struct notifier_block *nb);
+int smsm_driver_state_notifier_unregister(struct notifier_block *nb);
 void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
 	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
 void smsm_reset_modem(unsigned mode);
diff --git a/arch/arm/mach-msm/include/mach/msm_xo.h b/arch/arm/mach-msm/include/mach/msm_xo.h
index 7760647..f9795b4 100644
--- a/arch/arm/mach-msm/include/mach/msm_xo.h
+++ b/arch/arm/mach-msm/include/mach/msm_xo.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
@@ -19,8 +19,6 @@
 	MSM_XO_TCXO_A1,
 	MSM_XO_TCXO_A2,
 	MSM_XO_CORE,
-	MSM_XO_PXO,
-	MSM_XO_CXO,
 	NUM_MSM_XO_IDS
 };
 
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
index c580774..86216d4 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
@@ -15,7 +15,7 @@
 EXTERNALIZED FUNCTIONS
   None
 
-Copyright (c) 1992-2009, Code Aurora Forum. All rights reserved.
+Copyright(c) 1992-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
@@ -958,6 +958,12 @@
 #define AUDPP_CMD_CMD_TYPE_OBJ		0x0015
 #define AUDPP_CMD_CMD_TYPE_QUERY	0x1000
 
+#define SRS_PARAMS_MAX_G 8
+#define SRS_PARAMS_MAX_W 55
+#define SRS_PARAMS_MAX_C 51
+#define SRS_PARAMS_MAX_H 53
+#define SRS_PARAMS_MAX_P 116
+#define SRS_PARAMS_MAX_L 8
 
 typedef struct {
 	unsigned short			cmd_id;
@@ -999,6 +1005,33 @@
 	unsigned short			absolute_gain;
 } __attribute__((packed)) audpp_cmd_reverb_config_env_15;
 
+/*
+ * Command Structure to configure post processing params (SRS TruMedia)
+ */
+struct audpp_cmd_cfg_object_params_srstm_g {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_G];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_w {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_W];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_c {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_C];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_h {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_H];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_p {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_P];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_l {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_L];
+} __packed;
 
 #endif /* QDSP5AUDPPCMDI_H */
 
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/qdss.h b/arch/arm/mach-msm/include/mach/qdss.h
new file mode 100644
index 0000000..3b236b8
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdss.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.
+ */
+
+#ifndef __MACH_QDSS_H
+#define __MACH_QDSS_H
+
+struct qdss_source {
+	struct list_head link;
+	const char *name;
+	uint32_t fport_mask;
+};
+
+struct msm_qdss_platform_data {
+	struct qdss_source *src_table;
+	size_t size;
+	uint8_t afamily;
+};
+
+#ifdef CONFIG_MSM_QDSS
+extern struct qdss_source *qdss_get(const char *name);
+extern void qdss_put(struct qdss_source *src);
+extern int qdss_enable(struct qdss_source *src);
+extern void qdss_disable(struct qdss_source *src);
+extern int qdss_clk_enable(void);
+extern void qdss_clk_disable(void);
+#else
+static inline struct qdss_source *qdss_get(const char *name) { return NULL; }
+static inline void qdss_put(struct qdss_source *src) {}
+static inline int qdss_enable(struct qdss_source *src) { return -ENOSYS; }
+static inline void qdss_disable(struct qdss_source *src) {}
+static inline int qdss_clk_enable(void) { return -ENOSYS; }
+static inline void qdss_clk_disable(void) {}
+#endif
+
+#ifdef CONFIG_MSM_JTAG
+extern void msm_jtag_save_state(void);
+extern void msm_jtag_restore_state(void);
+#else
+static inline void msm_jtag_save_state(void) {}
+static inline void msm_jtag_restore_state(void) {}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qpnp.h b/arch/arm/mach-msm/include/mach/qpnp.h
new file mode 100644
index 0000000..1d2e440
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qpnp.h
@@ -0,0 +1,19 @@
+ /* 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/spmi.h>
+
+struct resource *qpnp_get_resource(struct spmi_device *dev,
+				   unsigned int node_idx, unsigned int type,
+				   unsigned int res_num);
+int qpnp_get_irq(struct spmi_device *dev, unsigned int node_idx,
+					  unsigned int res_num);
diff --git a/arch/arm/mach-msm/include/mach/rpc_hsusb.h b/arch/arm/mach-msm/include/mach/rpc_hsusb.h
index 2255237..88d7650 100644
--- a/arch/arm/mach-msm/include/mach/rpc_hsusb.h
+++ b/arch/arm/mach-msm/include/mach/rpc_hsusb.h
@@ -1,6 +1,6 @@
 /* linux/include/mach/rpc_hsusb.h
  *
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -42,7 +42,7 @@
 int msm_chg_usb_charger_disconnected(void);
 int msm_chg_rpc_close(void);
 
-#ifdef CONFIG_USB_GADGET_MSM_72K
+#ifdef CONFIG_USB_MSM_72K
 int hsusb_chg_init(int connect);
 void hsusb_chg_vbus_draw(unsigned mA);
 void hsusb_chg_connected(enum chg_type chgtype);
@@ -78,7 +78,7 @@
 static inline int msm_chg_usb_charger_disconnected(void) { return 0; }
 static inline int msm_chg_rpc_close(void) { return 0; }
 
-#ifdef CONFIG_USB_GADGET_MSM_72K
+#ifdef CONFIG_USB_MSM_72K
 static inline int hsusb_chg_init(int connect) { return 0; }
 static inline void hsusb_chg_vbus_draw(unsigned mA) { }
 static inline void hsusb_chg_connected(enum chg_type chgtype) { }
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 04218b2..0211b67 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -100,7 +100,8 @@
 	MSM_RPM_8930_SEL_CXO_BUFFERS				= 81,
 	MSM_RPM_8930_SEL_USB_OTG_SWITCH				= 82,
 	MSM_RPM_8930_SEL_HDMI_SWITCH				= 83,
-	MSM_RPM_8930_SEL_LAST = MSM_RPM_8930_SEL_HDMI_SWITCH,
+	MSM_RPM_8930_SEL_VOLTAGE_CORNER				= 87,
+	MSM_RPM_8930_SEL_LAST = MSM_RPM_8930_SEL_VOLTAGE_CORNER,
 };
 
 /* RPM resource (4 byte) word ID enum */
@@ -140,106 +141,107 @@
 	MSM_RPM_8930_ID_APPS_FABRIC_CFG_CLKMOD_2		= 39,
 	MSM_RPM_8930_ID_APPS_FABRIC_CFG_IOCTL			= 40,
 	MSM_RPM_8930_ID_APPS_FABRIC_ARB_0			= 41,
-	MSM_RPM_8930_ID_APPS_FABRIC_ARB_11 =
-		MSM_RPM_8930_ID_APPS_FABRIC_ARB_0 + 11,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_0			= 53,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_1			= 54,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_0			= 55,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_1			= 56,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_2			= 57,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_IOCTL			= 58,
-	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0			= 59,
-	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_28 =
-		MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0 + 28,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_0			= 88,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_1			= 89,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_0		= 90,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_1		= 91,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_2		= 92,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_IOCTL			= 93,
-	MSM_RPM_8930_ID_MM_FABRIC_ARB_0				= 94,
-	MSM_RPM_8930_ID_MM_FABRIC_ARB_22 =
-		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 22,
+	MSM_RPM_8930_ID_APPS_FABRIC_ARB_5 =
+		MSM_RPM_8930_ID_APPS_FABRIC_ARB_0 + 5,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_0			= 47,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_1			= 48,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_0			= 49,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_1			= 50,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_2			= 51,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_IOCTL			= 52,
+	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0			= 53,
+	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_19 =
+		MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0 + 19,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_0			= 73,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_1			= 74,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_0		= 75,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_1		= 76,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_2		= 77,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_IOCTL			= 78,
+	MSM_RPM_8930_ID_MM_FABRIC_ARB_0				= 79,
+	MSM_RPM_8930_ID_MM_FABRIC_ARB_10 =
+		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 10,
 
-	MSM_RPM_8930_ID_PM8038_S1_0				= 117,
-	MSM_RPM_8930_ID_PM8038_S1_1				= 118,
-	MSM_RPM_8930_ID_PM8038_S2_0				= 119,
-	MSM_RPM_8930_ID_PM8038_S2_1				= 120,
-	MSM_RPM_8930_ID_PM8038_S3_0				= 121,
-	MSM_RPM_8930_ID_PM8038_S3_1				= 122,
-	MSM_RPM_8930_ID_PM8038_S4_0				= 123,
-	MSM_RPM_8930_ID_PM8038_S4_1				= 124,
-	MSM_RPM_8930_ID_PM8038_S5_0				= 125,
-	MSM_RPM_8930_ID_PM8038_S5_1				= 126,
-	MSM_RPM_8930_ID_PM8038_S6_0				= 127,
-	MSM_RPM_8930_ID_PM8038_S6_1				= 128,
-	MSM_RPM_8930_ID_PM8038_L1_0				= 129,
-	MSM_RPM_8930_ID_PM8038_L1_1				= 130,
-	MSM_RPM_8930_ID_PM8038_L2_0				= 131,
-	MSM_RPM_8930_ID_PM8038_L2_1				= 132,
-	MSM_RPM_8930_ID_PM8038_L3_0				= 133,
-	MSM_RPM_8930_ID_PM8038_L3_1				= 134,
-	MSM_RPM_8930_ID_PM8038_L4_0				= 135,
-	MSM_RPM_8930_ID_PM8038_L4_1				= 136,
-	MSM_RPM_8930_ID_PM8038_L5_0				= 137,
-	MSM_RPM_8930_ID_PM8038_L5_1				= 138,
-	MSM_RPM_8930_ID_PM8038_L6_0				= 139,
-	MSM_RPM_8930_ID_PM8038_L6_1				= 140,
-	MSM_RPM_8930_ID_PM8038_L7_0				= 141,
-	MSM_RPM_8930_ID_PM8038_L7_1				= 142,
-	MSM_RPM_8930_ID_PM8038_L8_0				= 143,
-	MSM_RPM_8930_ID_PM8038_L8_1				= 144,
-	MSM_RPM_8930_ID_PM8038_L9_0				= 145,
-	MSM_RPM_8930_ID_PM8038_L9_1				= 146,
-	MSM_RPM_8930_ID_PM8038_L10_0				= 147,
-	MSM_RPM_8930_ID_PM8038_L10_1				= 148,
-	MSM_RPM_8930_ID_PM8038_L11_0				= 149,
-	MSM_RPM_8930_ID_PM8038_L11_1				= 150,
-	MSM_RPM_8930_ID_PM8038_L12_0				= 151,
-	MSM_RPM_8930_ID_PM8038_L12_1				= 152,
-	MSM_RPM_8930_ID_PM8038_L13_0				= 153,
-	MSM_RPM_8930_ID_PM8038_L13_1				= 154,
-	MSM_RPM_8930_ID_PM8038_L14_0				= 155,
-	MSM_RPM_8930_ID_PM8038_L14_1				= 156,
-	MSM_RPM_8930_ID_PM8038_L15_0				= 157,
-	MSM_RPM_8930_ID_PM8038_L15_1				= 158,
-	MSM_RPM_8930_ID_PM8038_L16_0				= 159,
-	MSM_RPM_8930_ID_PM8038_L16_1				= 160,
-	MSM_RPM_8930_ID_PM8038_L17_0				= 161,
-	MSM_RPM_8930_ID_PM8038_L17_1				= 162,
-	MSM_RPM_8930_ID_PM8038_L18_0				= 163,
-	MSM_RPM_8930_ID_PM8038_L18_1				= 164,
-	MSM_RPM_8930_ID_PM8038_L19_0				= 165,
-	MSM_RPM_8930_ID_PM8038_L19_1				= 166,
-	MSM_RPM_8930_ID_PM8038_L20_0				= 167,
-	MSM_RPM_8930_ID_PM8038_L20_1				= 168,
-	MSM_RPM_8930_ID_PM8038_L21_0				= 169,
-	MSM_RPM_8930_ID_PM8038_L21_1				= 170,
-	MSM_RPM_8930_ID_PM8038_L22_0				= 171,
-	MSM_RPM_8930_ID_PM8038_L22_1				= 172,
-	MSM_RPM_8930_ID_PM8038_L23_0				= 173,
-	MSM_RPM_8930_ID_PM8038_L23_1				= 174,
-	MSM_RPM_8930_ID_PM8038_L24_0				= 175,
-	MSM_RPM_8930_ID_PM8038_L24_1				= 176,
-	MSM_RPM_8930_ID_PM8038_L25_0				= 177,
-	MSM_RPM_8930_ID_PM8038_L25_1				= 178,
-	MSM_RPM_8930_ID_PM8038_L26_0				= 179,
-	MSM_RPM_8930_ID_PM8038_L26_1				= 180,
-	MSM_RPM_8930_ID_PM8038_L27_0				= 181,
-	MSM_RPM_8930_ID_PM8038_L27_1				= 182,
-	MSM_RPM_8930_ID_PM8038_CLK1_0				= 183,
-	MSM_RPM_8930_ID_PM8038_CLK1_1				= 184,
-	MSM_RPM_8930_ID_PM8038_CLK2_0				= 185,
-	MSM_RPM_8930_ID_PM8038_CLK2_1				= 186,
-	MSM_RPM_8930_ID_PM8038_LVS1				= 187,
-	MSM_RPM_8930_ID_PM8038_LVS2				= 188,
-	MSM_RPM_8930_ID_NCP_0					= 189,
-	MSM_RPM_8930_ID_NCP_1					= 190,
-	MSM_RPM_8930_ID_CXO_BUFFERS				= 191,
-	MSM_RPM_8930_ID_USB_OTG_SWITCH				= 192,
-	MSM_RPM_8930_ID_HDMI_SWITCH				= 193,
-	MSM_RPM_8930_ID_QDSS_CLK				= 194,
-	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_QDSS_CLK,
+	MSM_RPM_8930_ID_PM8038_S1_0	= 90,
+	MSM_RPM_8930_ID_PM8038_S1_1	= 91,
+	MSM_RPM_8930_ID_PM8038_S2_0	= 92,
+	MSM_RPM_8930_ID_PM8038_S2_1	= 93,
+	MSM_RPM_8930_ID_PM8038_S3_0	= 94,
+	MSM_RPM_8930_ID_PM8038_S3_1	= 95,
+	MSM_RPM_8930_ID_PM8038_S4_0	= 96,
+	MSM_RPM_8930_ID_PM8038_S4_1	= 97,
+	MSM_RPM_8930_ID_PM8038_S5_0	= 98,
+	MSM_RPM_8930_ID_PM8038_S5_1	= 99,
+	MSM_RPM_8930_ID_PM8038_S6_0	= 100,
+	MSM_RPM_8930_ID_PM8038_S6_1	= 101,
+	MSM_RPM_8930_ID_PM8038_L1_0	= 102,
+	MSM_RPM_8930_ID_PM8038_L1_1	= 103,
+	MSM_RPM_8930_ID_PM8038_L2_0	= 104,
+	MSM_RPM_8930_ID_PM8038_L2_1	= 105,
+	MSM_RPM_8930_ID_PM8038_L3_0	= 106,
+	MSM_RPM_8930_ID_PM8038_L3_1	= 107,
+	MSM_RPM_8930_ID_PM8038_L4_0	= 108,
+	MSM_RPM_8930_ID_PM8038_L4_1	= 109,
+	MSM_RPM_8930_ID_PM8038_L5_0	= 110,
+	MSM_RPM_8930_ID_PM8038_L5_1	= 111,
+	MSM_RPM_8930_ID_PM8038_L6_0	= 112,
+	MSM_RPM_8930_ID_PM8038_L6_1	= 113,
+	MSM_RPM_8930_ID_PM8038_L7_0	= 114,
+	MSM_RPM_8930_ID_PM8038_L7_1	= 115,
+	MSM_RPM_8930_ID_PM8038_L8_0	= 116,
+	MSM_RPM_8930_ID_PM8038_L8_1	= 117,
+	MSM_RPM_8930_ID_PM8038_L9_0	= 118,
+	MSM_RPM_8930_ID_PM8038_L9_1	= 119,
+	MSM_RPM_8930_ID_PM8038_L10_0	= 120,
+	MSM_RPM_8930_ID_PM8038_L10_1	= 121,
+	MSM_RPM_8930_ID_PM8038_L11_0	= 122,
+	MSM_RPM_8930_ID_PM8038_L11_1	= 123,
+	MSM_RPM_8930_ID_PM8038_L12_0	= 124,
+	MSM_RPM_8930_ID_PM8038_L12_1	= 125,
+	MSM_RPM_8930_ID_PM8038_L13_0	= 126,
+	MSM_RPM_8930_ID_PM8038_L13_1	= 127,
+	MSM_RPM_8930_ID_PM8038_L14_0	= 128,
+	MSM_RPM_8930_ID_PM8038_L14_1	= 129,
+	MSM_RPM_8930_ID_PM8038_L15_0	= 130,
+	MSM_RPM_8930_ID_PM8038_L15_1	= 131,
+	MSM_RPM_8930_ID_PM8038_L16_0	= 132,
+	MSM_RPM_8930_ID_PM8038_L16_1	= 133,
+	MSM_RPM_8930_ID_PM8038_L17_0	= 134,
+	MSM_RPM_8930_ID_PM8038_L17_1	= 135,
+	MSM_RPM_8930_ID_PM8038_L18_0	= 136,
+	MSM_RPM_8930_ID_PM8038_L18_1	= 137,
+	MSM_RPM_8930_ID_PM8038_L19_0	= 138,
+	MSM_RPM_8930_ID_PM8038_L19_1	= 139,
+	MSM_RPM_8930_ID_PM8038_L20_0	= 140,
+	MSM_RPM_8930_ID_PM8038_L20_1	= 141,
+	MSM_RPM_8930_ID_PM8038_L21_0	= 142,
+	MSM_RPM_8930_ID_PM8038_L21_1	= 143,
+	MSM_RPM_8930_ID_PM8038_L22_0	= 144,
+	MSM_RPM_8930_ID_PM8038_L22_1	= 145,
+	MSM_RPM_8930_ID_PM8038_L23_0	= 146,
+	MSM_RPM_8930_ID_PM8038_L23_1	= 147,
+	MSM_RPM_8930_ID_PM8038_L24_0	= 148,
+	MSM_RPM_8930_ID_PM8038_L24_1	= 149,
+	MSM_RPM_8930_ID_PM8038_L25_0	= 150,
+	MSM_RPM_8930_ID_PM8038_L25_1	= 151,
+	MSM_RPM_8930_ID_PM8038_L26_0	= 152,
+	MSM_RPM_8930_ID_PM8038_L26_1	= 153,
+	MSM_RPM_8930_ID_PM8038_L27_0	= 154,
+	MSM_RPM_8930_ID_PM8038_L27_1	= 155,
+	MSM_RPM_8930_ID_PM8038_CLK1_0	= 156,
+	MSM_RPM_8930_ID_PM8038_CLK1_1	= 157,
+	MSM_RPM_8930_ID_PM8038_CLK2_0	= 158,
+	MSM_RPM_8930_ID_PM8038_CLK2_1	= 159,
+	MSM_RPM_8930_ID_PM8038_LVS1	= 160,
+	MSM_RPM_8930_ID_PM8038_LVS2	= 161,
+	MSM_RPM_8930_ID_NCP_0	= 162,
+	MSM_RPM_8930_ID_NCP_1	= 163,
+	MSM_RPM_8930_ID_CXO_BUFFERS	= 164,
+	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 165,
+	MSM_RPM_8930_ID_HDMI_SWITCH	= 166,
+	MSM_RPM_8930_ID_QDSS_CLK	= 167,
+	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 168,
+	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
 };
 
 /* RPM status ID enum */
@@ -349,7 +351,8 @@
 	MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH			= 106,
 	MSM_RPM_8930_STATUS_ID_HDMI_SWITCH			= 107,
 	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 108,
-	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_QDSS_CLK,
+	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 109,
+	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
 };
 
 #endif /* __ARCH_ARM_MACH_MSM_RPM_8930_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
index 9e654ed..684f9d3 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
@@ -121,7 +121,8 @@
 	RPM_VREG_ID_PM8038_S6,
 	RPM_VREG_ID_PM8038_LVS1,
 	RPM_VREG_ID_PM8038_LVS2,
-	RPM_VREG_ID_PM8038_MAX_REAL = RPM_VREG_ID_PM8038_LVS2,
+	RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+	RPM_VREG_ID_PM8038_MAX_REAL = RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
 
 	/* The following are IDs for regulator devices to enable pin control. */
 	RPM_VREG_ID_PM8038_L2_PC,
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index f8f4c87..f9fc487 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.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
@@ -68,6 +68,19 @@
 };
 
 /**
+ * enum rpm_vreg_voltage_corner - possible voltage corner values
+ *
+ * These should be used in regulator_set_voltage and rpm_vreg_set_voltage calls
+ * for corner type regulators as if they had units of uV.
+ */
+enum rpm_vreg_voltage_corner {
+	RPM_VREG_CORNER_NONE = 1,
+	RPM_VREG_CORNER_LOW,
+	RPM_VREG_CORNER_NOMINAL,
+	RPM_VREG_CORNER_HIGH,
+};
+
+/**
  * struct rpm_regulator_init_data - RPM regulator initialization data
  * @init_data:		regulator constraints
  * @id:			regulator id; from enum rpm_vreg_id
@@ -87,6 +100,9 @@
  * @pin_fn:		action to perform when pin control pin(s) is/are active
  * @force_mode:		used to specify a force mode which overrides the votes
  *			of other RPM masters.
+ * @sleep_set_force_mode: force mode to use in sleep-set requests
+ * @power_mode:		mode to use as HPM (typically PWM or hysteretic) when
+ *			utilizing Auto mode selection
  * @default_uV:		initial voltage to set the regulator to if enable is
  *			called before set_voltage (e.g. when boot_on or
  *			always_on is set).
@@ -107,6 +123,7 @@
 	unsigned			pin_ctrl;
 	int				pin_fn;
 	int				force_mode;
+	int				sleep_set_force_mode;
 	int				power_mode;
 	int				default_uV;
 	unsigned			peak_uA;
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index bcb1240..140b7c9 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -451,6 +451,7 @@
 	MSM_RPM_ID_PM8038_CLK2_1,
 	MSM_RPM_ID_PM8038_LVS1,
 	MSM_RPM_ID_PM8038_LVS2,
+	MSM_RPM_ID_VOLTAGE_CORNER,
 
 	/* 8064 specific */
 	MSM_RPM_ID_PM8821_S1_0,
@@ -815,6 +816,7 @@
 	MSM_RPM_STATUS_ID_PM8038_CLK2_1,
 	MSM_RPM_STATUS_ID_PM8038_LVS1,
 	MSM_RPM_STATUS_ID_PM8038_LVS2,
+	MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
 
 	/* 8064 specific */
 	MSM_RPM_STATUS_ID_PM8821_S1_0,
@@ -880,6 +882,7 @@
 struct msm_rpm_platform_data {
 	void __iomem *reg_base_addrs[MSM_RPM_PAGE_COUNT];
 	unsigned int irq_ack;
+	unsigned int irq_err;
 	void *ipc_rpm_reg;
 	unsigned int ipc_rpm_val;
 	struct msm_rpm_map_data target_id[MSM_RPM_ID_LAST];
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 6aa944f..7cc5f7a 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,11 +31,14 @@
 
 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))
 
 extern u32 scm_get_version(void);
 extern int scm_is_call_available(u32 svc_id, u32 cmd_id);
+extern int scm_get_feat_version(u32 feat);
 
 #else
 
@@ -54,6 +58,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;
@@ -64,5 +74,10 @@
 	return 0;
 }
 
+static inline int scm_get_feat_version(u32 feat)
+{
+	return 0;
+}
+
 #endif
 #endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index e1d4459..99bf212 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -36,9 +36,12 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmcopper")
 #define machine_is_copper()		\
 	of_machine_is_compatible("qcom,msmcopper")
+#define machine_is_copper_sim()		\
+	of_machine_is_compatible("qcom,msmcopper-sim")
 #else
 #define early_machine_is_copper()	0
 #define machine_is_copper()		0
+#define machine_is_copper_sim()	0
 #endif
 
 enum msm_cpu {
@@ -68,6 +71,7 @@
 enum msm_cpu socinfo_get_msm_cpu(void);
 uint32_t socinfo_get_id(void);
 uint32_t socinfo_get_version(void);
+uint32_t socinfo_get_raw_id(void);
 char *socinfo_get_build_id(void);
 uint32_t socinfo_get_platform_type(void);
 uint32_t socinfo_get_platform_subtype(void);
@@ -103,7 +107,7 @@
 
 static inline int cpu_is_msm7x27(void)
 {
-#ifdef CONFIG_ARCH_MSM7X27
+#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)
 	enum msm_cpu cpu = socinfo_get_msm_cpu();
 
 	BUG_ON(cpu == MSM_CPU_UNKNOWN);
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 34729b3..7eaf526 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.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
@@ -51,7 +51,12 @@
 #define SPS_IOVEC_FLAG_INT  0x8000  /* Generate interrupt */
 #define SPS_IOVEC_FLAG_EOT  0x4000  /* Generate end-of-transfer indication */
 #define SPS_IOVEC_FLAG_EOB  0x2000  /* Generate end-of-block indication */
-#define SPS_IOVEC_FLAG_NO_SUBMIT 0x0100  /* Do not submit descriptor to HW */
+#define SPS_IOVEC_FLAG_NWD  0x1000  /* notify when done */
+#define SPS_IOVEC_FLAG_CMD  0x0800  /* command descriptor */
+#define SPS_IOVEC_FLAG_LOCK  0x0400  /* pipe lock */
+#define SPS_IOVEC_FLAG_UNLOCK  0x0200  /* pipe unlock */
+#define SPS_IOVEC_FLAG_IMME 0x0100  /* immediate command descriptor */
+#define SPS_IOVEC_FLAG_NO_SUBMIT 0x0002  /* Do not submit descriptor to HW */
 #define SPS_IOVEC_FLAG_DEFAULT   0x0001  /* Use driver default */
 
 /* BAM device options flags */
@@ -127,6 +132,8 @@
 	SPS_O_STREAMING = 0x00010000,  /* Enable streaming mode (no EOT) */
 	/* Use MTI/SETPEND instead of BAM interrupt */
 	SPS_O_IRQ_MTI   = 0x00020000,
+	/* NWD bit written with EOT for BAM2BAM producer pipe */
+	SPS_O_WRITE_NWD   = 0x00040000,
 
 	/* Options to enable software features */
 	/* Transfer operation should be polled */
@@ -233,6 +240,14 @@
 /*   SPS_TIMER_MODE_PERIODIC,    Not supported by hardware yet */
 };
 
+/*
+ * This enum indicates the command type in a command element
+ */
+enum sps_command_type {
+	SPS_WRITE_COMMAND = 0,
+	SPS_READ_COMMAND,
+};
+
 /**
  * This data type corresponds to the native I/O vector (BAM descriptor)
  * supported by SPS hardware
@@ -248,6 +263,26 @@
 	u32 flags:16;
 };
 
+/**
+ * This data type corresponds to the native Command Element
+ * supported by SPS hardware
+ *
+ * @addr - register address.
+ * @command - command type.
+ * @data - for write command: content to be written into peripheral register.
+ *         for read command: dest addr to write peripheral register value to.
+ * @mask - register mask.
+ * @reserved - for future usage.
+ *
+ */
+struct sps_command_element {
+	u32 addr:24;
+	u32 command:8;
+	u32 data;
+	u32 mask;
+	u32 reserved;
+};
+
 /*
  * BAM device's security configuation
  */
@@ -398,6 +433,7 @@
  * @data - Data FIFO (BAM-to-BAM mode only).
  *
  * @event_thresh - Pipe event threshold or derivative.
+ * @lock_group - The lock group this pipe belongs to.
  *
  * @sps_reserved - Reserved word - client must not modify.
  *
@@ -419,6 +455,8 @@
 
 	u32 event_thresh;
 
+	u32 lock_group;
+
 	/* SETPEND/MTI interrupt generation parameters */
 
 	u32 irq_gen_addr;
@@ -1167,4 +1205,17 @@
 int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
 		  u32 addr, u32 size, int use_offset);
 
+/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @desc_num - number of unused descriptors
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num);
+
 #endif /* _SPS_H_ */
diff --git a/arch/arm/mach-msm/include/mach/timex.h b/arch/arm/mach-msm/include/mach/timex.h
index 61f1996..542aba3 100644
--- a/arch/arm/mach-msm/include/mach/timex.h
+++ b/arch/arm/mach-msm/include/mach/timex.h
@@ -18,7 +18,7 @@
 
 #define CLOCK_TICK_RATE		1000000
 
-#ifdef CONFIG_MSM_SMP
+#ifdef CONFIG_HAVE_ARCH_HAS_CURRENT_TIMER
 #define ARCH_HAS_READ_CURRENT_TIMER
 #endif
 
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index dcf9f12..7c0de57 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -43,7 +43,7 @@
  */
 unsigned int msm_shared_ram_phys = 0x00100000;
 
-static void msm_map_io(struct map_desc *io_desc, int size)
+static void __init msm_map_io(struct map_desc *io_desc, int size)
 {
 	int i;
 
@@ -68,7 +68,7 @@
 	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),
+	MSM_DEVICE(DEBUG_UART),
 #endif
 #ifdef CONFIG_CACHE_L2X0
 	{
@@ -273,6 +273,7 @@
 	MSM_CHIP_DEVICE(SAW3, APQ8064),
 	MSM_CHIP_DEVICE(SAW_L2, APQ8064),
 	MSM_CHIP_DEVICE(IMEM, APQ8064),
+	MSM_CHIP_DEVICE(HDMI, APQ8064),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
@@ -313,19 +314,19 @@
 
 #ifdef CONFIG_ARCH_MSM7X30
 static struct map_desc msm7x30_io_desc[] __initdata = {
-	MSM_DEVICE(VIC),
-	MSM_DEVICE(CSR),
-	MSM_DEVICE(TMR),
-	MSM_DEVICE(GPIO1),
-	MSM_DEVICE(GPIO2),
-	MSM_DEVICE(CLK_CTL),
-	MSM_DEVICE(CLK_CTL_SH2),
-	MSM_DEVICE(AD5),
-	MSM_DEVICE(MDC),
-	MSM_DEVICE(ACC),
-	MSM_DEVICE(SAW),
-	MSM_DEVICE(GCC),
-	MSM_DEVICE(TCSR),
+	MSM_CHIP_DEVICE(VIC, MSM7X30),
+	MSM_CHIP_DEVICE(CSR, MSM7X30),
+	MSM_CHIP_DEVICE(TMR, MSM7X30),
+	MSM_CHIP_DEVICE(GPIO1, MSM7X30),
+	MSM_CHIP_DEVICE(GPIO2, MSM7X30),
+	MSM_CHIP_DEVICE(CLK_CTL, MSM7X30),
+	MSM_CHIP_DEVICE(CLK_CTL_SH2, MSM7X30),
+	MSM_CHIP_DEVICE(AD5, MSM7X30),
+	MSM_CHIP_DEVICE(MDC, MSM7X30),
+	MSM_CHIP_DEVICE(ACC0, MSM7X30),
+	MSM_CHIP_DEVICE(SAW0, MSM7X30),
+	MSM_CHIP_DEVICE(APCS_GCC, MSM7X30),
+	MSM_CHIP_DEVICE(TCSR, MSM7X30),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
 	defined(CONFIG_DEBUG_MSM_UART3)
 	MSM_DEVICE(DEBUG_UART),
@@ -419,9 +420,11 @@
 	MSM_CHIP_DEVICE(CLK_CTL, MSM8625),
 	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),
+	MSM_DEVICE(DEBUG_UART),
 #endif
 #ifdef CONFIG_CACHE_L2X0
 	{
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 463d6c9..d495c1b 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.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
@@ -56,7 +56,7 @@
 
 static int msm_iommu_tex_class[4];
 
-DEFINE_SPINLOCK(msm_iommu_lock);
+DEFINE_MUTEX(msm_iommu_lock);
 
 struct msm_priv {
 	unsigned long *pgtable;
@@ -68,14 +68,14 @@
 {
 	int ret;
 
-	ret = clk_enable(drvdata->pclk);
+	ret = clk_prepare_enable(drvdata->pclk);
 	if (ret)
 		goto fail;
 
 	if (drvdata->clk) {
-		ret = clk_enable(drvdata->clk);
+		ret = clk_prepare_enable(drvdata->clk);
 		if (ret)
-			clk_disable(drvdata->pclk);
+			clk_disable_unprepare(drvdata->pclk);
 	}
 fail:
 	return ret;
@@ -84,8 +84,8 @@
 static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
 {
 	if (drvdata->clk)
-		clk_disable(drvdata->clk);
-	clk_disable(drvdata->pclk);
+		clk_disable_unprepare(drvdata->clk);
+	clk_disable_unprepare(drvdata->pclk);
 }
 
 static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
@@ -176,7 +176,8 @@
 }
 
 static void __program_context(void __iomem *base, int ctx, int ncb,
-			      phys_addr_t pgtable, int redirect)
+			      phys_addr_t pgtable, int redirect,
+			      int ttbr_split)
 {
 	unsigned int prrr, nmrr;
 	int i, j, found;
@@ -189,8 +190,10 @@
 	/* V2P configuration: HTW for access */
 	SET_V2PCFG(base, ctx, 0x3);
 
-	SET_TTBCR(base, ctx, 0);
+	SET_TTBCR(base, ctx, ttbr_split);
 	SET_TTBR0_PA(base, ctx, (pgtable >> TTBR0_PA_SHIFT));
+	if (ttbr_split)
+		SET_TTBR1_PA(base, ctx, (pgtable >> TTBR1_PA_SHIFT));
 
 	/* Enable context fault interrupt */
 	SET_CFEIE(base, ctx, 1);
@@ -299,11 +302,10 @@
 static void msm_iommu_domain_destroy(struct iommu_domain *domain)
 {
 	struct msm_priv *priv;
-	unsigned long flags;
 	unsigned long *fl_table;
 	int i;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 	priv = domain->priv;
 	domain->priv = NULL;
 
@@ -320,7 +322,7 @@
 	}
 
 	kfree(priv);
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 }
 
 static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -331,9 +333,8 @@
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	struct msm_iommu_ctx_drvdata *tmp_drvdata;
 	int ret = 0;
-	unsigned long flags;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 
@@ -367,13 +368,14 @@
 		goto fail;
 
 	__program_context(iommu_drvdata->base, ctx_dev->num, iommu_drvdata->ncb,
-			  __pa(priv->pgtable), priv->redirect);
+			  __pa(priv->pgtable), priv->redirect,
+			  iommu_drvdata->ttbr_split);
 
 	__disable_clocks(iommu_drvdata);
 	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
 
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -384,10 +386,9 @@
 	struct msm_iommu_ctx_dev *ctx_dev;
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
-	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 	priv = domain->priv;
 
 	if (!priv || !dev)
@@ -412,7 +413,7 @@
 	list_del_init(&ctx_drvdata->attached_elm);
 
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 }
 
 static int __get_pgprot(int prot, int len)
@@ -447,7 +448,6 @@
 			 phys_addr_t pa, int order, int prot)
 {
 	struct msm_priv *priv;
-	unsigned long flags;
 	unsigned long *fl_table;
 	unsigned long *fl_pte;
 	unsigned long fl_offset;
@@ -458,7 +458,7 @@
 	size_t len = 0x1000UL << order;
 	int ret = 0;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 	if (!priv) {
@@ -525,7 +525,7 @@
 
 		if (*fl_pte == 0) {
 			unsigned long *sl;
-			sl = (unsigned long *) __get_free_pages(GFP_ATOMIC,
+			sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
 							get_order(SZ_4K));
 
 			if (!sl) {
@@ -583,7 +583,7 @@
 
 	ret = __flush_iotlb_va(domain, va);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -591,7 +591,6 @@
 			    int order)
 {
 	struct msm_priv *priv;
-	unsigned long flags;
 	unsigned long *fl_table;
 	unsigned long *fl_pte;
 	unsigned long fl_offset;
@@ -601,7 +600,7 @@
 	size_t len = 0x1000UL << order;
 	int i, ret = 0;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 
@@ -686,10 +685,23 @@
 
 	ret = __flush_iotlb_va(domain, va);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
+static unsigned int get_phys_addr(struct scatterlist *sg)
+{
+	/*
+	 * Try sg_dma_address first so that we can
+	 * map carveout regions that do not have a
+	 * struct page associated with them.
+	 */
+	unsigned int pa = sg_dma_address(sg);
+	if (pa == 0)
+		pa = sg_phys(sg);
+	return pa;
+}
+
 static int msm_iommu_map_range(struct iommu_domain *domain, unsigned int va,
 			       struct scatterlist *sg, unsigned int len,
 			       int prot)
@@ -702,13 +714,12 @@
 	unsigned long fl_offset;
 	unsigned long *sl_table;
 	unsigned long sl_offset, sl_start;
-	unsigned long flags;
 	unsigned int chunk_offset = 0;
 	unsigned int chunk_pa;
 	int ret = 0;
 	struct msm_priv *priv;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	BUG_ON(len & (SZ_4K - 1));
 
@@ -728,13 +739,18 @@
 	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
 	sl_offset = SL_OFFSET(va);
 
-	chunk_pa = sg_phys(sg);
+	chunk_pa = get_phys_addr(sg);
+	if (chunk_pa == 0) {
+		pr_debug("No dma address for sg %p\n", sg);
+		ret = -EINVAL;
+		goto fail;
+	}
 
 	while (offset < len) {
 		/* Set up a 2nd level page table if one doesn't exist */
 		if (*fl_pte == 0) {
 			sl_table = (unsigned long *)
-				 __get_free_pages(GFP_ATOMIC, get_order(SZ_4K));
+				 __get_free_pages(GFP_KERNEL, get_order(SZ_4K));
 
 			if (!sl_table) {
 				pr_debug("Could not allocate second level table\n");
@@ -770,7 +786,13 @@
 			if (chunk_offset >= sg->length && offset < len) {
 				chunk_offset = 0;
 				sg = sg_next(sg);
-				chunk_pa = sg_phys(sg);
+				chunk_pa = get_phys_addr(sg);
+				if (chunk_pa == 0) {
+					pr_debug("No dma address for sg %p\n",
+						 sg);
+					ret = -EINVAL;
+					goto fail;
+				}
 			}
 		}
 
@@ -782,7 +804,7 @@
 	}
 	__flush_iotlb(domain);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -796,11 +818,10 @@
 	unsigned long fl_offset;
 	unsigned long *sl_table;
 	unsigned long sl_start, sl_end;
-	unsigned long flags;
 	int used, i;
 	struct msm_priv *priv;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	BUG_ON(len & (SZ_4K - 1));
 
@@ -854,7 +875,7 @@
 	}
 
 	__flush_iotlb(domain);
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return 0;
 }
 
@@ -865,12 +886,11 @@
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	unsigned int par;
-	unsigned long flags;
 	void __iomem *base;
 	phys_addr_t ret = 0;
 	int ctx;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 	if (list_empty(&priv->list_attached))
@@ -903,7 +923,7 @@
 
 	__disable_clocks(iommu_drvdata);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -947,7 +967,7 @@
 	unsigned int fsr;
 	int i, ret;
 
-	spin_lock(&msm_iommu_lock);
+	mutex_lock(&msm_iommu_lock);
 
 	if (!drvdata) {
 		pr_err("Invalid device ID in context interrupt handler\n");
@@ -975,7 +995,7 @@
 	}
 	__disable_clocks(drvdata);
 fail:
-	spin_unlock(&msm_iommu_lock);
+	mutex_unlock(&msm_iommu_lock);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index 1982082..6633cae 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.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
@@ -156,7 +156,7 @@
 		goto fail;
 	}
 
-	ret = clk_enable(iommu_pclk);
+	ret = clk_prepare_enable(iommu_pclk);
 	if (ret)
 		goto fail_enable;
 
@@ -168,7 +168,7 @@
 			clk_set_rate(iommu_clk, ret);
 		}
 
-		ret = clk_enable(iommu_clk);
+		ret = clk_prepare_enable(iommu_clk);
 		if (ret) {
 			clk_put(iommu_clk);
 			goto fail_pclk;
@@ -226,8 +226,8 @@
 		goto fail_io;
 	}
 
-	ret = request_irq(irq, msm_iommu_fault_handler, 0,
-			"msm_iommu_secure_irpt_handler", drvdata);
+	ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+			IRQF_ONESHOT, "msm_iommu_secure_irpt_handler", drvdata);
 	if (ret) {
 		pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
 		goto fail_io;
@@ -239,6 +239,7 @@
 	drvdata->base = regs_base;
 	drvdata->irq = irq;
 	drvdata->ncb = iommu_dev->ncb;
+	drvdata->ttbr_split = iommu_dev->ttbr_split;
 	drvdata->name = iommu_dev->name;
 
 	pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
@@ -247,9 +248,9 @@
 	platform_set_drvdata(pdev, drvdata);
 
 	if (iommu_clk)
-		clk_disable(iommu_clk);
+		clk_disable_unprepare(iommu_clk);
 
-	clk_disable(iommu_pclk);
+	clk_disable_unprepare(iommu_pclk);
 
 	return 0;
 fail_io:
@@ -258,11 +259,11 @@
 	release_mem_region(r->start, len);
 fail_clk:
 	if (iommu_clk) {
-		clk_disable(iommu_clk);
+		clk_disable_unprepare(iommu_clk);
 		clk_put(iommu_clk);
 	}
 fail_pclk:
-	clk_disable(iommu_pclk);
+	clk_disable_unprepare(iommu_pclk);
 fail_enable:
 	clk_put(iommu_pclk);
 fail:
@@ -315,14 +316,14 @@
 	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
 	platform_set_drvdata(pdev, ctx_drvdata);
 
-	ret = clk_enable(drvdata->pclk);
+	ret = clk_prepare_enable(drvdata->pclk);
 	if (ret)
 		goto fail;
 
 	if (drvdata->clk) {
-		ret = clk_enable(drvdata->clk);
+		ret = clk_prepare_enable(drvdata->clk);
 		if (ret) {
-			clk_disable(drvdata->pclk);
+			clk_disable_unprepare(drvdata->pclk);
 			goto fail;
 		}
 	}
@@ -357,8 +358,8 @@
 	mb();
 
 	if (drvdata->clk)
-		clk_disable(drvdata->clk);
-	clk_disable(drvdata->pclk);
+		clk_disable_unprepare(drvdata->clk);
+	clk_disable_unprepare(drvdata->pclk);
 
 	dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
 	return 0;
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 727b729..1959f5d 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.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
@@ -13,6 +13,7 @@
 #include <mach/msm_subsystem_map.h>
 #include <linux/memory_alloc.h>
 #include <linux/iommu.h>
+#include <linux/vmalloc.h>
 #include <asm/sizes.h>
 #include <asm/page.h>
 #include <linux/init.h>
@@ -43,10 +44,145 @@
 	char *name;
 	int  domain;
 } msm_iommu_ctx_names[] = {
+	/* Camera */
+	{
+		.name = "vpe_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vpe_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_imgwr",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_misc",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_src",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_dst",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_mm1",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_b_mm2",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_stream",
+		.domain = VIDEO_DOMAIN,
+	},
 };
 
+static struct mem_pool video_pools[] =  {
+	/*
+	 * Video hardware has the following requirements:
+	 * 1. All video addresses used by the video hardware must be at a higher
+	 *    address than video firmware address.
+	 * 2. Video hardware can only access a range of 256MB from the base of
+	 *    the video firmware.
+	*/
+	[VIDEO_FIRMWARE_POOL] =
+	/* Low addresses, intended for video firmware */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_16M - SZ_128K,
+		},
+	[VIDEO_MAIN_POOL] =
+	/* Main video pool */
+		{
+			.paddr	= SZ_16M,
+			.size	= SZ_256M - SZ_16M,
+		},
+	[GEN_POOL] =
+	/* Remaining address space up to 2G */
+		{
+			.paddr	= SZ_256M,
+			.size	= SZ_2G - SZ_256M,
+		},
+};
+
+static struct mem_pool camera_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for camera */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool display_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for display */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool rotator_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
 
 static struct msm_iommu_domain msm_iommu_domains[] = {
+		[VIDEO_DOMAIN] = {
+			.iova_pools = video_pools,
+			.npools = ARRAY_SIZE(video_pools),
+		},
+		[CAMERA_DOMAIN] = {
+			.iova_pools = camera_pools,
+			.npools = ARRAY_SIZE(camera_pools),
+		},
+		[DISPLAY_DOMAIN] = {
+			.iova_pools = display_pools,
+			.npools = ARRAY_SIZE(display_pools),
+		},
+		[ROTATOR_DOMAIN] = {
+			.iova_pools = rotator_pools,
+			.npools = ARRAY_SIZE(rotator_pools),
+		},
 };
 
 int msm_iommu_map_extra(struct iommu_domain *domain,
@@ -54,33 +190,32 @@
 				unsigned long size,
 				int cached)
 {
-	int i, ret;
-	unsigned long temp_iova;
+	int i, ret = 0;
+	struct scatterlist *sglist;
+	unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
+	struct page *dummy_page = phys_to_page(
+					PFN_ALIGN(virt_to_phys(iommu_dummy)));
 
-	for (i = size, temp_iova = start_iova; i > 0; i -= SZ_4K,
-						temp_iova += SZ_4K) {
-		ret = iommu_map(domain, temp_iova,
-				PFN_ALIGN(virt_to_phys(iommu_dummy)),
-				get_order(SZ_4K),
-				0);
-
-		if (ret) {
-			pr_err("%s: could not map %lx to dummy page in domain"
-				" %p\n",
-				__func__, temp_iova, domain);
-			goto out;
-		}
+	sglist = vmalloc(sizeof(*sglist) * nrpages);
+	if (!sglist) {
+		ret = -ENOMEM;
+		goto err1;
 	}
 
-	return 0;
+	sg_init_table(sglist, nrpages);
 
-out:
+	for (i = 0; i < nrpages; i++)
+		sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
 
-	for ( ; i < size; i += SZ_4K, temp_iova -= SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+	ret = iommu_map_range(domain, start_iova, sglist, size, cached);
+	if (ret) {
+		pr_err("%s: could not map extra %lx in domain %p\n",
+			__func__, start_iova, domain);
+	}
 
-	return -EINVAL;
-
+	vfree(sglist);
+err1:
+	return ret;
 }
 
 
@@ -92,9 +227,22 @@
 		return NULL;
 }
 
+static unsigned long subsystem_to_domain_tbl[] = {
+	VIDEO_DOMAIN,
+	VIDEO_DOMAIN,
+	CAMERA_DOMAIN,
+	DISPLAY_DOMAIN,
+	ROTATOR_DOMAIN,
+	0xFFFFFFFF
+};
+
 unsigned long msm_subsystem_get_domain_no(int subsys_id)
 {
-	return GLOBAL_DOMAIN;
+	if (subsys_id > INVALID_SUBSYS_ID && subsys_id <= MAX_SUBSYSTEM_ID &&
+	    subsys_id < ARRAY_SIZE(subsystem_to_domain_tbl))
+		return subsystem_to_domain_tbl[subsys_id];
+	else
+		return subsystem_to_domain_tbl[MAX_SUBSYSTEM_ID];
 }
 
 unsigned long msm_subsystem_get_partition_no(int subsys_id)
@@ -168,8 +316,7 @@
 
 int msm_use_iommu()
 {
-	/* Kill use of the iommu by these clients for now. */
-	return 0;
+	return iommu_found();
 }
 
 static int __init msm_subsystem_iommu_init(void)
@@ -185,25 +332,29 @@
 			struct mem_pool *pool = &msm_iommu_domains[i].
 							iova_pools[j];
 			mutex_init(&pool->pool_mutex);
-			pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
+			if (pool->size) {
+				pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
 
-			if (!pool->gpool) {
-				pr_err("%s: domain %d: could not allocate iova"
-					" pool. iommu programming will not work"
-					" with iova space %d\n", __func__,
-					i, j);
-				continue;
-			}
+				if (!pool->gpool) {
+					pr_err("%s: could not allocate pool\n",
+						__func__);
+					pr_err("%s: domain %d iova space %d\n",
+						__func__, i, j);
+					continue;
+				}
 
-			if (gen_pool_add(pool->gpool, pool->paddr, pool->size,
-						-1)) {
-				pr_err("%s: domain %d: could not add memory to"
-					" iova pool. iommu programming will not"
-					" work with iova space %d\n", __func__,
-					i, j);
-				gen_pool_destroy(pool->gpool);
+				if (gen_pool_add(pool->gpool, pool->paddr,
+						pool->size, -1)) {
+					pr_err("%s: could not add memory\n",
+						__func__);
+					pr_err("%s: domain %d pool %d\n",
+						__func__, i, j);
+					gen_pool_destroy(pool->gpool);
+					pool->gpool = NULL;
+					continue;
+				}
+			} else {
 				pool->gpool = NULL;
-				continue;
 			}
 		}
 	}
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 15ea8ba..538dbbe 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.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
@@ -756,7 +756,7 @@
 	pkt->length = pkt_size;
 
 	mutex_lock(&xprt_info->tx_lock);
-	ret = xprt_info->xprt->write(pkt, pkt_size, 0);
+	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock);
 
 	release_pkt(pkt);
@@ -933,7 +933,8 @@
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
 		mutex_lock(&fwd_xprt_info->tx_lock);
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+			fwd_xprt_info->xprt->write(pkt, pkt->length,
+						   fwd_xprt_info->xprt);
 		mutex_unlock(&fwd_xprt_info->tx_lock);
 	}
 	mutex_unlock(&xprt_info_list_lock);
@@ -984,7 +985,7 @@
 		pr_err("%s: DST in the same cluster\n", __func__);
 		return 0;
 	}
-	fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
 	mutex_unlock(&fwd_xprt_info->tx_lock);
 	mutex_unlock(&rt_entry->lock);
 	mutex_unlock(&routing_table_lock);
@@ -1713,7 +1714,7 @@
 	mutex_lock(&rt_entry->lock);
 	xprt_info = rt_entry->xprt_info;
 	mutex_lock(&xprt_info->tx_lock);
-	ret = xprt_info->xprt->write(pkt, pkt->length, 0);
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock);
 	mutex_unlock(&rt_entry->lock);
 	mutex_unlock(&routing_table_lock);
@@ -2070,7 +2071,7 @@
 	mutex_lock(&xprt_info_list_lock);
 	list_for_each_entry_safe(xprt_info, tmp_xprt_info,
 				 &xprt_info_list, list) {
-		xprt_info->xprt->close();
+		xprt_info->xprt->close(xprt_info->xprt);
 		list_del(&xprt_info->list);
 		kfree(xprt_info);
 	}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index b125185..bd10ea7 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.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
@@ -150,11 +150,13 @@
 	uint32_t link_id;
 	void *priv;
 
-	int (*read_avail)(void);
-	int (*read)(void *data, uint32_t len);
-	int (*write_avail)(void);
-	int (*write)(void *data, uint32_t len, enum write_data_type type);
-	int (*close)(void);
+	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*read)(void *data, uint32_t len,
+		    struct msm_ipc_router_xprt *xprt);
+	int (*write_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*write)(void *data, uint32_t len,
+		     struct msm_ipc_router_xprt *xprt);
+	int (*close)(struct msm_ipc_router_xprt *xprt);
 };
 
 extern struct completion msm_ipc_remote_router_up;
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 997d4b5..6960d2e 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.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
@@ -38,14 +38,21 @@
 
 #define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
 
+#define NUM_SMD_XPRTS 2
+#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
+
 struct msm_ipc_router_smd_xprt {
 	struct msm_ipc_router_xprt xprt;
-
 	smd_channel_t *channel;
+	struct workqueue_struct *smd_xprt_wq;
+	wait_queue_head_t write_avail_wait_q;
+	struct rr_packet *in_pkt;
+	int is_partial_in_pkt;
+	struct delayed_work read_work;
+	spinlock_t ss_reset_lock;	/*Subsystem reset lock*/
+	int ss_reset;
 };
 
-static struct msm_ipc_router_smd_xprt smd_remote_xprt;
-
 struct msm_ipc_router_smd_xprt_work {
 	struct msm_ipc_router_xprt *xprt;
 	struct work_struct work;
@@ -54,24 +61,45 @@
 static void smd_xprt_read_data(struct work_struct *work);
 static void smd_xprt_open_event(struct work_struct *work);
 static void smd_xprt_close_event(struct work_struct *work);
-static DECLARE_DELAYED_WORK(work_read_data, smd_xprt_read_data);
-static struct workqueue_struct *smd_xprt_workqueue;
 
-static wait_queue_head_t write_avail_wait_q;
-static struct rr_packet *in_pkt;
-static int is_partial_in_pkt;
+struct msm_ipc_router_smd_xprt_config {
+	char ch_name[SMD_MAX_CH_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	uint32_t edge;
+	uint32_t link_id;
+};
 
-static DEFINE_SPINLOCK(modem_reset_lock);
-static int modem_reset;
+struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
+};
 
-static int msm_ipc_router_smd_remote_write_avail(void)
+static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
+
+static int find_smd_xprt_cfg(const char *name)
 {
-	return smd_write_avail(smd_remote_xprt.channel);
+	int i;
+
+	for (i = 0; i < NUM_SMD_XPRTS; i++) {
+		if (!strncmp(name, smd_xprt_cfg[i].ch_name, 20))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static int msm_ipc_router_smd_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_write_avail(smd_xprtp->channel);
 }
 
 static int msm_ipc_router_smd_remote_write(void *data,
 					   uint32_t len,
-					   uint32_t type)
+					   struct msm_ipc_router_xprt *xprt)
 {
 	struct rr_packet *pkt = (struct rr_packet *)data;
 	struct sk_buff *ipc_rtr_pkt;
@@ -79,6 +107,8 @@
 	int offset, sz_written = 0;
 	int ret, num_retries = 0;
 	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
 
 	if (!pkt)
 		return -EINVAL;
@@ -87,81 +117,92 @@
 		return -EINVAL;
 
 	align_sz = ALIGN_SIZE(pkt->length);
-	while ((ret = smd_write_start(smd_remote_xprt.channel,
+	while ((ret = smd_write_start(smd_xprtp->channel,
 				      (len + align_sz))) < 0) {
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		if (modem_reset) {
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
-			pr_err("%s: Modem reset\n", __func__);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
+			pr_err("%s: %s chnl reset\n", __func__, xprt->name);
 			return -ENETRESET;
 		}
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 		if (num_retries >= 5) {
-			pr_err("%s: Error %d @ smd_write_start\n",
-				__func__, ret);
+			pr_err("%s: Error %d @smd_write_start for %s\n",
+				__func__, ret, xprt->name);
 			return ret;
 		}
 		msleep(50);
+		num_retries++;
 	}
 
 	D("%s: Ready to write\n", __func__);
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
-			if (!smd_write_avail(smd_remote_xprt.channel))
-				smd_enable_read_intr(smd_remote_xprt.channel);
+			if (!smd_write_avail(smd_xprtp->channel))
+				smd_enable_read_intr(smd_xprtp->channel);
 
-			wait_event(write_avail_wait_q,
-				(smd_write_avail(smd_remote_xprt.channel) ||
-				modem_reset));
-			smd_disable_read_intr(smd_remote_xprt.channel);
-			spin_lock_irqsave(&modem_reset_lock, flags);
-			if (modem_reset) {
-				spin_unlock_irqrestore(&modem_reset_lock,
-							flags);
-				pr_err("%s: Modem reset\n", __func__);
+			wait_event(smd_xprtp->write_avail_wait_q,
+				(smd_write_avail(smd_xprtp->channel) ||
+				smd_xprtp->ss_reset));
+			smd_disable_read_intr(smd_xprtp->channel);
+			spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+			if (smd_xprtp->ss_reset) {
+				spin_unlock_irqrestore(
+					&smd_xprtp->ss_reset_lock, flags);
+				pr_err("%s: %s chnl reset\n",
+					__func__, xprt->name);
 				return -ENETRESET;
 			}
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
 
-			sz_written = smd_write_segment(smd_remote_xprt.channel,
-					  ipc_rtr_pkt->data + offset,
-					  (ipc_rtr_pkt->len - offset), 0);
+			sz_written = smd_write_segment(smd_xprtp->channel,
+					ipc_rtr_pkt->data + offset,
+					(ipc_rtr_pkt->len - offset), 0);
 			offset += sz_written;
 			sz_written = 0;
 		}
-		D("%s: Wrote %d bytes\n", __func__, offset);
+		D("%s: Wrote %d bytes over %s\n",
+		  __func__, offset, xprt->name);
 	}
 
 	if (align_sz) {
-		if (smd_write_avail(smd_remote_xprt.channel) < align_sz)
-			smd_enable_read_intr(smd_remote_xprt.channel);
+		if (smd_write_avail(smd_xprtp->channel) < align_sz)
+			smd_enable_read_intr(smd_xprtp->channel);
 
-		wait_event(write_avail_wait_q,
-			((smd_write_avail(smd_remote_xprt.channel) >=
-			 align_sz) || modem_reset));
-		smd_disable_read_intr(smd_remote_xprt.channel);
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		if (modem_reset) {
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
-			pr_err("%s: Modem reset\n", __func__);
+		wait_event(smd_xprtp->write_avail_wait_q,
+			((smd_write_avail(smd_xprtp->channel) >=
+			 align_sz) || smd_xprtp->ss_reset));
+		smd_disable_read_intr(smd_xprtp->channel);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(
+				&smd_xprtp->ss_reset_lock, flags);
+			pr_err("%s: %s chnl reset\n",
+				__func__, xprt->name);
 			return -ENETRESET;
 		}
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+					flags);
 
-		smd_write_segment(smd_remote_xprt.channel,
+		smd_write_segment(smd_xprtp->channel,
 				  &align_data, align_sz, 0);
-		D("%s: Wrote %d align bytes\n", __func__, align_sz);
+		D("%s: Wrote %d align bytes over %s\n",
+		  __func__, align_sz, xprt->name);
 	}
-	if (!smd_write_end(smd_remote_xprt.channel))
+	if (!smd_write_end(smd_xprtp->channel))
 		D("%s: Finished writing\n", __func__);
 	return len;
 }
 
-static int msm_ipc_router_smd_remote_close(void)
+static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
 {
-	smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
-	return smd_close(smd_remote_xprt.channel);
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_close(smd_xprtp->channel);
 }
 
 static void smd_xprt_read_data(struct work_struct *work)
@@ -170,90 +211,97 @@
 	struct sk_buff *ipc_rtr_pkt;
 	void *data;
 	unsigned long flags;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(rwork, struct msm_ipc_router_smd_xprt, read_work);
 
-	spin_lock_irqsave(&modem_reset_lock, flags);
-	if (modem_reset) {
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
-		release_pkt(in_pkt);
-		is_partial_in_pkt = 0;
-		pr_err("%s: Modem reset\n", __func__);
+	spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+	if (smd_xprtp->ss_reset) {
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->in_pkt)
+			release_pkt(smd_xprtp->in_pkt);
+		smd_xprtp->is_partial_in_pkt = 0;
+		pr_err("%s: %s channel reset\n",
+			__func__, smd_xprtp->xprt.name);
 		return;
 	}
-	spin_unlock_irqrestore(&modem_reset_lock, flags);
+	spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 
 	D("%s pkt_size: %d, read_avail: %d\n", __func__,
-		smd_cur_packet_size(smd_remote_xprt.channel),
-		smd_read_avail(smd_remote_xprt.channel));
-	while ((pkt_size = smd_cur_packet_size(smd_remote_xprt.channel)) &&
-		smd_read_avail(smd_remote_xprt.channel)) {
-		if (!is_partial_in_pkt) {
-			in_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
-			if (!in_pkt) {
+		smd_cur_packet_size(smd_xprtp->channel),
+		smd_read_avail(smd_xprtp->channel));
+	while ((pkt_size = smd_cur_packet_size(smd_xprtp->channel)) &&
+		smd_read_avail(smd_xprtp->channel)) {
+		if (!smd_xprtp->is_partial_in_pkt) {
+			smd_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						    GFP_KERNEL);
+			if (!smd_xprtp->in_pkt) {
 				pr_err("%s: Couldn't alloc rr_packet\n",
 					__func__);
 				return;
 			}
 
-			in_pkt->pkt_fragment_q = kmalloc(
-						  sizeof(struct sk_buff_head),
-						  GFP_KERNEL);
-			if (!in_pkt->pkt_fragment_q) {
+			smd_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (!smd_xprtp->in_pkt->pkt_fragment_q) {
 				pr_err("%s: Couldn't alloc pkt_fragment_q\n",
 					__func__);
-				kfree(in_pkt);
+				kfree(smd_xprtp->in_pkt);
 				return;
 			}
-			skb_queue_head_init(in_pkt->pkt_fragment_q);
-			is_partial_in_pkt = 1;
+			skb_queue_head_init(smd_xprtp->in_pkt->pkt_fragment_q);
+			smd_xprtp->is_partial_in_pkt = 1;
 			D("%s: Allocated rr_packet\n", __func__);
 		}
 
 		if (((pkt_size >= MIN_FRAG_SZ) &&
-		     (smd_read_avail(smd_remote_xprt.channel) < MIN_FRAG_SZ)) ||
+		     (smd_read_avail(smd_xprtp->channel) < MIN_FRAG_SZ)) ||
 		    ((pkt_size < MIN_FRAG_SZ) &&
-		     (smd_read_avail(smd_remote_xprt.channel) < pkt_size)))
+		     (smd_read_avail(smd_xprtp->channel) < pkt_size)))
 			return;
 
-		sz = smd_read_avail(smd_remote_xprt.channel);
+		sz = smd_read_avail(smd_xprtp->channel);
 		do {
 			ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
 			if (!ipc_rtr_pkt) {
 				if (sz <= (PAGE_SIZE/2)) {
-					queue_delayed_work(smd_xprt_workqueue,
-						   &work_read_data,
-						   msecs_to_jiffies(100));
+					queue_delayed_work(
+						smd_xprtp->smd_xprt_wq,
+						&smd_xprtp->read_work,
+						msecs_to_jiffies(100));
 					return;
 				}
 				sz = sz / 2;
 			}
 		} while (!ipc_rtr_pkt);
 
-		D("%s: Allocated the sk_buff of size %d\n",
-			__func__, sz);
+		D("%s: Allocated the sk_buff of size %d\n", __func__, sz);
 		data = skb_put(ipc_rtr_pkt, sz);
-		sz_read = smd_read(smd_remote_xprt.channel, data, sz);
+		sz_read = smd_read(smd_xprtp->channel, data, sz);
 		if (sz_read != sz) {
-			pr_err("%s: Couldn't read completely\n", __func__);
+			pr_err("%s: Couldn't read %s completely\n",
+				__func__, smd_xprtp->xprt.name);
 			kfree_skb(ipc_rtr_pkt);
-			release_pkt(in_pkt);
-			is_partial_in_pkt = 0;
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->is_partial_in_pkt = 0;
 			return;
 		}
-		skb_queue_tail(in_pkt->pkt_fragment_q, ipc_rtr_pkt);
-		in_pkt->length += sz_read;
+		skb_queue_tail(smd_xprtp->in_pkt->pkt_fragment_q, ipc_rtr_pkt);
+		smd_xprtp->in_pkt->length += sz_read;
 		if (sz_read != pkt_size)
-			is_partial_in_pkt = 1;
+			smd_xprtp->is_partial_in_pkt = 1;
 		else
-			is_partial_in_pkt = 0;
+			smd_xprtp->is_partial_in_pkt = 0;
 
-		if (!is_partial_in_pkt) {
+		if (!smd_xprtp->is_partial_in_pkt) {
 			D("%s: Packet size read %d\n",
-				__func__, in_pkt->length);
-			msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
-					   IPC_ROUTER_XPRT_EVENT_DATA,
-					   (void *)in_pkt);
-			release_pkt(in_pkt);
-			in_pkt = NULL;
+			  __func__, smd_xprtp->in_pkt->length);
+			msm_ipc_router_xprt_notify(&smd_xprtp->xprt,
+						IPC_ROUTER_XPRT_EVENT_DATA,
+						(void *)smd_xprtp->in_pkt);
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->in_pkt = NULL;
 		}
 	}
 }
@@ -265,7 +313,8 @@
 
 	msm_ipc_router_xprt_notify(xprt_work->xprt,
 				IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
-	D("%s: Notified IPC Router of OPEN Event\n", __func__);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	   __func__, xprt_work->xprt->name);
 	kfree(xprt_work);
 }
 
@@ -276,28 +325,34 @@
 
 	msm_ipc_router_xprt_notify(xprt_work->xprt,
 				IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
-	D("%s: Notified IPC Router of CLOSE Event\n", __func__);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	   __func__, xprt_work->xprt->name);
 	kfree(xprt_work);
 }
 
 static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
 {
 	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
 	struct msm_ipc_router_smd_xprt_work *xprt_work;
 
+	smd_xprtp = (struct msm_ipc_router_smd_xprt *)_dev;
+	if (!smd_xprtp)
+		return;
+
 	switch (event) {
 	case SMD_EVENT_DATA:
-		if (smd_read_avail(smd_remote_xprt.channel))
-			queue_delayed_work(smd_xprt_workqueue,
-					   &work_read_data, 0);
-		if (smd_write_avail(smd_remote_xprt.channel))
-			wake_up(&write_avail_wait_q);
+		if (smd_read_avail(smd_xprtp->channel))
+			queue_delayed_work(smd_xprtp->smd_xprt_wq,
+					   &smd_xprtp->read_work, 0);
+		if (smd_write_avail(smd_xprtp->channel))
+			wake_up(&smd_xprtp->write_avail_wait_q);
 		break;
 
 	case SMD_EVENT_OPEN:
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		modem_reset = 0;
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 0;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
 				    GFP_ATOMIC);
 		if (!xprt_work) {
@@ -305,16 +360,16 @@
 				__func__, event);
 			return;
 		}
-		xprt_work->xprt = &smd_remote_xprt.xprt;
+		xprt_work->xprt = &smd_xprtp->xprt;
 		INIT_WORK(&xprt_work->work, smd_xprt_open_event);
-		queue_work(smd_xprt_workqueue, &xprt_work->work);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
 		break;
 
 	case SMD_EVENT_CLOSE:
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		modem_reset = 1;
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
-		wake_up(&write_avail_wait_q);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 1;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		wake_up(&smd_xprtp->write_avail_wait_q);
 		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
 				    GFP_ATOMIC);
 		if (!xprt_work) {
@@ -322,9 +377,9 @@
 				__func__, event);
 			return;
 		}
-		xprt_work->xprt = &smd_remote_xprt.xprt;
+		xprt_work->xprt = &smd_xprtp->xprt;
 		INIT_WORK(&xprt_work->work, smd_xprt_close_event);
-		queue_work(smd_xprt_workqueue, &xprt_work->work);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
 		break;
 	}
 }
@@ -332,50 +387,93 @@
 static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
 {
 	int rc;
+	int id;		/*Index into the smd_xprt_cfg table*/
 
-	smd_xprt_workqueue = create_singlethread_workqueue("smd_xprt");
-	if (!smd_xprt_workqueue)
-		return -ENOMEM;
+	id = find_smd_xprt_cfg(pdev->name);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
 
-	smd_remote_xprt.xprt.name = "msm_ipc_router_smd_xprt";
-	smd_remote_xprt.xprt.link_id = 1;
-	smd_remote_xprt.xprt.read_avail = NULL;
-	smd_remote_xprt.xprt.read = NULL;
-	smd_remote_xprt.xprt.write_avail =
+	smd_remote_xprt[id].smd_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!smd_remote_xprt[id].smd_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
+	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.read_avail = NULL;
+	smd_remote_xprt[id].xprt.read = NULL;
+	smd_remote_xprt[id].xprt.write_avail =
 		msm_ipc_router_smd_remote_write_avail;
-	smd_remote_xprt.xprt.write = msm_ipc_router_smd_remote_write;
-	smd_remote_xprt.xprt.close = msm_ipc_router_smd_remote_close;
-	smd_remote_xprt.xprt.priv = NULL;
+	smd_remote_xprt[id].xprt.write = msm_ipc_router_smd_remote_write;
+	smd_remote_xprt[id].xprt.close = msm_ipc_router_smd_remote_close;
+	smd_remote_xprt[id].xprt.priv = NULL;
 
-	init_waitqueue_head(&write_avail_wait_q);
+	init_waitqueue_head(&smd_remote_xprt[id].write_avail_wait_q);
+	smd_remote_xprt[id].in_pkt = NULL;
+	smd_remote_xprt[id].is_partial_in_pkt = 0;
+	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
+	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
+	smd_remote_xprt[id].ss_reset = 0;
 
-	rc = smd_open("RPCRPY_CNTL", &smd_remote_xprt.channel, NULL,
-		      msm_ipc_router_smd_remote_notify);
+	rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
+				    smd_xprt_cfg[id].edge,
+				    &smd_remote_xprt[id].channel,
+				    &smd_remote_xprt[id],
+				    msm_ipc_router_smd_remote_notify);
 	if (rc < 0) {
-		destroy_workqueue(smd_xprt_workqueue);
+		pr_err("%s: Channel open failed for %s\n",
+			__func__, smd_xprt_cfg[id].ch_name);
+		destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
 		return rc;
 	}
 
-	smd_disable_read_intr(smd_remote_xprt.channel);
+	smd_disable_read_intr(smd_remote_xprt[id].channel);
 
 	smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
 
 	return 0;
 }
 
-static struct platform_driver msm_ipc_router_smd_remote_driver = {
-	.probe		= msm_ipc_router_smd_remote_probe,
-	.driver		= {
-			.name	= "RPCRPY_CNTL",
-			.owner	= THIS_MODULE,
+static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "RPCRPY_CNTL",
+				.owner	= THIS_MODULE,
+		},
+	},
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "IPCRTR",
+				.owner	= THIS_MODULE,
+		},
 	},
 };
 
 static int __init msm_ipc_router_smd_init(void)
 {
-	return platform_driver_register(&msm_ipc_router_smd_remote_driver);
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(msm_ipc_router_smd_remote_driver) != NUM_SMD_XPRTS);
+	BUG_ON(ARRAY_SIZE(smd_xprt_cfg) != NUM_SMD_XPRTS);
+	for (i = 0; i < NUM_SMD_XPRTS; i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_smd_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for"
+			       " xprt%d. Continuing...\n", __func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
 }
 
 module_init(msm_ipc_router_smd_init);
-MODULE_DESCRIPTION("RPC Router SMD XPRT");
+MODULE_DESCRIPTION("IPC Router SMD XPRT");
 MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index b75fb38..8dae9c6 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -16,26 +16,34 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
+#include <linux/export.h>
 #include <linux/printk.h>
 #include <linux/ratelimit.h>
+#include <mach/scm.h>
 
-#include "qdss.h"
+#include "qdss-priv.h"
 #include "cp14.h"
 
- /* no of dbg regs + 1 (for storing the reg count) */
+/* no of dbg regs + 1 (for storing the reg count) */
 #define MAX_DBG_REGS		(90)
 #define MAX_DBG_STATE_SIZE	(MAX_DBG_REGS * num_possible_cpus())
- /* no of etm regs + 1 (for storing the reg count) */
+/* no of etm regs + 1 (for storing the reg count) */
 #define MAX_ETM_REGS		(78)
 #define MAX_ETM_STATE_SIZE	(MAX_ETM_REGS * num_possible_cpus())
 
+#define OSLOCK_MAGIC		(0xC5ACCE55)
 #define DBGDSCR_MASK		(0x6C30FC3C)
 #define CPMR_ETMCLKEN		(0x8)
+#define TZ_DBG_ETM_FEAT_ID	(0x8)
+#define TZ_DBG_ETM_VER		(0x400000)
 
 
+uint32_t msm_jtag_save_cntr[NR_CPUS];
+uint32_t msm_jtag_restore_cntr[NR_CPUS];
+
 struct dbg_ctx {
 	uint8_t		arch;
-	bool		arch_supported;
+	bool		save_restore_enabled;
 	uint8_t		nr_wp;
 	uint8_t		nr_bp;
 	uint8_t		nr_ctx_cmp;
@@ -45,7 +53,7 @@
 
 struct etm_ctx {
 	uint8_t		arch;
-	bool		arch_supported;
+	bool		save_restore_enabled;
 	uint8_t		nr_addr_cmp;
 	uint8_t		nr_cntr;
 	uint8_t		nr_ext_inp;
@@ -998,16 +1006,23 @@
 	etm_clk_disable();
 }
 
-/* msm_jtag_save_state and msm_jtag_restore_state should be fast
+/**
+ * msm_jtag_save_state - save debug and etm registers
  *
- * These functions will be called either from:
- * 1. per_cpu idle thread context for idle power collapses.
- * 2. per_cpu idle thread context for hotplug/suspend power collapse for
- *    nonboot cpus.
- * 3. suspend thread context for core0.
+ * Debug and etm registers are saved before power collapse if debug
+ * and etm architecture is supported respectively and TZ isn't supporting
+ * the save and restore of debug and etm registers.
  *
- * In all cases we are guaranteed to be running on the same cpu for the
- * entire duration.
+ * CONTEXT:
+ * Called with preemption off and interrupts locked from:
+ * 1. per_cpu idle thread context for idle power collapses
+ * or
+ * 2. per_cpu idle thread context for hotplug/suspend power collapse
+ *    for nonboot cpus
+ * or
+ * 3. suspend thread context for suspend power collapse for core0
+ *
+ * In all cases we will run on the same cpu for the entire duration.
  */
 void msm_jtag_save_state(void)
 {
@@ -1015,23 +1030,51 @@
 
 	cpu = raw_smp_processor_id();
 
-	if (dbg.arch_supported)
+	msm_jtag_save_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
+	if (dbg.save_restore_enabled)
 		dbg_save_state(cpu);
-	if (etm.arch_supported)
+	if (etm.save_restore_enabled)
 		etm_save_state(cpu);
 }
+EXPORT_SYMBOL(msm_jtag_save_state);
 
+/**
+ * msm_jtag_restore_state - restore debug and etm registers
+ *
+ * Debug and etm registers are restored after power collapse if debug
+ * and etm architecture is supported respectively and TZ isn't supporting
+ * the save and restore of debug and etm registers.
+ *
+ * CONTEXT:
+ * Called with preemption off and interrupts locked from:
+ * 1. per_cpu idle thread context for idle power collapses
+ * or
+ * 2. per_cpu idle thread context for hotplug/suspend power collapse
+ *    for nonboot cpus
+ * or
+ * 3. suspend thread context for suspend power collapse for core0
+ *
+ * In all cases we will run on the same cpu for the entire duration.
+ */
 void msm_jtag_restore_state(void)
 {
 	int cpu;
 
 	cpu = raw_smp_processor_id();
 
-	if (dbg.arch_supported)
+	msm_jtag_restore_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
+	if (dbg.save_restore_enabled)
 		dbg_restore_state(cpu);
-	if (etm.arch_supported)
+	if (etm.save_restore_enabled)
 		etm_restore_state(cpu);
 }
+EXPORT_SYMBOL(msm_jtag_restore_state);
 
 static int __init msm_jtag_dbg_init(void)
 {
@@ -1041,17 +1084,25 @@
 	/* This will run on core0 so use it to populate parameters */
 
 	/* Populate dbg_ctx data */
+
 	dbgdidr = dbg_read(DBGDIDR);
 	dbg.arch = BMVAL(dbgdidr, 16, 19);
-	dbg.arch_supported = dbg_arch_supported(dbg.arch);
-	if (!dbg.arch_supported) {
-		pr_info("dbg arch %u not supported\n", dbg.arch);
-		goto dbg_out;
-	}
 	dbg.nr_ctx_cmp = BMVAL(dbgdidr, 20, 23) + 1;
 	dbg.nr_bp = BMVAL(dbgdidr, 24, 27) + 1;
 	dbg.nr_wp = BMVAL(dbgdidr, 28, 31) + 1;
 
+	if (dbg_arch_supported(dbg.arch)) {
+		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER) {
+			dbg.save_restore_enabled = true;
+		} else {
+			pr_info("dbg save-restore supported by TZ\n");
+			goto dbg_out;
+		}
+	} else {
+		pr_info("dbg arch %u not supported\n", dbg.arch);
+		goto dbg_out;
+	}
+
 	/* Allocate dbg state save space */
 	dbg.state = kzalloc(MAX_DBG_STATE_SIZE * sizeof(uint32_t), GFP_KERNEL);
 	if (!dbg.state) {
@@ -1079,13 +1130,10 @@
 	isb();
 
 	/* Populate etm_ctx data */
+
 	etmidr = etm_read(ETMIDR);
 	etm.arch = BMVAL(etmidr, 4, 11);
-	etm.arch_supported = etm_arch_supported(etm.arch);
-	if (!etm.arch_supported) {
-		pr_info("etm arch %u not supported\n", etm.arch);
-		goto etm_out;
-	}
+
 	etmccr = etm_read(ETMCCR);
 	etm.nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
 	etm.nr_cntr = BMVAL(etmccr, 13, 15);
@@ -1093,6 +1141,18 @@
 	etm.nr_ext_out = BMVAL(etmccr, 20, 22);
 	etm.nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
 
+	if (etm_arch_supported(etm.arch)) {
+		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER) {
+			etm.save_restore_enabled = true;
+		} else {
+			pr_info("etm save-restore supported by TZ\n");
+			goto etm_out;
+		}
+	} else {
+		pr_info("etm arch %u not supported\n", etm.arch);
+		goto etm_out;
+	}
+
 	/* Vote for ETM power/clock disable */
 	etm_clk_disable();
 
@@ -1103,6 +1163,7 @@
 		goto etm_err;
 	}
 etm_out:
+	etm_clk_disable();
 	return 0;
 etm_err:
 	return ret;
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index 5eccf06..7775740 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -31,12 +31,10 @@
 
 #define SCM_Q6_NMI_CMD                  0x1
 #define MODULE_NAME			"lpass_8960"
-#define Q6SS_SOFT_INTR_WAKEUP		0x28800024
 
 /* Subsystem restart: QDSP6 data, functions */
 static void lpass_fatal_fn(struct work_struct *);
 static DECLARE_WORK(lpass_fatal_work, lpass_fatal_fn);
-void __iomem *q6_wakeup_intr;
 struct lpass_ssr {
 	void *lpass_ramdump_dev;
 } lpass_ssr;
@@ -118,11 +116,6 @@
 	scm_call(SCM_SVC_UTIL, SCM_Q6_NMI_CMD,
 	&cmd, sizeof(cmd), NULL, 0);
 
-	/* Wakeup the Q6 */
-	if (q6_wakeup_intr)
-		writel_relaxed(0x01, q6_wakeup_intr);
-	mb();
-
 	/* Q6 requires worstcase 100ms to dump caches etc.*/
 	mdelay(100);
 	pr_debug("%s: Q6 NMI was sent.\n", __func__);
@@ -212,9 +205,6 @@
 				__func__, ret);
 		goto out;
 	}
-	q6_wakeup_intr = ioremap_nocache(Q6SS_SOFT_INTR_WAKEUP, 8);
-	if (!q6_wakeup_intr)
-		pr_err("%s: Unable to request q6 wakeup interrupt\n", __func__);
 
 	lpass_ssr_8960.lpass_ramdump_dev = create_ramdump_device("lpass");
 
@@ -230,7 +220,6 @@
 		ret = PTR_ERR(ssr_notif_hdle);
 		pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
 			__func__, ret);
-		iounmap(q6_wakeup_intr);
 		free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 		goto out;
 	}
@@ -242,7 +231,6 @@
 		pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
 			__func__, ret);
 		subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
-		iounmap(q6_wakeup_intr);
 		free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 		goto out;
 	}
@@ -256,7 +244,6 @@
 {
 	subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
 	subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
-	iounmap(q6_wakeup_intr);
 	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 }
 
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 34bc415..e0d2696 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -47,8 +47,8 @@
 #define MDM_MODEM_DELTA		100
 
 static int mdm_debug_on;
-static int first_power_on = 1;
-static int hsic_peripheral_status = 1;
+static int power_on_count;
+static int hsic_peripheral_status;
 static DEFINE_MUTEX(hsic_status_lock);
 
 static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
@@ -77,6 +77,16 @@
 
 static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
 {
+	power_on_count++;
+
+	/* The second attempt to power-on the mdm is the first attempt
+	 * from user space, but we're already powered on. Ignore this.
+	 * Subsequent attempts are from SSR or if something failed, in
+	 * which case we must always reset the modem.
+	 */
+	if (power_on_count == 2)
+		return;
+
 	mdm_peripheral_disconnect(mdm_drv);
 
 	/* Pull RESET gpio low and wait for it to settle. */
@@ -84,7 +94,7 @@
 	gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
 	usleep_range(5000, 10000);
 
-	/* Deassert RESET first and wait for ir to settle. */
+	/* Deassert RESET first and wait for it to settle. */
 	pr_debug("%s: Pulling RESET gpio high\n", __func__);
 	gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 1);
 	usleep(1000);
@@ -93,13 +103,12 @@
 	 * the first time the mdm is powered up.
 	 * Some targets do not use ap2mdm_kpdpwr_n_gpio.
 	 */
-	if (first_power_on) {
+	if (power_on_count == 1) {
 		if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
 			pr_debug("%s: Powering on mdm modem\n", __func__);
 			gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
 			usleep(1000);
 		}
-		first_power_on = 0;
 	}
 	mdm_peripheral_connect(mdm_drv);
 
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 7445a61..a7ba4a0 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -42,6 +42,8 @@
 
 #define MDM_MODEM_TIMEOUT	6000
 #define MDM_MODEM_DELTA	100
+#define MDM_BOOT_TIMEOUT	60000L
+#define MDM_RDUMP_TIMEOUT	60000L
 
 static int mdm_debug_on;
 static struct workqueue_struct *mdm_queue;
@@ -139,11 +141,14 @@
 {
 	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
 
+	if (!mdm_drv->mdm_ready)
+		return;
+
 	mdm_drv->ops->status_cb(mdm_drv, value);
 
 	pr_debug("%s: status:%d\n", __func__, value);
 
-	if ((value == 0) && mdm_drv->mdm_ready) {
+	if ((value == 0)) {
 		pr_info("%s: unexpected reset external modem\n", __func__);
 		subsystem_restart(EXTERNAL_MODEM);
 	} else if (value == 1) {
@@ -242,11 +247,17 @@
 
 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);
-	wait_for_completion(&mdm_boot);
-	pr_info("%s: mdm modem has been restarted\n", __func__);
+	if (!wait_for_completion_timeout(&mdm_boot,
+			msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
+		mdm_drv->mdm_boot_status = -ETIMEDOUT;
+		pr_info("%s: mdm modem restart timed out.\n", __func__);
+	} else
+		pr_info("%s: mdm modem has been restarted\n", __func__);
 	INIT_COMPLETION(mdm_boot);
 	return mdm_drv->mdm_boot_status;
 }
@@ -258,7 +269,14 @@
 	if (want_dumps) {
 		mdm_drv->boot_type = CHARM_RAM_DUMPS;
 		complete(&mdm_needs_reload);
-		wait_for_completion(&mdm_ram_dumps);
+		if (!wait_for_completion_timeout(&mdm_ram_dumps,
+				msecs_to_jiffies(MDM_RDUMP_TIMEOUT))) {
+			mdm_drv->mdm_ram_dump_status = -ETIMEDOUT;
+			pr_info("%s: mdm modem ramdumps timed out.\n",
+					__func__);
+		} else
+			pr_info("%s: mdm modem ramdumps completed.\n",
+					__func__);
 		INIT_COMPLETION(mdm_ram_dumps);
 		gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
 		mdm_drv->ops->power_down_mdm_cb(mdm_drv);
@@ -503,13 +521,8 @@
 
 void mdm_common_modem_shutdown(struct platform_device *pdev)
 {
-	pr_debug("%s: setting AP2MDM_STATUS low for a graceful restart\n",
-		__func__);
-
 	mdm_disable_irqs();
 
-	gpio_set_value(mdm_drv->ap2mdm_status_gpio, 0);
-
 	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
 		gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
 
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index d26d76b..8dbf304 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -146,7 +146,7 @@
 	flush_axi_bus_buffer();
 }
 
-void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
+void * __init alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
 {
 	void *unused_addr = NULL;
 	unsigned long addr, tmp_size, unused_size;
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 6208a0d..70aaf4a 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -66,7 +66,8 @@
 }
 #endif
 
-#if defined(CONFIG_ARCH_MSM8960)
+#if (defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_MSM8930)) \
+	&& defined(CONFIG_ENABLE_DMM)
 static int rpm_change_memory_state(int retention_mask,
 					int active_mask)
 {
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 7345a89..7df1c3a 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-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
@@ -93,14 +93,6 @@
 {
 	void __iomem *q6_fw_wdog_addr;
 	void __iomem *q6_sw_wdog_addr;
-	int smsm_notif_unregistered = 0;
-
-	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
-		smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
-			smsm_state_cb, 0);
-		smsm_notif_unregistered = 1;
-		smsm_reset_modem(SMSM_RESET);
-	}
 
 	/*
 	 * Disable the modem watchdog since it keeps running even after the
@@ -127,10 +119,6 @@
 	disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
 	disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
 
-	if (smsm_notif_unregistered)
-		smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
-			smsm_state_cb, 0);
-
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
new file mode 100644
index 0000000..8ef7d61
--- /dev/null
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -0,0 +1,461 @@
+/* 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/bitops.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware/gic.h>
+#include <mach/msm_smsm.h>
+
+#define NUM_REGS_ENABLE		2
+/* (NR_MSM_IRQS/32) 96 max irqs supported */
+#define NUM_REGS_DISABLE	3
+#define GIC_IRQ_MASK(irq)	BIT(irq % 32)
+#define GIC_IRQ_INDEX(irq)	(irq / 32)
+
+#ifdef CONFIG_PM
+u32 saved_spi_enable[DIV_ROUND_UP(256, 32)];
+u32 saved_spi_conf[DIV_ROUND_UP(256, 16)];
+u32 saved_spi_target[DIV_ROUND_UP(256, 4)];
+u32 __percpu *saved_ppi_enable;
+u32 __percpu *saved_ppi_conf;
+#endif
+
+enum {
+	IRQ_DEBUG_SLEEP_INT_TRIGGER	= BIT(0),
+	IRQ_DEBUG_SLEEP_INT		= BIT(1),
+	IRQ_DEBUG_SLEEP_ABORT		= BIT(2),
+	IRQ_DEBUG_SLEEP			= BIT(3),
+	IRQ_DEBUG_SLEEP_REQUEST		= BIT(4)
+};
+
+static int msm_gic_irq_debug_mask;
+module_param_named(debug_mask, msm_gic_irq_debug_mask, int,
+		S_IRUGO | S_IWUSR | S_IWGRP);
+
+static uint32_t msm_gic_irq_smsm_wake_enable[NUM_REGS_ENABLE];
+static uint32_t msm_gic_irq_idle_disable[NUM_REGS_DISABLE];
+
+static DEFINE_RAW_SPINLOCK(gic_controller_lock);
+static void __iomem *dist_base, *cpu_base;
+static unsigned int max_irqs;
+
+ /*
+  * Some of the interrupts which will not be considered as wake capable
+  * should be marked as FAKE.
+  * Interrupts: GPIO, Timers etc..
+  */
+#define SMSM_FAKE_IRQ	(0xff)
+
+ /* msm_gic_irq_to_smsm:  IRQ's those will be monitored by Modem */
+static uint8_t msm_gic_irq_to_smsm[NR_IRQS] = {
+	[MSM8625_INT_USB_OTG]		= 4,
+	[MSM8625_INT_PWB_I2C]		= 5,
+	[MSM8625_INT_SDC1_0]		= 6,
+	[MSM8625_INT_SDC1_1]		= 7,
+	[MSM8625_INT_SDC2_0]		= 8,
+	[MSM8625_INT_SDC2_1]		= 9,
+	[MSM8625_INT_ADSP_A9_A11]	= 10,
+	[MSM8625_INT_UART1]		= 11,
+	[MSM8625_INT_UART2]		= 12,
+	[MSM8625_INT_UART3]		= 13,
+	[MSM8625_INT_UART1_RX]		= 14,
+	[MSM8625_INT_UART2_RX]		= 15,
+	[MSM8625_INT_UART3_RX]		= 16,
+	[MSM8625_INT_UART1DM_IRQ]	= 17,
+	[MSM8625_INT_UART1DM_RX]	= 18,
+	[MSM8625_INT_KEYSENSE]		= 19,
+	[MSM8625_INT_AD_HSSD]		= 20,
+	[MSM8625_INT_NAND_WR_ER_DONE]	= 21,
+	[MSM8625_INT_NAND_OP_DONE]	= 22,
+	[MSM8625_INT_TCHSCRN1]		= 23,
+	[MSM8625_INT_TCHSCRN2]		= 24,
+	[MSM8625_INT_TCHSCRN_SSBI]	= 25,
+	[MSM8625_INT_USB_HS]		= 26,
+	[MSM8625_INT_UART2DM_RX]	= 27,
+	[MSM8625_INT_UART2DM_IRQ]	= 28,
+	[MSM8625_INT_SDC4_1]		= 29,
+	[MSM8625_INT_SDC4_0]		= 30,
+	[MSM8625_INT_SDC3_1]		= 31,
+	[MSM8625_INT_SDC3_0]		= 32,
+
+	/* fake wakeup interrupts */
+	[MSM8625_INT_GPIO_GROUP1]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_GPIO_GROUP2]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_A9_M2A_0]		= SMSM_FAKE_IRQ,
+	[MSM8625_INT_A9_M2A_1]		= SMSM_FAKE_IRQ,
+	[MSM8625_INT_A9_M2A_5]		= SMSM_FAKE_IRQ,
+	[MSM8625_INT_GP_TIMER_EXP]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_DEBUG_TIMER_EXP]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_ADSP_A11]		= SMSM_FAKE_IRQ,
+};
+
+static void msm_gic_mask_irq(struct irq_data *d)
+{
+	unsigned int index = GIC_IRQ_INDEX(d->irq);
+	uint32_t mask;
+	int smsm_irq = msm_gic_irq_to_smsm[d->irq];
+
+	mask = GIC_IRQ_MASK(d->irq);
+
+	if (smsm_irq == 0) {
+		msm_gic_irq_idle_disable[index] &= ~mask;
+	} else {
+		mask = GIC_IRQ_MASK(smsm_irq - 1);
+		msm_gic_irq_smsm_wake_enable[0] &= ~mask;
+	}
+}
+
+static void msm_gic_unmask_irq(struct irq_data *d)
+{
+	unsigned int index = GIC_IRQ_INDEX(d->irq);
+	uint32_t mask;
+	int smsm_irq = msm_gic_irq_to_smsm[d->irq];
+
+	mask = GIC_IRQ_MASK(d->irq);
+
+	if (smsm_irq == 0) {
+		msm_gic_irq_idle_disable[index] |= mask;
+	} else {
+		mask = GIC_IRQ_MASK(smsm_irq - 1);
+		msm_gic_irq_smsm_wake_enable[0] |= mask;
+	}
+}
+
+static int msm_gic_set_irq_wake(struct irq_data *d, unsigned int on)
+{
+	uint32_t mask;
+	int smsm_irq = msm_gic_irq_to_smsm[d->irq];
+
+	if (smsm_irq == 0) {
+		pr_err("bad wake up irq %d\n", d->irq);
+		return  -EINVAL;
+	}
+
+	if (smsm_irq == SMSM_FAKE_IRQ)
+		return 0;
+
+	mask = GIC_IRQ_MASK(smsm_irq - 1);
+	if (on)
+		msm_gic_irq_smsm_wake_enable[1] |= mask;
+	else
+		msm_gic_irq_smsm_wake_enable[1] &= ~mask;
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static void __init msm_gic_pm_init(void)
+{
+	saved_ppi_enable =  __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
+						sizeof(u32));
+	BUG_ON(!saved_ppi_enable);
+
+	saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
+						sizeof(u32));
+	BUG_ON(!saved_ppi_conf);
+}
+#endif
+
+void msm_gic_irq_extn_init(void __iomem *db, void __iomem *cb)
+{
+	dist_base = db;
+	cpu_base = cb;
+	max_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x11f;
+	max_irqs = (max_irqs + 1) * 32;
+
+	gic_arch_extn.irq_mask	= msm_gic_mask_irq;
+	gic_arch_extn.irq_unmask = msm_gic_unmask_irq;
+	gic_arch_extn.irq_disable = msm_gic_mask_irq;
+	gic_arch_extn.irq_set_wake = msm_gic_set_irq_wake;
+
+#ifdef CONFIG_PM
+	msm_gic_pm_init();
+#endif
+}
+
+/* GIC APIs */
+
+ /*
+  * Save the GIC cpu and distributor context before PC and
+  * restor it back after coming out of PC.
+  */
+static void msm_gic_save(void)
+{
+	int i;
+	u32 *ptr;
+
+	/* Save the Per CPU PPI's */
+	ptr = __this_cpu_ptr(saved_ppi_enable);
+	/* 0 - 31 the SGI and PPI */
+	ptr[0] = readl_relaxed(dist_base +  GIC_DIST_ENABLE_SET);
+
+	ptr = __this_cpu_ptr(saved_ppi_conf);
+	for (i = 0; i < 2; i++)
+		ptr[i] =  readl_relaxed(dist_base +  GIC_DIST_CONFIG + i * 4);
+
+	/* Save the SPIs */
+	for (i = 0; (i * 16) < max_irqs; i++)
+		saved_spi_conf[i] =
+			readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+	for (i = 0; (i * 4) < max_irqs; i++)
+		saved_spi_target[i] =
+			readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
+
+	for (i = 0; (i * 32) < max_irqs; i++)
+		saved_spi_enable[i] =
+		readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+}
+
+static void msm_gic_restore(void)
+{
+	int i;
+	u32 *ptr;
+
+	/* restore CPU Interface */
+	/* Per CPU SGIs and PPIs */
+	ptr = __this_cpu_ptr(saved_ppi_enable);
+	writel_relaxed(ptr[0], dist_base + GIC_DIST_ENABLE_SET);
+
+	ptr = __this_cpu_ptr(saved_ppi_conf);
+	for (i = 0; i < 2; i++)
+		writel_relaxed(ptr[i], dist_base +  GIC_DIST_CONFIG + i * 4);
+
+	for (i = 0; (i * 4) < max_irqs; i++)
+		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
+
+	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
+	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+
+	/* restore Distributor */
+	writel_relaxed(0, dist_base + GIC_DIST_CTRL);
+
+	for (i = 0; (i * 16) < max_irqs; i++)
+		writel_relaxed(saved_spi_conf[i],
+				dist_base + GIC_DIST_CONFIG + i * 4);
+
+	for (i = 0; (i * 4) < max_irqs; i++)
+		writel_relaxed(0xa0a0a0a0,
+				dist_base + GIC_DIST_PRI + i * 4);
+
+	for (i = 0; (i * 4) < max_irqs; i++)
+		writel_relaxed(saved_spi_target[i],
+				dist_base + GIC_DIST_TARGET + i * 4);
+
+	for (i = 0; (i * 32) < max_irqs; i++)
+		writel_relaxed(saved_spi_enable[i],
+				dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+
+	mb();
+}
+
+/* Power APIs */
+
+ /*
+  *  Check for any interrupts which are enabled are pending
+  *  in the pending set or not.
+  *  Return :
+  *       0 : No pending interrupts
+  *       1 : Pending interrupts other than A9_M2A_5
+  */
+unsigned int msm_gic_spi_ppi_pending(void)
+{
+	unsigned int i, bit = 0;
+	unsigned int pending_enb = 0, pending = 0;
+	unsigned long value = 0;
+
+	raw_spin_lock(&gic_controller_lock);
+	/*
+	 * PPI and SGI to be included.
+	 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
+	 * requesting sleep triggers it
+	 */
+	for (i = 0; (i * 32) < max_irqs; i++) {
+		pending = readl_relaxed(dist_base +
+				GIC_DIST_PENDING_SET + i * 4);
+		pending_enb = readl_relaxed(dist_base +
+				GIC_DIST_ENABLE_SET + i * 4);
+		value = pending & pending_enb;
+
+		if (value) {
+			for (bit = 0; bit < 32; bit++) {
+				bit = find_next_bit(&value, 32, bit);
+				if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
+					raw_spin_unlock(&gic_controller_lock);
+					return 1;
+				}
+			}
+		}
+	}
+	raw_spin_unlock(&gic_controller_lock);
+
+	return 0;
+}
+
+ /*
+  * Iterate over the disable list
+  */
+
+int msm_gic_irq_idle_sleep_allowed(void)
+{
+	uint32_t i, disable = 0;
+
+	for (i = 0; i < NUM_REGS_DISABLE; i++)
+		disable |= msm_gic_irq_idle_disable[i];
+
+	return !disable;
+}
+
+ /*
+  * Prepare interrupt subsystem for entering sleep -- phase 1
+  * If modem_wake is true, return currently enabled interrupt
+  * mask in  *irq_mask
+  */
+void msm_gic_irq_enter_sleep1(bool modem_wake, int from_idle, uint32_t
+		*irq_mask)
+{
+	if (modem_wake) {
+		*irq_mask = msm_gic_irq_smsm_wake_enable[!from_idle];
+		if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+			pr_info("%s irq_mask %x\n", __func__, *irq_mask);
+	}
+}
+
+ /*
+  * Prepare interrupt susbsytem for entering sleep -- phase 2
+  * Detect any pending interrupts and configure interrupt hardware.
+  * Return value:
+  * -EAGAIN: there are pending interrupt(s); interrupt configuration is not
+  *		changed
+  *	  0: Success
+  */
+int msm_gic_irq_enter_sleep2(bool modem_wake, int from_idle)
+{
+	int i;
+
+	if (from_idle && !modem_wake)
+		return 0;
+
+	/* edge triggered interrupt may get lost if this mode is used */
+	WARN_ON_ONCE(!modem_wake && !from_idle);
+
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s interrupts pending\n", __func__);
+
+	/* check the pending interrupts */
+	if (msm_gic_spi_ppi_pending()) {
+		if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT)
+			pr_info("%s aborted....\n", __func__);
+		return -EAGAIN;
+	}
+
+	if (modem_wake) {
+		/* save the contents of GIC CPU interface and Distributor */
+		msm_gic_save();
+		/* Disable all the Interrupts, if we enter from idle pc */
+		if (from_idle) {
+			for (i = 0; (i * 32) < max_irqs; i++)
+				writel_relaxed(0xffffffff, dist_base
+					+ GIC_DIST_ENABLE_CLEAR + i * 4);
+		}
+		irq_set_irq_type(MSM8625_INT_A9_M2A_6, IRQF_TRIGGER_RISING);
+		enable_irq(MSM8625_INT_A9_M2A_6);
+		pr_debug("%s going for sleep now\n", __func__);
+	}
+
+	return 0;
+}
+
+ /*
+  * Restore interrupt subsystem from sleep -- phase 1
+  * Configure the interrupt hardware.
+  */
+void msm_gic_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs)
+{
+	/* Restore GIC contents, which were saved */
+	msm_gic_restore();
+
+	/* Disable A9_M2A_6 */
+	disable_irq(MSM8625_INT_A9_M2A_6);
+
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s %x %x %x now\n", __func__, irq_mask,
+				pending_irqs, wakeup_reason);
+}
+
+ /*
+  * Restore interrupt subsystem from sleep -- phase 2
+  * Poke the specified pending interrupts into interrupt hardware.
+  */
+void msm_gic_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason,
+			uint32_t pending)
+{
+	int i, smsm_irq, smsm_mask;
+	struct irq_desc *desc;
+
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s %x %x %x now\n", __func__, irq_mask,
+				 pending, wakeup_reason);
+
+	for (i = 0; pending && i < ARRAY_SIZE(msm_gic_irq_to_smsm); i++) {
+		smsm_irq = msm_gic_irq_to_smsm[i];
+
+		if (smsm_irq == 0)
+			continue;
+
+		smsm_mask = BIT(smsm_irq - 1);
+		if (!(pending & smsm_mask))
+			continue;
+
+		pending &= ~smsm_mask;
+
+		if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+			pr_info("%s, irq %d, still pending %x now\n",
+					__func__, i, pending);
+		/* Peding IRQ */
+		desc = i ? irq_to_desc(i) : NULL;
+
+		/* Check if the pending */
+		if (desc && !irqd_is_level_type(&desc->irq_data)) {
+			/* Mark the IRQ as pending, if not Level */
+			irq_set_pending(i);
+			check_irq_resend(desc, i);
+		}
+	}
+}
+
+ /*
+  * Restore interrupt subsystem from sleep -- phase 3
+  * Print debug information
+  */
+void msm_gic_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs)
+{
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s, irq_mask %x pending_irqs %x, wakeup_reason %x,"
+				"state %x now\n", __func__, irq_mask,
+				pending_irqs, wakeup_reason,
+				smsm_get_state(SMSM_MODEM_STATE));
+}
diff --git a/arch/arm/mach-msm/mpm-8625.h b/arch/arm/mach-msm/mpm-8625.h
new file mode 100644
index 0000000..4ada9e2
--- /dev/null
+++ b/arch/arm/mach-msm/mpm-8625.h
@@ -0,0 +1,30 @@
+/* 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 _ARCH_ARM_MACH_MSM_MPM_8625_H_
+#define _ARCH_ARM_MACH_MSM_MPM_8625_H_
+
+void msm_gic_irq_extn_init(void __iomem *, void __iomem *);
+
+unsigned int msm_gic_spi_ppi_pending(void);
+int msm_gic_irq_idle_sleep_allowed(void);
+void msm_gic_irq_enter_sleep1(bool modem_wake, int from_idle, uint32_t
+		*irq_mask);
+int msm_gic_irq_enter_sleep2(bool modem_wake, int from_idle);
+void msm_gic_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs);
+void msm_gic_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending);
+void msm_gic_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs);
+#endif
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
index b03e2d2..3d341e3 100644
--- a/arch/arm/mach-msm/msm-krait-l2-accessors.c
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -29,14 +29,13 @@
 
 	mb();
 	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+		      "isb\n\t"
 		      "mcr     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
-			:
+		      "isb\n\t"
+		      "mrc p15, 3, %[l2cpdr_read], c15, c0, 7\n\t"
+			: [l2cpdr_read]"=r" (ret_val)
 			: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
 	);
-	isb();
-	/* Ensure the value took */
-	asm volatile ("mrc p15, 3, %0, c15, c0, 7" : "=r" (ret_val));
-
 	raw_spin_unlock_irqrestore(&l2_access_lock, flags);
 
 	return ret_val;
@@ -53,11 +52,12 @@
 	raw_spin_lock_irqsave(&l2_access_lock, flags);
 	mb();
 	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+		      "isb\n\t"
 		      "mcr     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
+		      "isb\n\t"
 			:
 			: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
 	);
-	isb();
 	raw_spin_unlock_irqrestore(&l2_access_lock, flags);
 }
 EXPORT_SYMBOL(set_l2_indirect_reg);
@@ -72,6 +72,7 @@
 
 	raw_spin_lock_irqsave(&l2_access_lock, flags);
 	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+		      "isb\n\t"
 		      "mrc     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
 			: [l2cpdr]"=r" (val)
 			: [l2cpselr]"r" (reg_addr)
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..07082b7 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>
@@ -192,7 +195,7 @@
 		list_for_each_entry(fabnodeinfo, gateways, list) {
 		/* see if the destination is at a connected fabric */
 			if (_dst == (fabnodeinfo->info->node_info->priv_id /
-				FABRIC_ID_KEY) && !(fabdev->visited)) {
+				FABRIC_ID_KEY)) {
 				/* Found the fab on which the device exists */
 				info = fabnodeinfo->info;
 				trynextgw = false;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
index d05eaea..5a3d722 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -360,6 +360,8 @@
 		.tier = tier2,
 		.num_tiers = ARRAY_SIZE(tier2),
 		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
index 36fe156..0f37c6d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
@@ -316,6 +316,8 @@
 		.tier = tier2,
 		.num_tiers = ARRAY_SIZE(tier2),
 		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 0d265c7..7ede23d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -356,6 +356,8 @@
 		.tier = tier2,
 		.num_tiers = ARRAY_SIZE(tier2),
 		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
index 5b52cb9..34cb2db 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
@@ -184,6 +184,8 @@
 		.tier = tier2,
 		.num_tiers = ARRAY_SIZE(tier2),
 		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
 	},
 	{
 		.id = MSM_BUS_SLAVE_EBI_CH0,
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..a936e6f 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>
@@ -547,7 +550,7 @@
 	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
 		(int)ts.tv_sec, (int)ts.tv_nsec);
 
-	msm_bus_rpm_fill_cdata_buffer(&i, buf + i, MAX_BUFF_SIZE, cdata,
+	msm_bus_rpm_fill_cdata_buffer(&i, buf, MAX_BUFF_SIZE, cdata,
 		nmasters, nslaves, ntslaves);
 	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
 	mutex_lock(&msm_bus_dbg_fablist_lock);
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..64fd03e 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>
@@ -346,12 +348,12 @@
 			status = clk_set_rate(info->nodeclk[i].clk, info->
 				nodeclk[i].rate);
 			if (enable && !(info->nodeclk[i].enable)) {
-				clk_enable(info->nodeclk[i].clk);
+				clk_prepare_enable(info->nodeclk[i].clk);
 				info->nodeclk[i].dirty = false;
 				info->nodeclk[i].enable = true;
 			} else if ((info->nodeclk[i].rate == 0) && (!enable)
 				&& (info->nodeclk[i].enable)) {
-				clk_disable(info->nodeclk[i].clk);
+				clk_disable_unprepare(info->nodeclk[i].clk);
 				info->nodeclk[i].dirty = false;
 				info->nodeclk[i].enable = false;
 			}
@@ -360,12 +362,12 @@
 	if (info->memclk.dirty) {
 		status = clk_set_rate(info->memclk.clk, info->memclk.rate);
 		if (enable && !(info->memclk.enable)) {
-			clk_enable(info->memclk.clk);
+			clk_prepare_enable(info->memclk.clk);
 			info->memclk.dirty = false;
 			info->memclk.enable = true;
 		} else if (info->memclk.rate == 0 && (!enable) &&
 			(info->memclk.enable)) {
-			clk_disable(info->memclk.clk);
+			clk_disable_unprepare(info->memclk.clk);
 			info->memclk.dirty = false;
 			info->memclk.enable = false;
 		}
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_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
new file mode 100644
index 0000000..404c8f0
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -0,0 +1,144 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/memory_alloc.h>
+#include <linux/notifier.h>
+#include <mach/scm.h>
+#include <mach/msm_cache_dump.h>
+#include <mach/memory.h>
+#include <mach/msm_iomap.h>
+
+#define L2C_IMEM_ADDR 0x2a03f014
+
+static unsigned long msm_cache_dump_addr;
+
+/*
+ * These are dummy pointers so the defintion of l1_cache_dump
+ * and l2_cache_dump don't get optimized away. If they aren't
+ * referenced, the structure definitions don't show up in the
+ * debugging information which is needed for post processing.
+ */
+static struct l1_cache_dump __used *l1_dump;
+static struct l2_cache_dump __used *l2_dump;
+
+static int msm_cache_dump_panic(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC
+	scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
+	scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
+#endif
+	return 0;
+}
+
+static struct notifier_block msm_cache_dump_blk = {
+	.notifier_call  = msm_cache_dump_panic,
+	/*
+	 * higher priority to ensure this runs before another panic handler
+	 * flushes the caches.
+	 */
+	.priority = 1,
+};
+
+static int msm_cache_dump_probe(struct platform_device *pdev)
+{
+	struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
+	int ret;
+	struct {
+		unsigned long buf;
+		unsigned long size;
+	} l1_cache_data;
+#ifndef CONFIG_MSM_CACHE_DUMP_ON_PANIC
+	unsigned int *imem_loc;
+#endif
+	void *temp;
+	unsigned long total_size = d->l1_size + d->l2_size;
+
+	msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
+
+	if (!msm_cache_dump_addr) {
+		pr_err("%s: Could not get memory for cache dumping\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	temp = ioremap(msm_cache_dump_addr, total_size);
+	memset(temp, 0xFF, total_size);
+	iounmap(temp);
+
+	l1_cache_data.buf = msm_cache_dump_addr;
+	l1_cache_data.size = d->l1_size;
+
+	ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
+			&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
+
+	if (ret)
+		pr_err("%s: could not register L1 buffer ret = %d.\n",
+			__func__, ret);
+
+#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
+	l1_cache_data.buf = msm_cache_dump_addr + d->l1_size;
+	l1_cache_data.size = d->l2_size;
+
+	ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
+			&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
+
+	if (ret)
+		pr_err("%s: could not register L2 buffer ret = %d.\n",
+			__func__, ret);
+#else
+	imem_loc = ioremap(L2C_IMEM_ADDR, SZ_4K);
+	__raw_writel(msm_cache_dump_addr + d->l1_size, imem_loc);
+	iounmap(imem_loc);
+#endif
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+						&msm_cache_dump_blk);
+	return 0;
+}
+
+static int msm_cache_dump_remove(struct platform_device *pdev)
+{
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+					&msm_cache_dump_blk);
+	return 0;
+}
+
+static struct platform_driver msm_cache_dump_driver = {
+	.remove		= __devexit_p(msm_cache_dump_remove),
+	.driver         = {
+		.name = "msm_cache_dump",
+		.owner = THIS_MODULE
+	},
+};
+
+static int __init msm_cache_dump_init(void)
+{
+	return platform_driver_probe(&msm_cache_dump_driver,
+					msm_cache_dump_probe);
+}
+
+static void __exit msm_cache_dump_exit(void)
+{
+	platform_driver_unregister(&msm_cache_dump_driver);
+}
+late_initcall(msm_cache_dump_init);
+module_exit(msm_cache_dump_exit)
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
new file mode 100644
index 0000000..c547d8c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -0,0 +1,778 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stringify.h>
+#include <linux/debugfs.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <mach/msm_dcvs.h>
+
+#define CORE_HANDLE_OFFSET (0xA0)
+#define __err(f, ...) pr_err("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
+#define __info(f, ...) pr_info("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
+#define MAX_PENDING	(5)
+
+enum {
+	MSM_DCVS_DEBUG_NOTIFIER    = BIT(0),
+	MSM_DCVS_DEBUG_IDLE_PULSE  = BIT(1),
+	MSM_DCVS_DEBUG_FREQ_CHANGE = BIT(2),
+};
+
+struct core_attribs {
+	struct kobj_attribute idle_enabled;
+	struct kobj_attribute freq_change_enabled;
+	struct kobj_attribute actual_freq;
+	struct kobj_attribute freq_change_us;
+
+	struct kobj_attribute max_time_us;
+
+	struct kobj_attribute slack_time_us;
+	struct kobj_attribute scale_slack_time;
+	struct kobj_attribute scale_slack_time_pct;
+	struct kobj_attribute disable_pc_threshold;
+	struct kobj_attribute em_window_size;
+	struct kobj_attribute em_max_util_pct;
+	struct kobj_attribute ss_window_size;
+	struct kobj_attribute ss_util_pct;
+	struct kobj_attribute ss_iobusy_conv;
+
+	struct attribute_group attrib_group;
+};
+
+struct dcvs_core {
+	char core_name[CORE_NAME_MAX];
+	uint32_t new_freq[MAX_PENDING];
+	uint32_t actual_freq;
+	uint32_t freq_change_us;
+
+	uint32_t max_time_us; /* core param */
+
+	struct msm_dcvs_algo_param algo_param;
+	struct msm_dcvs_idle *idle_driver;
+	struct msm_dcvs_freq *freq_driver;
+
+	/* private */
+	int64_t time_start;
+	struct mutex lock;
+	spinlock_t cpu_lock;
+	struct task_struct *task;
+	struct core_attribs attrib;
+	uint32_t handle;
+	uint32_t group_id;
+	uint32_t freq_pending;
+	struct hrtimer timer;
+	int32_t core_slack_time_us;
+	int32_t timer_disabled;
+};
+
+static int msm_dcvs_debug;
+static int msm_dcvs_enabled = 1;
+module_param_named(enable, msm_dcvs_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static struct dentry *debugfs_base;
+
+static struct dcvs_core core_list[CORES_MAX];
+static DEFINE_MUTEX(core_list_lock);
+
+static struct kobject *cores_kobj;
+static struct dcvs_core *core_handles[CORES_MAX];
+
+/* Change core frequency, called with core mutex locked */
+static int __msm_dcvs_change_freq(struct dcvs_core *core)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+	unsigned int requested_freq = 0;
+	unsigned int prev_freq = 0;
+	int64_t time_start = 0;
+	int64_t time_end = 0;
+	uint32_t slack_us = 0;
+	uint32_t ret1 = 0;
+
+	if (!core->freq_driver || !core->freq_driver->set_frequency) {
+		/* Core may have unregistered or hotplugged */
+		return -ENODEV;
+	}
+repeat:
+	spin_lock_irqsave(&core->cpu_lock, flags);
+	if (unlikely(!core->freq_pending)) {
+		spin_unlock_irqrestore(&core->cpu_lock, flags);
+		return ret;
+	}
+	requested_freq = core->new_freq[core->freq_pending - 1];
+	if (unlikely(core->freq_pending > 1) &&
+		(msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)) {
+		int i;
+		for (i = 0; i < core->freq_pending - 1; i++) {
+			__info("Core %s missing freq %u\n",
+				core->core_name, core->new_freq[i]);
+		}
+	}
+	time_start = core->time_start;
+	core->time_start = 0;
+	core->freq_pending = 0;
+	/**
+	 * Cancel the timers, we dont want the timer firing as we are
+	 * changing the clock rate. Dont let idle_exit and others setup
+	 * timers as well.
+	 */
+	hrtimer_cancel(&core->timer);
+	core->timer_disabled = 1;
+	spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+	if (requested_freq == core->actual_freq)
+		return ret;
+
+	/**
+	 * Call the frequency sink driver to change the frequency
+	 * We will need to get back the actual frequency in KHz and
+	 * the record the time taken to change it.
+	 */
+	ret = core->freq_driver->set_frequency(core->freq_driver,
+				requested_freq);
+	if (ret <= 0) {
+		__err("Core %s failed to set freq %u\n",
+				core->core_name, requested_freq);
+		/* Restart the timers at the current slack time */
+		core->timer_disabled = 0;
+		ret = hrtimer_start(&core->timer,
+			ktime_set(0, core->core_slack_time_us * 1000),
+				HRTIMER_MODE_REL_PINNED);
+			if (ret)
+				__err("Failed to register timer for core %s\n",
+						core->core_name);
+		return -EFAULT;
+	}
+
+	prev_freq = core->actual_freq;
+	core->actual_freq = ret;
+	time_end = ktime_to_ns(ktime_get());
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
+		__info("Core %s Time end %llu Time start: %llu\n",
+			core->core_name, time_end, time_start);
+	time_end -= time_start;
+	do_div(time_end, NSEC_PER_USEC);
+	core->freq_change_us = (uint32_t)time_end;
+
+	/**
+	 * Disable low power modes if the actual frequency is >
+	 * disable_pc_threshold.
+	 */
+	if (core->actual_freq >
+			core->algo_param.disable_pc_threshold) {
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
+		if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+			__info("Disabling LPM for %s\n", core->core_name);
+	} else if (core->actual_freq <=
+			core->algo_param.disable_pc_threshold) {
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+		if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+			__info("Enabling LPM for %s\n", core->core_name);
+	}
+
+	/**
+	 * Update algorithm with new freq and time taken to change
+	 * to this frequency and that will get us the new slack
+	 * timer
+	 */
+	ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
+		core->actual_freq, (uint32_t)time_end, &slack_us, &ret1);
+	if (!ret) {
+		/* Reset the slack timer */
+		core->core_slack_time_us = slack_us;
+		if (slack_us) {
+			core->timer_disabled = 0;
+			ret = hrtimer_start(&core->timer,
+				ktime_set(0, slack_us * 1000),
+				HRTIMER_MODE_REL_PINNED);
+			if (ret)
+				__err("Failed to register timer for core %s\n",
+						core->core_name);
+		}
+	} else {
+		__err("Error sending core (%s) freq change (%u)\n",
+				core->core_name, core->actual_freq);
+	}
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
+		__info("Freq %u requested for core %s (actual %u prev %u) "
+			"change time %u us slack time %u us\n",
+			requested_freq, core->core_name,
+			core->actual_freq, prev_freq,
+			core->freq_change_us, core->core_slack_time_us);
+
+	/**
+	 * By the time we are done with freq changes, we could be asked to
+	 * change again. Check before exiting.
+	 */
+	if (core->freq_pending)
+		goto repeat;
+
+	return ret;
+}
+
+static int msm_dcvs_do_freq(void *data)
+{
+	struct dcvs_core *core = (struct dcvs_core *)data;
+	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
+
+	sched_setscheduler(current, SCHED_FIFO, &param);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+
+	while (!kthread_should_stop()) {
+		mutex_lock(&core->lock);
+		__msm_dcvs_change_freq(core);
+		mutex_unlock(&core->lock);
+
+		schedule();
+
+		if (kthread_should_stop())
+			break;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+	}
+
+	__set_current_state(TASK_RUNNING);
+
+	return 0;
+}
+
+static int msm_dcvs_update_freq(struct dcvs_core *core,
+		enum msm_dcvs_scm_event event, uint32_t param0)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+	uint32_t new_freq = 0;
+	uint32_t ret1 = 0;
+
+	spin_lock_irqsave(&core->cpu_lock, flags);
+	ret = msm_dcvs_scm_event(core->handle, event, param0,
+				core->actual_freq, &new_freq, &ret1);
+
+	if (ret) {
+		__err("Error (%d) sending SCM event %d for core %s\n",
+				ret, event, core->core_name);
+		goto freq_done;
+	}
+
+	if ((core->actual_freq != new_freq) &&
+			(core->new_freq[core->freq_pending] != new_freq)) {
+		if (core->freq_pending >= MAX_PENDING - 1)
+			core->freq_pending = MAX_PENDING - 1;
+		core->new_freq[core->freq_pending++] = new_freq;
+		core->time_start = ktime_to_ns(ktime_get());
+
+		/* Schedule the frequency change */
+		if (!core->task)
+			__err("Uninitialized task for core %s\n",
+					core->core_name);
+		else
+			wake_up_process(core->task);
+	}
+freq_done:
+	spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+	return ret;
+}
+
+static enum hrtimer_restart msm_dcvs_core_slack_timer(struct hrtimer *timer)
+{
+	int ret = 0;
+	struct dcvs_core *core = container_of(timer, struct dcvs_core, timer);
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
+		__info("Slack timer fired for core %s\n", core->core_name);
+
+	/**
+	 * Timer expired, notify TZ
+	 * Dont care about the third arg.
+	 */
+	ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_QOS_TIMER_EXPIRED, 0);
+	if (ret)
+		__err("Timer expired for core %s but failed to notify.\n",
+				core->core_name);
+
+	return HRTIMER_NORESTART;
+}
+
+/* Helper functions and macros for sysfs nodes for a core */
+#define CORE_FROM_ATTRIBS(attr, name) \
+	container_of(container_of(attr, struct core_attribs, name), \
+		struct dcvs_core, attrib);
+
+#define DCVS_PARAM_SHOW(_name, v) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj, \
+		struct kobj_attribute *attr, char *buf) \
+{ \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	return snprintf(buf, PAGE_SIZE, "%d\n", v); \
+}
+
+#define DCVS_ALGO_PARAM(_name) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
+		struct kobj_attribute *attr, char *buf) \
+{ \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	return snprintf(buf, PAGE_SIZE, "%d\n", core->algo_param._name); \
+} \
+static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
+		struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+	int ret = 0; \
+	uint32_t val = 0; \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	mutex_lock(&core->lock); \
+	ret = kstrtouint(buf, 10, &val); \
+	if (ret) { \
+		__err("Invalid input %s for %s\n", buf, __stringify(_name));\
+	} else { \
+		uint32_t old_val = core->algo_param._name; \
+		core->algo_param._name = val; \
+		ret = msm_dcvs_scm_set_algo_params(core->handle, \
+				&core->algo_param); \
+		if (ret) { \
+			core->algo_param._name = old_val; \
+			__err("Error(%d) in setting %d for algo param %s\n",\
+					ret, val, __stringify(_name)); \
+		} \
+	} \
+	mutex_unlock(&core->lock); \
+	return count; \
+}
+
+#define DCVS_RO_ATTRIB(i, _name) \
+	core->attrib._name.attr.name = __stringify(_name); \
+	core->attrib._name.attr.mode = S_IRUGO; \
+	core->attrib._name.show = msm_dcvs_attr_##_name##_show; \
+	core->attrib._name.store = NULL; \
+	core->attrib.attrib_group.attrs[i] = &core->attrib._name.attr;
+
+#define DCVS_RW_ATTRIB(i, _name) \
+	core->attrib._name.attr.name = __stringify(_name); \
+	core->attrib._name.attr.mode = S_IRUGO | S_IWUSR; \
+	core->attrib._name.show = msm_dcvs_attr_##_name##_show; \
+	core->attrib._name.store = msm_dcvs_attr_##_name##_store; \
+	core->attrib.attrib_group.attrs[i] = &core->attrib._name.attr;
+
+/**
+ * Function declarations for different attributes.
+ * Gets used when setting the attribute show and store parameters.
+ */
+DCVS_PARAM_SHOW(idle_enabled, (core->idle_driver != NULL))
+DCVS_PARAM_SHOW(freq_change_enabled, (core->freq_driver != NULL))
+DCVS_PARAM_SHOW(actual_freq, (core->actual_freq))
+DCVS_PARAM_SHOW(freq_change_us, (core->freq_change_us))
+DCVS_PARAM_SHOW(max_time_us, (core->max_time_us))
+
+DCVS_ALGO_PARAM(slack_time_us)
+DCVS_ALGO_PARAM(scale_slack_time)
+DCVS_ALGO_PARAM(scale_slack_time_pct)
+DCVS_ALGO_PARAM(disable_pc_threshold)
+DCVS_ALGO_PARAM(em_window_size)
+DCVS_ALGO_PARAM(em_max_util_pct)
+DCVS_ALGO_PARAM(ss_window_size)
+DCVS_ALGO_PARAM(ss_util_pct)
+DCVS_ALGO_PARAM(ss_iobusy_conv)
+
+static int msm_dcvs_setup_core_sysfs(struct dcvs_core *core)
+{
+	int ret = 0;
+	struct kobject *core_kobj = NULL;
+	const int attr_count = 15;
+
+	BUG_ON(!cores_kobj);
+
+	core->attrib.attrib_group.attrs =
+		kzalloc(attr_count * sizeof(struct attribute *), GFP_KERNEL);
+
+	if (!core->attrib.attrib_group.attrs) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	DCVS_RO_ATTRIB(0, idle_enabled);
+	DCVS_RO_ATTRIB(1, freq_change_enabled);
+	DCVS_RO_ATTRIB(2, actual_freq);
+	DCVS_RO_ATTRIB(3, freq_change_us);
+	DCVS_RO_ATTRIB(4, max_time_us);
+
+	DCVS_RW_ATTRIB(5, slack_time_us);
+	DCVS_RW_ATTRIB(6, scale_slack_time);
+	DCVS_RW_ATTRIB(7, scale_slack_time_pct);
+	DCVS_RW_ATTRIB(8, disable_pc_threshold);
+	DCVS_RW_ATTRIB(9, em_window_size);
+	DCVS_RW_ATTRIB(10, em_max_util_pct);
+	DCVS_RW_ATTRIB(11, ss_window_size);
+	DCVS_RW_ATTRIB(12, ss_util_pct);
+	DCVS_RW_ATTRIB(13, ss_iobusy_conv);
+
+	core->attrib.attrib_group.attrs[14] = NULL;
+
+	core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
+	if (!core_kobj) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	ret = sysfs_create_group(core_kobj, &core->attrib.attrib_group);
+	if (ret)
+		__err("Cannot create core %s attr group\n", core->core_name);
+	else if (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER)
+		__info("Setting up attributes for core %s\n", core->core_name);
+
+done:
+	if (ret) {
+		kfree(core->attrib.attrib_group.attrs);
+		kobject_del(core_kobj);
+	}
+
+	return ret;
+}
+
+/* Return the core if found or add to list if @add_to_list is true */
+static struct dcvs_core *msm_dcvs_get_core(const char *name, int add_to_list)
+{
+	struct dcvs_core *core = NULL;
+	int i;
+	int empty = -1;
+
+	if (!name[0] ||
+		(strnlen(name, CORE_NAME_MAX - 1) == CORE_NAME_MAX - 1))
+		return core;
+
+	mutex_lock(&core_list_lock);
+	for (i = 0; i < CORES_MAX; i++) {
+		core = &core_list[i];
+		if ((empty < 0) && !core->core_name[0]) {
+			empty = i;
+			continue;
+		}
+		if (!strncmp(name, core->core_name, CORE_NAME_MAX))
+			break;
+	}
+
+	/* Check for core_list full */
+	if ((i == CORES_MAX) && (empty < 0)) {
+		mutex_unlock(&core_list_lock);
+		return NULL;
+	}
+
+	if (i == CORES_MAX && add_to_list) {
+		core = &core_list[empty];
+		strlcpy(core->core_name, name, CORE_NAME_MAX);
+		mutex_init(&core->lock);
+		spin_lock_init(&core->cpu_lock);
+		core->handle = empty + CORE_HANDLE_OFFSET;
+		hrtimer_init(&core->timer,
+				CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+		core->timer.function = msm_dcvs_core_slack_timer;
+	}
+	mutex_unlock(&core_list_lock);
+
+	return core;
+}
+
+int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
+		struct msm_dcvs_core_info *info)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!core_name || !core_name[0])
+		return ret;
+
+	core = msm_dcvs_get_core(core_name, true);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (group_id) {
+		/**
+		 * Create a group for cores, if this core is part of a group
+		 * if the group_id is 0, the core is not part of a group.
+		 * If the group_id already exits, it will through an error
+		 * which we will ignore.
+		 */
+		ret = msm_dcvs_scm_create_group(group_id);
+		if (ret == -ENOMEM)
+			goto bail;
+	}
+	core->group_id = group_id;
+
+	core->max_time_us = info->core_param.max_time_us;
+	memcpy(&core->algo_param, &info->algo_param,
+			sizeof(struct msm_dcvs_algo_param));
+
+	ret = msm_dcvs_scm_register_core(core->handle, group_id,
+			&info->core_param, info->freq_tbl);
+	if (ret)
+		goto bail;
+
+	ret = msm_dcvs_scm_set_algo_params(core->handle, &info->algo_param);
+	if (ret)
+		goto bail;
+
+	ret = msm_dcvs_setup_core_sysfs(core);
+	if (ret) {
+		__err("Unable to setup core %s sysfs\n", core->core_name);
+		core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
+		goto bail;
+	}
+
+bail:
+	mutex_unlock(&core->lock);
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_register_core);
+
+int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, true);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (core->freq_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
+		__info("Frequency notifier for %s being replaced\n",
+				core->core_name);
+	core->freq_driver = drv;
+	core->task = kthread_create(msm_dcvs_do_freq, (void *)core,
+			"msm_dcvs/%d", core->handle);
+	if (IS_ERR(core->task)) {
+		mutex_unlock(&core->lock);
+		return -EFAULT;
+	}
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+		__info("Enabling idle pulse for %s\n", core->core_name);
+
+	if (core->idle_driver) {
+		core->actual_freq = core->freq_driver->get_frequency(drv);
+		/* Notify TZ to start receiving idle info for the core */
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 1);
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_ENABLE_IDLE_PULSE);
+	}
+
+	mutex_unlock(&core->lock);
+
+	return core->handle;
+}
+EXPORT_SYMBOL(msm_dcvs_freq_sink_register);
+
+int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, false);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+		__info("Disabling idle pulse for %s\n", core->core_name);
+	if (core->idle_driver) {
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_DISABLE_IDLE_PULSE);
+		/* Notify TZ to stop receiving idle info for the core */
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 0);
+		hrtimer_cancel(&core->timer);
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+		if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+			__info("Enabling LPM for %s\n", core->core_name);
+	}
+	core->freq_pending = 0;
+	core->freq_driver = NULL;
+	mutex_unlock(&core->lock);
+	kthread_stop(core->task);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_dcvs_freq_sink_unregister);
+
+int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, true);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (core->idle_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
+		__info("Idle notifier for %s being replaced\n",
+				core->core_name);
+	core->idle_driver = drv;
+	mutex_unlock(&core->lock);
+
+	return core->handle;
+}
+EXPORT_SYMBOL(msm_dcvs_idle_source_register);
+
+int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, false);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	core->idle_driver = NULL;
+	mutex_unlock(&core->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_dcvs_idle_source_unregister);
+
+int msm_dcvs_idle(int handle, enum msm_core_idle_state state, uint32_t iowaited)
+{
+	int ret = 0;
+	struct dcvs_core *core = NULL;
+	int64_t timer_interval_us = 0;
+	uint32_t r0, r1;
+
+	if (handle >= CORE_HANDLE_OFFSET &&
+			(handle - CORE_HANDLE_OFFSET) < CORES_MAX)
+		core = &core_list[handle - CORE_HANDLE_OFFSET];
+
+	BUG_ON(!core);
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+		__info("Core %s idle state %d\n", core->core_name, state);
+
+	switch (state) {
+	case MSM_DCVS_IDLE_ENTER:
+		hrtimer_cancel(&core->timer);
+		ret = msm_dcvs_scm_event(core->handle,
+				MSM_DCVS_SCM_IDLE_ENTER, 0, 0, &r0, &r1);
+		if (ret)
+			__err("Error (%d) sending idle enter for %s\n",
+					ret, core->core_name);
+		break;
+
+	case MSM_DCVS_IDLE_EXIT:
+		hrtimer_cancel(&core->timer);
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_IDLE_EXIT,
+				iowaited);
+		if (ret)
+			__err("Error (%d) sending idle exit for %s\n",
+					ret, core->core_name);
+		timer_interval_us = core->core_slack_time_us;
+		if (timer_interval_us && !core->timer_disabled) {
+			ret = hrtimer_start(&core->timer,
+				ktime_set(0, timer_interval_us * 1000),
+				HRTIMER_MODE_REL_PINNED);
+			if (ret)
+				__err("Failed to register timer for core %s\n",
+						core->core_name);
+		}
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_idle);
+
+static int __init msm_dcvs_late_init(void)
+{
+	struct kobject *module_kobj = NULL;
+	int ret = 0;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+				__func__, KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto err;
+	}
+
+	cores_kobj = kobject_create_and_add("cores", module_kobj);
+	if (!cores_kobj) {
+		__err("Cannot create %s kobject\n", "cores");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	debugfs_base = debugfs_create_dir("msm_dcvs", NULL);
+	if (!debugfs_base) {
+		__err("Cannot create debugfs base %s\n", "msm_dcvs");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	if (!debugfs_create_u32("debug_mask", S_IRUGO | S_IWUSR,
+				debugfs_base, &msm_dcvs_debug)) {
+		__err("Cannot create debugfs entry %s\n", "debug_mask");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+err:
+	if (ret) {
+		kobject_del(cores_kobj);
+		cores_kobj = NULL;
+		debugfs_remove(debugfs_base);
+	}
+
+	return ret;
+}
+late_initcall(msm_dcvs_late_init);
+
+static int __init msm_dcvs_early_init(void)
+{
+	int ret = 0;
+
+	if (!msm_dcvs_enabled) {
+		__info("Not enabled (%d)\n", msm_dcvs_enabled);
+		return 0;
+	}
+
+	ret = msm_dcvs_scm_init(10 * 1024);
+	if (ret)
+		__err("Unable to initialize DCVS err=%d\n", ret);
+
+	return ret;
+}
+postcore_initcall(msm_dcvs_early_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_idle.c b/arch/arm/mach-msm/msm_dcvs_idle.c
new file mode 100644
index 0000000..59f2742
--- /dev/null
+++ b/arch/arm/mach-msm/msm_dcvs_idle.c
@@ -0,0 +1,170 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/cpu_pm.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos_params.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <mach/msm_dcvs.h>
+
+struct cpu_idle_info {
+	int cpu;
+	int enabled;
+	int handle;
+	struct msm_dcvs_idle dcvs_notifier;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info);
+static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu);
+static char core_name[NR_CPUS][10];
+static struct pm_qos_request_list qos_req;
+static uint32_t latency;
+
+static int msm_dcvs_idle_notifier(struct msm_dcvs_idle *self,
+		enum msm_core_control_event event)
+{
+	struct cpu_idle_info *info = container_of(self,
+				struct cpu_idle_info, dcvs_notifier);
+
+	switch (event) {
+	case MSM_DCVS_ENABLE_IDLE_PULSE:
+		info->enabled = true;
+		break;
+
+	case MSM_DCVS_DISABLE_IDLE_PULSE:
+		info->enabled = false;
+		break;
+
+	case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
+		pm_qos_update_request(&qos_req, PM_QOS_DEFAULT_VALUE);
+		break;
+
+	case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
+		pm_qos_update_request(&qos_req, latency);
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
+		void *v)
+{
+	struct cpu_idle_info *info =
+		&per_cpu(cpu_idle_info, smp_processor_id());
+	u64 io_wait_us = 0;
+	u64 prev_io_wait_us = 0;
+	u64 last_update_time = 0;
+	u64 val = 0;
+	uint32_t iowaited = 0;
+
+	if (!info->enabled)
+		return NOTIFY_OK;
+
+	switch (cmd) {
+	case CPU_PM_ENTER:
+		val = get_cpu_iowait_time_us(smp_processor_id(),
+					&last_update_time);
+		/* val could be -1 when NOHZ is not enabled */
+		if (val == (u64)-1)
+			val = 0;
+		per_cpu(iowait_on_cpu, smp_processor_id()) = val;
+		msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_ENTER, 0);
+		break;
+
+	case CPU_PM_ENTER_FAILED:
+	case CPU_PM_EXIT:
+		prev_io_wait_us = per_cpu(iowait_on_cpu, smp_processor_id());
+		val = get_cpu_iowait_time_us(smp_processor_id(),
+				&last_update_time);
+		if (val == (u64)-1)
+			val = 0;
+		io_wait_us = val;
+		iowaited = (io_wait_us - prev_io_wait_us);
+		msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_EXIT, iowaited);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block idle_nb = {
+	.notifier_call = msm_cpuidle_notifier,
+};
+
+static int msm_dcvs_idle_probe(struct platform_device *pdev)
+{
+	int cpu;
+	struct cpu_idle_info *info = NULL;
+	struct msm_dcvs_idle *inotify = NULL;
+
+	for_each_possible_cpu(cpu) {
+		info = &per_cpu(cpu_idle_info, cpu);
+		info->cpu = cpu;
+		inotify = &info->dcvs_notifier;
+		snprintf(core_name[cpu], 10, "cpu%d", cpu);
+		inotify->core_name = core_name[cpu];
+		inotify->enable = msm_dcvs_idle_notifier;
+		info->handle = msm_dcvs_idle_source_register(inotify);
+		BUG_ON(info->handle < 0);
+	}
+
+	latency = *((uint32_t *)pdev->dev.platform_data);
+	pm_qos_add_request(&qos_req, PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
+	return cpu_pm_register_notifier(&idle_nb);
+}
+
+static int msm_dcvs_idle_remove(struct platform_device *pdev)
+{
+	int ret = 0;
+	int rc = 0;
+	int cpu = 0;
+	struct msm_dcvs_idle *inotify = NULL;
+	struct cpu_idle_info *info = NULL;
+
+	rc = cpu_pm_unregister_notifier(&idle_nb);
+
+	for_each_possible_cpu(cpu) {
+		info = &per_cpu(cpu_idle_info, cpu);
+		inotify = &info->dcvs_notifier;
+		ret = msm_dcvs_idle_source_unregister(inotify);
+		if (ret) {
+			rc = -EFAULT;
+			pr_err("Error de-registering core %d idle notifier.\n",
+					cpu);
+		}
+	}
+
+	return rc;
+}
+
+static struct platform_driver idle_pdrv = {
+	.probe = msm_dcvs_idle_probe,
+	.remove = __devexit_p(msm_dcvs_idle_remove),
+	.driver = {
+		.name  = "msm_cpu_idle",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int msm_dcvs_idle_init(void)
+{
+	return platform_driver_register(&idle_pdrv);
+}
+late_initcall(msm_dcvs_idle_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c
new file mode 100644
index 0000000..6095e0813
--- /dev/null
+++ b/arch/arm/mach-msm/msm_dcvs_scm.c
@@ -0,0 +1,161 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/memory_alloc.h>
+#include <mach/memory.h>
+#include <mach/scm.h>
+#include <mach/msm_dcvs_scm.h>
+
+#define DCVS_CMD_CREATE_GROUP		1
+#define DCVS_CMD_REGISTER_CORE		2
+#define DCVS_CMD_SET_ALGO_PARAM		3
+#define DCVS_CMD_EVENT			4
+#define DCVS_CMD_INIT			5
+
+struct scm_register_core {
+	uint32_t core_id;
+	uint32_t group_id;
+	phys_addr_t core_param_phy;
+	phys_addr_t freq_phy;
+};
+
+struct scm_algo {
+	uint32_t core_id;
+	phys_addr_t algo_phy;
+};
+
+struct scm_init {
+	uint32_t phy;
+	uint32_t size;
+};
+
+int msm_dcvs_scm_init(size_t size)
+{
+	int ret = 0;
+	struct scm_init init;
+	uint32_t p = 0;
+
+	/* Allocate word aligned non-cacheable memory */
+	p = allocate_contiguous_ebi_nomap(size, 4);
+	if (!p)
+		return -ENOMEM;
+
+	init.phy = p;
+	init.size = size;
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_INIT,
+			&init, sizeof(init), NULL, 0);
+
+	/* Not freed if the initialization succeeds */
+	if (ret)
+		free_contiguous_memory_by_paddr(p);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_init);
+
+int msm_dcvs_scm_create_group(uint32_t id)
+{
+	int ret = 0;
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_CREATE_GROUP,
+			&id, sizeof(uint32_t), NULL, 0);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_create_group);
+
+int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
+		struct msm_dcvs_core_param *param,
+		struct msm_dcvs_freq_entry *freq)
+{
+	int ret = 0;
+	struct scm_register_core reg_data;
+	struct msm_dcvs_core_param *p = NULL;
+	struct msm_dcvs_freq_entry *f = NULL;
+
+	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_core_param)), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	f = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_freq_entry) *
+				param->num_freq), GFP_KERNEL);
+	if (!f) {
+		kfree(p);
+		return -ENOMEM;
+	}
+
+	memcpy(p, param, sizeof(struct msm_dcvs_core_param));
+	memcpy(f, freq, sizeof(struct msm_dcvs_freq_entry) * param->num_freq);
+
+	reg_data.core_id = core_id;
+	reg_data.group_id = group_id;
+	reg_data.core_param_phy = virt_to_phys(p);
+	reg_data.freq_phy = virt_to_phys(f);
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_REGISTER_CORE,
+			&reg_data, sizeof(reg_data), NULL, 0);
+
+	kfree(f);
+	kfree(p);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_register_core);
+
+int msm_dcvs_scm_set_algo_params(uint32_t core_id,
+		struct msm_dcvs_algo_param *param)
+{
+	int ret = 0;
+	struct scm_algo algo;
+	struct msm_dcvs_algo_param *p = NULL;
+
+	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_algo_param)), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	memcpy(p, param, sizeof(struct msm_dcvs_algo_param));
+
+	algo.core_id = core_id;
+	algo.algo_phy = virt_to_phys(p);
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
+			&algo, sizeof(algo), NULL, 0);
+
+	kfree(p);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_set_algo_params);
+
+int msm_dcvs_scm_event(uint32_t core_id,
+		enum msm_dcvs_scm_event event_id,
+		uint32_t param0, uint32_t param1,
+		uint32_t *ret0, uint32_t *ret1)
+{
+	int ret = -EINVAL;
+
+	if (!ret0 || !ret1)
+		return ret;
+
+	ret = scm_call_atomic4_3(SCM_SVC_DCVS, DCVS_CMD_EVENT,
+			core_id, event_id, param0, param1, ret0, ret1);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_event);
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index efb2bf6..057665b 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -39,7 +39,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 
-#include <timer.h>
+#include "timer.h"
 
 #define DRV_NAME	"msm_dsps"
 #define DRV_VERSION	"3.02"
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index 492612f..9d14d56 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/rq_stats.h>
+#include <asm/smp_plat.h>
 
 #define MAX_LONG_SIZE 24
 #define DEFAULT_RQ_POLL_JIFFIES 1
@@ -197,6 +198,12 @@
 {
 	int ret;
 
+	/* Bail out if this is not an SMP Target */
+	if (!is_smp()) {
+		rq_info.init = 0;
+		return -ENOSYS;
+	}
+
 	rq_wq = create_singlethread_workqueue("rq_stats");
 	BUG_ON(!rq_wq);
 	INIT_WORK(&rq_info.def_timer_work, def_work_fn);
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index 6e79dfe..3f56d1a 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -54,6 +54,7 @@
 	int nentries;
 	int size;
 	int enabled;
+	int initialized;
 	uint32_t filter;
 	int step_size;
 };
@@ -66,6 +67,7 @@
 
 struct msm_rtb_state msm_rtb = {
 	.filter = 1 << LOGK_LOGBUF,
+	.enabled = 1,
 };
 
 module_param_named(filter, msm_rtb.filter, uint, 0644);
@@ -73,7 +75,7 @@
 
 int msm_rtb_event_should_log(enum logk_event_type log_type)
 {
-	return msm_rtb.enabled &&
+	return msm_rtb.initialized && msm_rtb.enabled &&
 		((1 << log_type) & msm_rtb.filter);
 }
 EXPORT_SYMBOL(msm_rtb_event_should_log);
@@ -217,7 +219,7 @@
 #endif
 
 
-	msm_rtb.enabled = 1;
+	msm_rtb.initialized = 1;
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 5bff832..aabb644 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -23,6 +23,8 @@
 #include <linux/suspend.h>
 #include <linux/percpu.h>
 #include <linux/interrupt.h>
+#include <asm/fiq.h>
+#include <asm/hardware/gic.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
 #include <mach/scm.h>
@@ -42,11 +44,14 @@
 
 #define WDT_HZ		32768
 
+struct msm_watchdog_dump msm_dump_cpu_ctx;
+
 static void __iomem *msm_tmr0_base;
 
 static unsigned long delay_time;
 static unsigned long bark_time;
 static unsigned long long last_pet;
+static bool has_vic;
 
 /*
  * On the kernel command line specify
@@ -77,6 +82,8 @@
 static int appsbark;
 module_param(appsbark, int, 0);
 
+static int appsbark_fiq;
+
 /*
  * Use /sys/module/msm_watchdog/parameters/print_all_stacks
  * to control whether stacks of all running
@@ -95,6 +102,13 @@
 static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
 static DECLARE_WORK(init_dogwork_struct, init_watchdog_work);
 
+/* Called from the FIQ bark handler */
+void msm_wdog_bark_fin(void)
+{
+	pr_crit("\nApps Watchdog bark received - Calling Panic\n");
+	panic("Apps Watchdog Bark received\n");
+}
+
 static int msm_watchdog_suspend(struct device *dev)
 {
 	if (!enable)
@@ -161,9 +175,16 @@
 		if (!old_val) {
 			__raw_writel(0, msm_tmr0_base + WDT0_EN);
 			mb();
-			disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
-			free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
-			free_percpu(percpu_pdata);
+			if (has_vic) {
+				free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+			} else {
+				disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+				if (!appsbark_fiq) {
+					free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+							percpu_pdata);
+					free_percpu(percpu_pdata);
+				}
+			}
 			enable = 0;
 			atomic_notifier_chain_unregister(&panic_notifier_list,
 			       &panic_blk);
@@ -221,9 +242,16 @@
 	if (enable) {
 		__raw_writel(0, msm_tmr0_base + WDT0_EN);
 		mb();
-		disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
-		free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
-		free_percpu(percpu_pdata);
+		if (has_vic) {
+			free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+		} else {
+			disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+			if (!appsbark_fiq) {
+				free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+						percpu_pdata);
+				free_percpu(percpu_pdata);
+			}
+		}
 		enable = 0;
 		/* In case we got suspended mid-exit */
 		__raw_writel(0, msm_tmr0_base + WDT0_EN);
@@ -304,6 +332,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);
 
@@ -316,45 +347,72 @@
 	__raw_writel(1, msm_tmr0_base + WDT0_RST);
 	last_pet = sched_clock();
 
+	if (!has_vic)
+		enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, IRQ_TYPE_EDGE_RISING);
+
 	printk(KERN_INFO "MSM Watchdog Initialized\n");
 
 	return;
 }
 
+struct fiq_handler wdog_fh = {
+	.name = MODULE_NAME,
+};
+
 static int msm_watchdog_probe(struct platform_device *pdev)
 {
 	struct msm_watchdog_pdata *pdata = pdev->dev.platform_data;
 	int ret;
+	void *stack;
 
 	if (!enable || !pdata || !pdata->pet_time || !pdata->bark_time) {
 		printk(KERN_INFO "MSM Watchdog Not Initialized\n");
 		return -ENODEV;
 	}
 
-	if (!pdata->has_secure)
-		appsbark = 1;
-
 	bark_time = pdata->bark_time;
+	has_vic = pdata->has_vic;
+	if (!pdata->has_secure) {
+		appsbark = 1;
+		appsbark_fiq = pdata->use_kernel_fiq;
+	}
 
 	msm_tmr0_base = msm_timer_get_timer0_base();
 
-	percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
-	if (!percpu_pdata) {
-		pr_err("%s: memory allocation failed for percpu data\n",
-				__func__);
-		return -ENOMEM;
-	}
+	if (has_vic) {
+		ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
+				  "apps_wdog_bark", NULL);
+		if (ret)
+			return ret;
+	} else if (appsbark_fiq) {
+		claim_fiq(&wdog_fh);
+		set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
+		stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
+		if (!stack) {
+			pr_info("No free pages available - %s fails\n",
+					__func__);
+			return -ENOMEM;
+		}
 
-	*__this_cpu_ptr(percpu_pdata) = pdata;
-	/* Must request irq before sending scm command */
-	ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler,
-			  "apps_wdog_bark", percpu_pdata);
-	if (ret) {
-		free_percpu(percpu_pdata);
-		return ret;
-	}
+		msm_wdog_fiq_setup(stack);
+		gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
+	} else {
+		percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+		if (!percpu_pdata) {
+			pr_err("%s: memory allocation failed for percpu data\n",
+					__func__);
+			return -ENOMEM;
+		}
 
-	enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, IRQ_TYPE_EDGE_RISING);
+		*__this_cpu_ptr(percpu_pdata) = pdata;
+		/* Must request irq before sending scm command */
+		ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+			wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
+		if (ret) {
+			free_percpu(percpu_pdata);
+			return ret;
+		}
+	}
 
 	/*
 	 * This is only temporary till SBLs turn on the XPUs
@@ -366,8 +424,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_watchdog.h b/arch/arm/mach-msm/msm_watchdog.h
index 33e9e0c..00ff0b6 100644
--- a/arch/arm/mach-msm/msm_watchdog.h
+++ b/arch/arm/mach-msm/msm_watchdog.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,8 +20,54 @@
 	unsigned int bark_time;
 	bool has_secure;
 	bool needs_expired_enable;
+	bool has_vic;
+	/* You have to be running in secure mode to use FIQ */
+	bool use_kernel_fiq;
 };
 
+struct msm_watchdog_dump {
+	uint32_t magic;
+	uint32_t curr_cpsr;
+	uint32_t usr_r0;
+	uint32_t usr_r1;
+	uint32_t usr_r2;
+	uint32_t usr_r3;
+	uint32_t usr_r4;
+	uint32_t usr_r5;
+	uint32_t usr_r6;
+	uint32_t usr_r7;
+	uint32_t usr_r8;
+	uint32_t usr_r9;
+	uint32_t usr_r10;
+	uint32_t usr_r11;
+	uint32_t usr_r12;
+	uint32_t usr_r13;
+	uint32_t usr_r14;
+	uint32_t irq_spsr;
+	uint32_t irq_r13;
+	uint32_t irq_r14;
+	uint32_t svc_spsr;
+	uint32_t svc_r13;
+	uint32_t svc_r14;
+	uint32_t abt_spsr;
+	uint32_t abt_r13;
+	uint32_t abt_r14;
+	uint32_t und_spsr;
+	uint32_t und_r13;
+	uint32_t und_r14;
+	uint32_t fiq_spsr;
+	uint32_t fiq_r8;
+	uint32_t fiq_r9;
+	uint32_t fiq_r10;
+	uint32_t fiq_r11;
+	uint32_t fiq_r12;
+	uint32_t fiq_r13;
+	uint32_t fiq_r14;
+};
+
+void msm_wdog_fiq_setup(void *stack);
+extern unsigned int msm_wdog_fiq_length, msm_wdog_fiq_start;
+
 #ifdef CONFIG_MSM_WATCHDOG
 void pet_watchdog(void);
 #else
diff --git a/arch/arm/mach-msm/msm_watchdog_asm.S b/arch/arm/mach-msm/msm_watchdog_asm.S
new file mode 100644
index 0000000..c0377d6
--- /dev/null
+++ b/arch/arm/mach-msm/msm_watchdog_asm.S
@@ -0,0 +1,84 @@
+/* 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/linkage.h>
+#include <asm/assembler.h>
+
+#define VERSION_ID 0x1
+#define MAGIC 0xDEAD0000 | VERSION_ID
+
+	.text
+
+	.align 3
+
+ENTRY(msm_wdog_fiq_start)
+	mov	sp, r8		@get stack
+	ldr	r8, Ldump_cpu_ctx
+	@ store magic to indicate a valid dump
+	ldr	r9, Lmagic
+	str	r9, [r8], #4
+	@ get the current cpsr
+	mrs	r9, cpsr
+	str	r9, [r8],#4
+	@ get the USR r0-r7
+	stmia	r8!, {r0-r7}
+	mov	r4, r8
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | SYSTEM_MODE
+	msr	cpsr_c, r5	@ select SYSTEM mode
+	stmia	r4!, {r8-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | IRQ_MODE
+	msr	cpsr_c, r5	@ select IRQ mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+	msr	cpsr_c, r5	@ select SVC mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | ABT_MODE
+	msr	cpsr_c, r5	@ select ABT mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | UND_MODE
+	msr	cpsr_c, r5	@ select UND mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
+	msr	cpsr_c, r5	@ select FIQ mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r8-r14}
+	dsb
+	mov	r5, #PSR_F_BIT | SVC_MODE
+	msr	cpsr_c, r5	@ select SVC mode
+	ldr	r2, Lwatchdog_bark_fin
+	blx	r2
+Ldump_cpu_ctx:
+	.word	msm_dump_cpu_ctx
+Lmagic:
+	.word	MAGIC
+Lwatchdog_bark_fin:
+	.word	msm_wdog_bark_fin
+ENTRY(msm_wdog_fiq_length)
+	.word	. - msm_wdog_fiq_start
+
+/* setup the stack */
+ENTRY(msm_wdog_fiq_setup)
+	mrs	r3, cpsr
+	msr	cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
+	mov	r8, r0
+	msr	cpsr_c, r3
+	bx	lr
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 74c64c1..407231a 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -15,10 +15,13 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/debugfs.h>
 #include <linux/list.h>
 #include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/string.h>
+#include <linux/clk.h>
 
 #include <mach/msm_xo.h>
 #include <mach/rpm.h>
@@ -26,7 +29,7 @@
 
 #include "rpm_resources.h"
 
-static DEFINE_SPINLOCK(msm_xo_lock);
+static DEFINE_MUTEX(msm_xo_lock);
 
 struct msm_xo {
 	unsigned votes[NUM_MSM_XO_MODES];
@@ -44,18 +47,93 @@
 static struct msm_xo msm_xo_sources[NUM_MSM_XO_IDS];
 
 #ifdef CONFIG_DEBUG_FS
-static const char *msm_xo_mode_to_str(unsigned mode)
+static const char *msm_xo_to_str[NUM_MSM_XO_IDS] = {
+	[MSM_XO_TCXO_D0] = "D0",
+	[MSM_XO_TCXO_D1] = "D1",
+	[MSM_XO_TCXO_A0] = "A0",
+	[MSM_XO_TCXO_A1] = "A1",
+	[MSM_XO_TCXO_A2] = "A2",
+	[MSM_XO_CORE] = "CORE",
+};
+
+static const char *msm_xo_mode_to_str[NUM_MSM_XO_MODES] = {
+	[MSM_XO_MODE_ON] = "ON",
+	[MSM_XO_MODE_PIN_CTRL] = "PIN",
+	[MSM_XO_MODE_OFF] = "OFF",
+};
+
+static int msm_xo_debugfs_open(struct inode *inode, struct file *filp)
 {
-	switch (mode) {
-	case MSM_XO_MODE_ON:
-		return "ON";
-	case MSM_XO_MODE_PIN_CTRL:
-		return "PIN";
-	case MSM_XO_MODE_OFF:
-		return "OFF";
-	default:
-		return "ERR";
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t msm_xo_debugfs_read(struct file *filp, char __user *ubuf,
+		size_t cnt, loff_t *ppos)
+{
+	int r;
+	char buf[10];
+	struct msm_xo_voter *xo = filp->private_data;
+
+	r = snprintf(buf, sizeof(buf), "%s\n", msm_xo_mode_to_str[xo->mode]);
+	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t msm_xo_debugfs_write(struct file *filp,
+		const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct msm_xo_voter *xo = filp->private_data;
+	char buf[10], *b;
+	int i, ret;
+
+	if (cnt > sizeof(buf) - 1)
+		return -EINVAL;
+
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+	buf[cnt] = '\0';
+	b = strstrip(buf);
+
+	for (i = 0; i < ARRAY_SIZE(msm_xo_mode_to_str); i++)
+		if (!strncasecmp(b, msm_xo_mode_to_str[i], sizeof(buf))) {
+			ret = msm_xo_mode_vote(xo, i);
+			return ret ? : cnt;
+		}
+
+	return -EINVAL;
+}
+
+static const struct file_operations msm_xo_debugfs_fops = {
+	.open	= msm_xo_debugfs_open,
+	.read	= msm_xo_debugfs_read,
+	.write	= msm_xo_debugfs_write,
+};
+
+static struct dentry *xo_debugfs_root;
+static struct msm_xo_voter *xo_debugfs_voters[NUM_MSM_XO_IDS];
+
+static int __init msm_xo_init_debugfs_voters(void)
+{
+	int i;
+
+	xo_debugfs_root = debugfs_create_dir("msm_xo", NULL);
+	if (!xo_debugfs_root)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++) {
+		xo_debugfs_voters[i] = msm_xo_get(i, "debugfs");
+		if (IS_ERR(xo_debugfs_voters[i]))
+			goto err;
+		debugfs_create_file(msm_xo_to_str[i], S_IRUGO | S_IWUSR,
+				xo_debugfs_root, xo_debugfs_voters[i],
+				&msm_xo_debugfs_fops);
 	}
+	return 0;
+err:
+	while (--i >= 0)
+		msm_xo_put(xo_debugfs_voters[i]);
+	debugfs_remove_recursive(xo_debugfs_root);
+	return -ENOMEM;
 }
 
 static void msm_xo_dump_xo(struct seq_file *m, struct msm_xo *xo,
@@ -63,28 +141,22 @@
 {
 	struct msm_xo_voter *voter;
 
-	seq_printf(m, "%-20s%s\n", name, msm_xo_mode_to_str(xo->mode));
+	seq_printf(m, "CXO %-16s%s\n", name, msm_xo_mode_to_str[xo->mode]);
 	list_for_each_entry(voter, &xo->voters, list)
 		seq_printf(m, " %s %-16s %s\n",
 				xo->mode == voter->mode ? "*" : " ",
 				voter->name,
-				msm_xo_mode_to_str(voter->mode));
+				msm_xo_mode_to_str[voter->mode]);
 }
 
 static int msm_xo_show_voters(struct seq_file *m, void *v)
 {
-	unsigned long flags;
+	int i;
 
-	spin_lock_irqsave(&msm_xo_lock, flags);
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_D0], "TCXO D0");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_D1], "TCXO D1");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_A0], "TCXO A0");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_A1], "TCXO A1");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_A2], "TCXO A2");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CORE], "TCXO Core");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_PXO], "PXO during sleep");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CXO], "CXO");
-	spin_unlock_irqrestore(&msm_xo_lock, flags);
+	mutex_lock(&msm_xo_lock);
+	for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++)
+		msm_xo_dump_xo(m, &msm_xo_sources[i], msm_xo_to_str[i]);
+	mutex_unlock(&msm_xo_lock);
 
 	return 0;
 }
@@ -103,19 +175,20 @@
 
 static int __init msm_xo_debugfs_init(void)
 {
-	struct dentry *entry;
-
-	entry = debugfs_create_file("xo_voters", S_IRUGO, NULL, NULL,
-			&msm_xo_voters_ops);
-	return IS_ERR(entry) ? PTR_ERR(entry) : 0;
+	msm_xo_init_debugfs_voters();
+	if (!debugfs_create_file("xo_voters", S_IRUGO, NULL, NULL,
+			&msm_xo_voters_ops))
+		return -ENOMEM;
+	return 0;
 }
-late_initcall(msm_xo_debugfs_init);
+#else
+static int __init msm_xo_debugfs_init(void) { return 0; }
 #endif
 
 static int msm_xo_update_vote(struct msm_xo *xo)
 {
 	int ret;
-	unsigned vote, prev_vote = xo->mode, ctx_set;
+	unsigned vote, prev_vote = xo->mode;
 	struct msm_rpm_iv_pair cmd;
 
 	if (xo->votes[MSM_XO_MODE_ON])
@@ -133,36 +206,21 @@
 	 * command fails we'll rollback.
 	 */
 	xo->mode = vote;
-
-	if (xo == &msm_xo_sources[MSM_XO_PXO]) {
-		cmd.id = MSM_RPM_ID_PXO_CLK;
-		cmd.value = msm_xo_sources[MSM_XO_PXO].mode ? 1 : 0;
-		ret = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &cmd, 1);
-	} else if (xo == &msm_xo_sources[MSM_XO_CXO]) {
-		cmd.id = MSM_RPM_ID_CXO_CLK;
-		cmd.value = msm_xo_sources[MSM_XO_CXO].mode ? 1 : 0;
-		if (cpu_is_msm9615())
-			ctx_set = MSM_RPM_CTX_SET_SLEEP;
-		else
-			ctx_set = MSM_RPM_CTX_SET_0;
-		ret = msm_rpmrs_set_noirq(ctx_set, &cmd, 1);
-	} else {
-		cmd.id = MSM_RPM_ID_CXO_BUFFERS;
-		cmd.value = (msm_xo_sources[MSM_XO_TCXO_D0].mode << 0)  |
-			    (msm_xo_sources[MSM_XO_TCXO_D1].mode << 8)  |
-			    (msm_xo_sources[MSM_XO_TCXO_A0].mode << 16) |
-			    (msm_xo_sources[MSM_XO_TCXO_A1].mode << 24) |
-			    (msm_xo_sources[MSM_XO_TCXO_A2].mode << 28) |
-			    /*
-			     * 8660 RPM has XO_CORE at bit 18 and 8960 RPM has
-			     * XO_CORE at bit 20. Since the opposite bit is
-			     * reserved in both cases, just set both and be
-			     * done with it.
-			     */
-			    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 20) |
-			    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 18);
-		ret = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &cmd, 1);
-	}
+	cmd.id = MSM_RPM_ID_CXO_BUFFERS;
+	cmd.value = (msm_xo_sources[MSM_XO_TCXO_D0].mode << 0)  |
+		    (msm_xo_sources[MSM_XO_TCXO_D1].mode << 8)  |
+		    (msm_xo_sources[MSM_XO_TCXO_A0].mode << 16) |
+		    (msm_xo_sources[MSM_XO_TCXO_A1].mode << 24) |
+		    (msm_xo_sources[MSM_XO_TCXO_A2].mode << 28) |
+		    /*
+		     * 8660 RPM has XO_CORE at bit 18 and 8960 RPM has
+		     * XO_CORE at bit 20. Since the opposite bit is
+		     * reserved in both cases, just set both and be
+		     * done with it.
+		     */
+		    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 20) |
+		    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 18);
+	ret = msm_rpm_set(MSM_RPM_CTX_SET_0, &cmd, 1);
 
 	if (ret)
 		xo->mode = prev_vote;
@@ -174,6 +232,9 @@
 {
 	int ret;
 	struct msm_xo *xo = xo_voter->xo;
+	int is_d0 = xo == &msm_xo_sources[MSM_XO_TCXO_D0];
+	int needs_workaround = cpu_is_msm8960() || cpu_is_apq8064() ||
+			       cpu_is_msm8930() || cpu_is_msm9615();
 
 	if (xo_voter->mode == mode)
 		return 0;
@@ -186,6 +247,20 @@
 		xo->votes[mode]--;
 		goto out;
 	}
+	/* TODO: Remove once RPM separates the concept of D0 and CXO */
+	if (is_d0 && needs_workaround) {
+		static struct clk *xo_clk;
+
+		if (!xo_clk) {
+			xo_clk = clk_get_sys("msm_xo", "xo");
+			BUG_ON(IS_ERR(xo_clk));
+		}
+		/* Ignore transitions from pin to on or vice versa */
+		if (mode && xo_voter->mode == MSM_XO_MODE_OFF)
+			clk_enable(xo_clk);
+		else if (!mode)
+			clk_disable(xo_clk);
+	}
 	xo_voter->mode = mode;
 out:
 	return ret;
@@ -205,7 +280,6 @@
 int msm_xo_mode_vote(struct msm_xo_voter *xo_voter, enum msm_xo_modes mode)
 {
 	int ret;
-	unsigned long flags;
 
 	if (!xo_voter)
 		return 0;
@@ -213,9 +287,9 @@
 	if (mode >= NUM_MSM_XO_MODES || IS_ERR(xo_voter))
 		return -EINVAL;
 
-	spin_lock_irqsave(&msm_xo_lock, flags);
+	mutex_lock(&msm_xo_lock);
 	ret = __msm_xo_mode_vote(xo_voter, mode);
-	spin_unlock_irqrestore(&msm_xo_lock, flags);
+	mutex_unlock(&msm_xo_lock);
 
 	return ret;
 }
@@ -234,16 +308,8 @@
 struct msm_xo_voter *msm_xo_get(enum msm_xo_ids xo_id, const char *voter)
 {
 	int ret;
-	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;
@@ -264,10 +330,10 @@
 	xo_voter->xo = &msm_xo_sources[xo_id];
 
 	/* Voters vote for OFF by default */
-	spin_lock_irqsave(&msm_xo_lock, flags);
+	mutex_lock(&msm_xo_lock);
 	xo_voter->xo->votes[MSM_XO_MODE_OFF]++;
 	list_add(&xo_voter->list, &xo_voter->xo->voters);
-	spin_unlock_irqrestore(&msm_xo_lock, flags);
+	mutex_unlock(&msm_xo_lock);
 
 	return xo_voter;
 
@@ -288,16 +354,14 @@
  */
 void msm_xo_put(struct msm_xo_voter *xo_voter)
 {
-	unsigned long flags;
-
 	if (!xo_voter || IS_ERR(xo_voter))
 		return;
 
-	spin_lock_irqsave(&msm_xo_lock, flags);
+	mutex_lock(&msm_xo_lock);
 	__msm_xo_mode_vote(xo_voter, MSM_XO_MODE_OFF);
 	xo_voter->xo->votes[MSM_XO_MODE_OFF]--;
 	list_del(&xo_voter->list);
-	spin_unlock_irqrestore(&msm_xo_lock, flags);
+	mutex_unlock(&msm_xo_lock);
 
 	kfree(xo_voter->name);
 	kfree(xo_voter);
@@ -306,39 +370,17 @@
 
 int __init msm_xo_init(void)
 {
-	int i;
-	int ret = 0;
-	struct msm_rpm_iv_pair cmd[2];
+	int i, ret;
+	struct msm_rpm_iv_pair cmd[1];
 
 	for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++)
 		INIT_LIST_HEAD(&msm_xo_sources[i].voters);
 
-	if (cpu_is_msm9615()) {
-		cmd[0].id = MSM_RPM_ID_CXO_CLK;
-		cmd[0].value = 1;
-		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, cmd, 1);
-		if (ret)
-			goto out;
-
-		cmd[0].id = MSM_RPM_ID_CXO_CLK;
-		cmd[0].value = 0;
-		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_SLEEP, cmd, 1);
-		goto out;
-	}
-
-	cmd[0].id = MSM_RPM_ID_PXO_CLK;
-	cmd[0].value = 1;
-	cmd[1].id = MSM_RPM_ID_CXO_BUFFERS;
-	cmd[1].value = 0;
-	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, cmd, 2);
-	if (ret)
-		goto out;
-
-	cmd[0].id = MSM_RPM_ID_PXO_CLK;
+	cmd[0].id = MSM_RPM_ID_CXO_BUFFERS;
 	cmd[0].value = 0;
-	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_SLEEP, cmd, 1);
+	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, cmd, ARRAY_SIZE(cmd));
 	if (ret)
-		goto out;
-out:
-	return ret;
+		return ret;
+	msm_xo_debugfs_init();
+	return 0;
 }
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 1004e01..fa9159e 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -20,44 +20,111 @@
 #include <linux/mutex.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/wakelock.h>
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
+#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 
+enum pil_state {
+	PIL_OFFLINE,
+	PIL_ONLINE,
+};
+
+static const char *pil_states[] = {
+	[PIL_OFFLINE] = "OFFLINE",
+	[PIL_ONLINE] = "ONLINE",
+};
+
 struct pil_device {
 	struct pil_desc *desc;
 	int count;
+	enum pil_state state;
 	struct mutex lock;
-	struct list_head list;
+	struct device dev;
+	struct module *owner;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	struct delayed_work proxy;
+	struct wake_lock wlock;
+	char wake_name[32];
 };
 
-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)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
-	struct pil_device *dev;
+	return snprintf(buf, PAGE_SIZE, "%s\n", to_pil_device(dev)->desc->name);
+}
 
-	list_for_each_entry(dev, &pil_list, list)
-		if (!strcmp(dev->desc->name, str))
-			return dev;
-	return NULL;
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	enum pil_state state = to_pil_device(dev)->state;
+	return snprintf(buf, PAGE_SIZE, "%s\n", pil_states[state]);
+}
+
+static struct device_attribute pil_attrs[] = {
+	__ATTR_RO(name),
+	__ATTR_RO(state),
+	{ },
+};
+
+struct bus_type pil_bus_type = {
+	.name		= "pil",
+	.dev_attrs	= pil_attrs,
+};
+
+static int __find_peripheral(struct device *dev, void *data)
+{
+	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);
+	dev = bus_find_device(&pil_bus_type, NULL, (void *)str,
+			__find_peripheral);
+	return dev ? to_pil_device(dev) : NULL;
+}
 
-	return dev;
+static void pil_proxy_work(struct work_struct *work)
+{
+	struct pil_device *pil;
+
+	pil = container_of(work, struct pil_device, proxy.work);
+	pil->desc->ops->proxy_unvote(pil->desc);
+	wake_unlock(&pil->wlock);
+}
+
+static int pil_proxy_vote(struct pil_device *pil)
+{
+	if (pil->desc->ops->proxy_vote) {
+		wake_lock(&pil->wlock);
+		return pil->desc->ops->proxy_vote(pil->desc);
+	}
+	return 0;
+}
+
+static void pil_proxy_unvote(struct pil_device *pil, unsigned long timeout)
+{
+	if (pil->desc->ops->proxy_unvote)
+		schedule_delayed_work(&pil->proxy, msecs_to_jiffies(timeout));
 }
 
 #define IOMAP_SIZE SZ_4M
@@ -65,30 +132,29 @@
 static int load_segment(const struct elf32_phdr *phdr, unsigned num,
 		struct pil_device *pil)
 {
-	int ret, count, paddr;
+	int ret = 0, count, paddr;
 	char fw_name[30];
 	const struct firmware *fw = NULL;
 	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 +171,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 +192,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;
 		}
@@ -137,10 +203,12 @@
 		paddr += size;
 	}
 
-	ret = pil->desc->ops->verify_blob(pil->desc, phdr->p_paddr,
+	if (pil->desc->ops->verify_blob) {
+		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);
+		if (ret)
+			dev_err(&pil->dev, "Blob%u failed verification\n", num);
+	}
 
 release_fw:
 	release_firmware(fw);
@@ -154,6 +222,9 @@
 	return (p->p_type & PT_LOAD) && !segment_is_hash(p->p_flags);
 }
 
+/* Sychronize request_firmware() with suspend */
+static DECLARE_RWSEM(pil_pm_rwsem);
+
 static int load_image(struct pil_device *pil)
 {
 	int i, ret;
@@ -161,42 +232,44 @@
 	struct elf32_hdr *ehdr;
 	const struct elf32_phdr *phdr;
 	const struct firmware *fw;
+	unsigned long proxy_timeout = pil->desc->proxy_timeout;
 
+	down_read(&pil_pm_rwsem);
 	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,25 +280,42 @@
 
 		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;
 		}
 	}
 
-	ret = pil->desc->ops->auth_and_reset(pil->desc);
+	ret = pil_proxy_vote(pil);
 	if (ret) {
-		dev_err(pil->desc->dev, "Failed to bring out of reset\n");
+		dev_err(&pil->dev, "Failed to proxy vote\n");
 		goto release_fw;
 	}
-	dev_info(pil->desc->dev, "brought out of reset\n");
 
+	ret = pil->desc->ops->auth_and_reset(pil->desc);
+	if (ret) {
+		dev_err(&pil->dev, "Failed to bring out of reset\n");
+		proxy_timeout = 0; /* Remove proxy vote immediately on error */
+		goto err_boot;
+	}
+	dev_info(&pil->dev, "brought %s out of reset\n", pil->desc->name);
+err_boot:
+	pil_proxy_unvote(pil, proxy_timeout);
 release_fw:
 	release_firmware(fw);
 out:
+	up_read(&pil_pm_rwsem);
 	return ret;
 }
 
+static void pil_set_state(struct pil_device *pil, enum pil_state state)
+{
+	if (pil->state != state) {
+		pil->state = state;
+		sysfs_notify(&pil->dev.kobj, NULL, "state");
+	}
+}
+
 /**
  * pil_get() - Load a peripheral into memory and take it out of reset
  * @name: pointer to a string containing the name of the peripheral to load
@@ -242,36 +332,52 @@
 	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:
+	pil_set_state(pil, PIL_ONLINE);
 	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);
 
+static void pil_shutdown(struct pil_device *pil)
+{
+	pil->desc->ops->shutdown(pil->desc);
+	flush_delayed_work(&pil->proxy);
+	pil_set_state(pil, PIL_OFFLINE);
+}
+
 /**
  * pil_put() - Inform PIL the peripheral no longer needs to be active
  * @peripheral_handle: pointer from a previous call to pil_get()
@@ -281,22 +387,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)
-		pil->desc->ops->shutdown(pil->desc);
+	if (WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
+		goto err_out;
+	if (!--pil->count)
+		pil_shutdown(pil);
 	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);
 
@@ -305,13 +418,17 @@
 	struct pil_device *pil;
 
 	pil = find_peripheral(name);
-	if (!pil)
+	if (!pil) {
+		pr_err("%s: Couldn't find %s\n", __func__, name);
 		return;
+	}
 
 	mutex_lock(&pil->lock);
 	if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
-		pil->desc->ops->shutdown(pil->desc);
+		pil_shutdown(pil);
 	mutex_unlock(&pil->lock);
+
+	put_device(&pil->dev);
 }
 EXPORT_SYMBOL(pil_force_shutdown);
 
@@ -321,20 +438,25 @@
 	struct pil_device *pil;
 
 	pil = find_peripheral(name);
-	if (!pil)
+	if (!pil) {
+		pr_err("%s: Couldn't find %s\n", __func__, name);
 		return -EINVAL;
+	}
 
 	mutex_lock(&pil->lock);
 	if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
 		ret = load_image(pil);
+	if (!ret)
+		pil_set_state(pil, PIL_ONLINE);
 	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 +506,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 +516,150 @@
 
 	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)
+{
+	pil_shutdown(to_pil_device(dev));
+	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 = kzalloc(sizeof(*pil), GFP_KERNEL);
+	struct pil_device *pil = to_pil_device(dev);
+	wake_lock_destroy(&pil->wlock);
+	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;
+
+	/* Ignore users who don't make any sense */
+	if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
+				"invalid proxy voting. ignoring\n"))
+		((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
+
+	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);
+	snprintf(pil->wake_name, sizeof(pil->wake_name), "pil-%s", desc->name);
+	wake_lock_init(&pil->wlock, WAKE_LOCK_SUSPEND, pil->wake_name);
+	INIT_DELAYED_WORK(&pil->proxy, pil_proxy_work);
 
-	return msm_pil_debugfs_add(pil);
+	dev_set_name(&pil->dev, "pil%d", atomic_inc_return(&pil_count));
+	err = device_register(&pil->dev);
+	if (err) {
+		put_device(&pil->dev);
+		wake_lock_destroy(&pil->wlock);
+		mutex_destroy(&pil->lock);
+		kfree(pil);
+		return ERR_PTR(err);
+	}
+
+	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);
+		flush_delayed_work_sync(&pil->proxy);
+		msm_pil_debugfs_remove(pil);
+		device_unregister(&pil->dev);
+		mutex_unlock(&pil->lock);
+		put_device(&pil->dev);
+	}
+}
+EXPORT_SYMBOL(msm_pil_unregister);
+
+static int pil_pm_notify(struct notifier_block *b, unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&pil_pm_rwsem);
+		break;
+	case PM_POST_SUSPEND:
+		up_write(&pil_pm_rwsem);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block pil_pm_notifier = {
+	.notifier_call = pil_pm_notify,
+};
+
+static int __init msm_pil_init(void)
+{
+	int ret = msm_pil_debugfs_init();
+	if (ret)
+		return ret;
+	register_pm_notifier(&pil_pm_notifier);
+	return bus_register(&pil_bus_type);
+}
+subsys_initcall(msm_pil_init);
+
+static void __exit msm_pil_exit(void)
+{
+	bus_unregister(&pil_bus_type);
+	unregister_pm_notifier(&pil_pm_notifier);
+	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..e3b250b 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,22 +13,49 @@
 #define __MSM_PERIPHERAL_LOADER_H
 
 struct device;
+struct module;
 
+/**
+ * struct pil_desc - PIL descriptor
+ * @name: string used for pil_get()
+ * @depends_on: booted before this peripheral
+ * @dev: parent device
+ * @ops: callback functions
+ * @owner: module the descriptor belongs to
+ * @proxy_timeout: delay in ms until proxy vote is removed
+ */
 struct pil_desc {
 	const char *name;
 	const char *depends_on;
 	struct device *dev;
 	const struct pil_reset_ops *ops;
+	struct module *owner;
+	unsigned long proxy_timeout;
 };
 
+/**
+ * struct pil_reset_ops - PIL operations
+ * @init_image: prepare an image for authentication
+ * @verify_blob: authenticate a program segment, called once for each loadable
+ *		 program segment (optional)
+ * @proxy_vote: make proxy votes before auth_and_reset (optional)
+ * @auth_and_reset: boot the processor
+ * @proxy_unvote: remove any proxy votes (optional)
+ * @shutdown: shutdown the processor
+ */
 struct pil_reset_ops {
 	int (*init_image)(struct pil_desc *pil, const u8 *metadata,
 			  size_t size);
 	int (*verify_blob)(struct pil_desc *pil, u32 phy_addr, size_t size);
+	int (*proxy_vote)(struct pil_desc *pil);
 	int (*auth_and_reset)(struct pil_desc *pil);
+	void (*proxy_unvote)(struct pil_desc *pil);
 	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
deleted file mode 100644
index 6fd8464..0000000
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* Copyright (c) 2011, 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/err.h>
-#include <linux/io.h>
-#include <linux/elf.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/msm_iomap.h>
-#include <mach/scm.h>
-
-#include "peripheral-loader.h"
-#include "scm-pas.h"
-
-#define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
-#define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
-#define PPSS_HCLK_CTL			(MSM_CLK_CTL_BASE + 0x2580)
-
-static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
-	return 0;
-}
-
-static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
-				     size_t size)
-{
-	/* Bring memory and bus interface out of reset */
-	writel_relaxed(0x2, PPSS_RESET);
-	writel_relaxed(0x10, PPSS_HCLK_CTL);
-	return 0;
-}
-
-static int reset_dsps_untrusted(struct pil_desc *pil)
-{
-	writel_relaxed(0x10, PPSS_PROC_CLK_CTL);
-	/* Bring DSPS out of reset */
-	writel_relaxed(0x0, PPSS_RESET);
-	return 0;
-}
-
-static int shutdown_dsps_untrusted(struct pil_desc *pil)
-{
-	writel_relaxed(0x3, PPSS_RESET);
-	writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
-	return 0;
-}
-
-static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
-				   size_t size)
-{
-	return pas_init_image(PAS_DSPS, metadata, size);
-}
-
-static int reset_dsps_trusted(struct pil_desc *pil)
-{
-	return pas_auth_and_reset(PAS_DSPS);
-}
-
-static int shutdown_dsps_trusted(struct pil_desc *pil)
-{
-	return pas_shutdown(PAS_DSPS);
-}
-
-struct pil_reset_ops pil_dsps_ops = {
-	.init_image = init_image_dsps_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_dsps_untrusted,
-	.shutdown = shutdown_dsps_untrusted,
-};
-
-static struct platform_device pil_dsps = {
-	.name = "pil_dsps",
-};
-
-static struct pil_desc pil_dsps_desc = {
-	.name = "dsps",
-	.dev = &pil_dsps.dev,
-	.ops = &pil_dsps_ops,
-};
-
-static void __init use_secure_pil(void)
-{
-	if (pas_supported(PAS_DSPS) > 0) {
-		pil_dsps_ops.init_image = init_image_dsps_trusted;
-		pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
-		pil_dsps_ops.shutdown = shutdown_dsps_trusted;
-	}
-}
-
-static int __init msm_peripheral_reset_init(void)
-{
-	/*
-	 * Don't initialize PIL on simulated targets, as some
-	 * subsystems may not be emulated on them.
-	 */
-	if (machine_is_msm8960_sim() || machine_is_msm8960_rumi3())
-		return 0;
-
-	use_secure_pil();
-
-	BUG_ON(platform_device_register(&pil_dsps));
-	BUG_ON(msm_pil_register(&pil_dsps_desc));
-
-	return 0;
-}
-arch_initcall(msm_peripheral_reset_init);
diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c
deleted file mode 100644
index 88b07a5..0000000
--- a/arch/arm/mach-msm/peripheral-reset.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/* Copyright (c) 2010-2011, 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/err.h>
-#include <linux/io.h>
-#include <linux/elf.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/scm.h>
-#include <mach/msm_iomap.h>
-
-#include "peripheral-loader.h"
-#include "scm-pas.h"
-
-#define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
-#define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
-#define CLK_HALT_DFAB_STATE		(MSM_CLK_CTL_BASE + 0x2FC8)
-
-static int dsps_start;
-
-static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
-				   size_t size)
-{
-	return pas_init_image(PAS_DSPS, metadata, size);
-}
-
-static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
-				     size_t size)
-{
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	dsps_start = ehdr->e_entry;
-	/* Bring memory and bus interface out of reset */
-	__raw_writel(0x2, PPSS_RESET);
-	mb();
-	return 0;
-}
-
-static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
-	return 0;
-}
-
-static int reset_dsps_untrusted(struct pil_desc *pil)
-{
-	__raw_writel(0x10, PPSS_PROC_CLK_CTL);
-	while (__raw_readl(CLK_HALT_DFAB_STATE) & BIT(18))
-		cpu_relax();
-
-	/* Bring DSPS out of reset */
-	__raw_writel(0x0, PPSS_RESET);
-	return 0;
-}
-
-static int reset_dsps_trusted(struct pil_desc *pil)
-{
-	return pas_auth_and_reset(PAS_DSPS);
-}
-
-static int shutdown_dsps_trusted(struct pil_desc *pil)
-{
-	return pas_shutdown(PAS_DSPS);
-}
-
-static int shutdown_dsps_untrusted(struct pil_desc *pil)
-{
-	__raw_writel(0x3, PPSS_RESET);
-	__raw_writel(0x0, PPSS_PROC_CLK_CTL);
-	return 0;
-}
-
-struct pil_reset_ops pil_dsps_ops = {
-	.init_image = init_image_dsps_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_dsps_untrusted,
-	.shutdown = shutdown_dsps_untrusted,
-};
-
-static struct platform_device pil_dsps = {
-	.name = "pil_dsps",
-};
-
-static struct pil_desc pil_dsps_desc = {
-	.name = "dsps",
-	.dev = &pil_dsps.dev,
-	.ops = &pil_dsps_ops,
-};
-
-static int __init msm_peripheral_reset_init(void)
-{
-	if (pas_supported(PAS_DSPS) > 0) {
-		pil_dsps_ops.init_image = init_image_dsps_trusted;
-		pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
-		pil_dsps_ops.shutdown = shutdown_dsps_trusted;
-	}
-
-	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));
-
-	return 0;
-}
-
-arch_initcall(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-dsps.c b/arch/arm/mach-msm/pil-dsps.c
new file mode 100644
index 0000000..81f5330
--- /dev/null
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -0,0 +1,146 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
+#define PPSS_RESET_PROC_RESET		0x2
+#define PPSS_RESET_RESET		0x1
+#define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
+#define CLK_BRANCH_ENA			0x10
+#define PPSS_HCLK_CTL			(MSM_CLK_CTL_BASE + 0x2580)
+#define CLK_HALT_DFAB_STATE		(MSM_CLK_CTL_BASE + 0x2FC8)
+
+static int init_image_dsps(struct pil_desc *pil, const u8 *metadata,
+				     size_t size)
+{
+	/* Bring memory and bus interface out of reset */
+	writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
+	writel_relaxed(CLK_BRANCH_ENA, PPSS_HCLK_CTL);
+	mb();
+	return 0;
+}
+
+static int reset_dsps(struct pil_desc *pil)
+{
+	writel_relaxed(CLK_BRANCH_ENA, PPSS_PROC_CLK_CTL);
+	while (readl_relaxed(CLK_HALT_DFAB_STATE) & BIT(18))
+		cpu_relax();
+	/* Bring DSPS out of reset */
+	writel_relaxed(0x0, PPSS_RESET);
+	return 0;
+}
+
+static int shutdown_dsps(struct pil_desc *pil)
+{
+	writel_relaxed(PPSS_RESET_PROC_RESET | PPSS_RESET_RESET, PPSS_RESET);
+	usleep_range(1000, 2000);
+	writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
+	writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
+	return 0;
+}
+
+struct pil_reset_ops pil_dsps_ops = {
+	.init_image = init_image_dsps,
+	.auth_and_reset = reset_dsps,
+	.shutdown = shutdown_dsps,
+};
+
+static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
+				   size_t size)
+{
+	return pas_init_image(PAS_DSPS, metadata, size);
+}
+
+static int reset_dsps_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_DSPS);
+}
+
+static int shutdown_dsps_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_DSPS);
+}
+
+struct pil_reset_ops pil_dsps_ops_trusted = {
+	.init_image = init_image_dsps_trusted,
+	.auth_and_reset = reset_dsps_trusted,
+	.shutdown = shutdown_dsps_trusted,
+};
+
+static int __devinit pil_dsps_driver_probe(struct platform_device *pdev)
+{
+	struct pil_desc *desc;
+	struct pil_device *pil;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->name = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	if (pas_supported(PAS_DSPS) > 0) {
+		desc->ops = &pil_dsps_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_dsps_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+	pil = msm_pil_register(desc);
+	if (IS_ERR(pil))
+		return PTR_ERR(pil);
+	platform_set_drvdata(pdev, pil);
+	return 0;
+}
+
+static int __devexit pil_dsps_driver_exit(struct platform_device *pdev)
+{
+	struct pil_device *pil = platform_get_drvdata(pdev);
+	msm_pil_unregister(pil);
+	return 0;
+}
+
+static struct platform_driver pil_dsps_driver = {
+	.probe = pil_dsps_driver_probe,
+	.remove = __devexit_p(pil_dsps_driver_exit),
+	.driver = {
+		.name = "pil_dsps",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_dsps_init(void)
+{
+	return platform_driver_register(&pil_dsps_driver);
+}
+module_init(pil_dsps_init);
+
+static void __exit pil_dsps_exit(void)
+{
+	platform_driver_unregister(&pil_dsps_driver);
+}
+module_exit(pil_dsps_exit);
+
+MODULE_DESCRIPTION("Support for booting sensors (DSPS) images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 2b4dae1..f41a6e3 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -19,13 +19,14 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
-#include <linux/workqueue.h>
 #include <linux/clk.h>
 #include <linux/smp.h>
 
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
 #include <mach/socinfo.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -43,14 +44,8 @@
 #define GSS_CLAMP_ENA		(MSM_CLK_CTL_BASE + 0x2C68)
 #define GSS_CXO_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2C74)
 
-#define PLL5_MODE		(MSM_CLK_CTL_BASE + 0x30E0)
-#define PLL5_L_VAL		(MSM_CLK_CTL_BASE + 0x30E4)
-#define PLL5_M_VAL		(MSM_CLK_CTL_BASE + 0x30E8)
-#define PLL5_N_VAL		(MSM_CLK_CTL_BASE + 0x30EC)
-#define PLL5_CONFIG		(MSM_CLK_CTL_BASE + 0x30F4)
 #define PLL5_STATUS		(MSM_CLK_CTL_BASE + 0x30F8)
 #define PLL_ENA_GSS		(MSM_CLK_CTL_BASE + 0x3480)
-#define PLL_ENA_RPM		(MSM_CLK_CTL_BASE + 0x34A0)
 
 #define PLL5_VOTE		BIT(5)
 #define PLL_STATUS		BIT(16)
@@ -62,21 +57,14 @@
 #define SLP_CLK_BRANCH_ENA	BIT(4)
 #define A5_RESET		BIT(0)
 
-#define PROXY_VOTE_TIMEOUT	10000
-
 struct gss_data {
 	void __iomem *base;
 	void __iomem *qgic2_base;
 	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)
-{
-	return 0;
-}
-
 static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
 		size_t size)
 {
@@ -86,31 +74,25 @@
 	return 0;
 }
 
-static int make_gss_proxy_votes(struct device *dev)
+static int make_gss_proxy_votes(struct pil_desc *pil)
 {
 	int ret;
-	struct gss_data *drv = dev_get_drvdata(dev);
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
 
 	ret = clk_prepare_enable(drv->xo);
 	if (ret) {
-		dev_err(dev, "Failed to enable XO\n");
+		dev_err(pil->dev, "Failed to enable XO\n");
 		return ret;
 	}
-	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 	return 0;
 }
 
-static void remove_gss_proxy_votes(struct work_struct *work)
+static void remove_gss_proxy_votes(struct pil_desc *pil)
 {
-	struct gss_data *drv = container_of(work, struct gss_data, work.work);
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
 	clk_disable_unprepare(drv->xo);
 }
 
-static void remove_gss_proxy_votes_now(struct gss_data *drv)
-{
-	flush_delayed_work(&drv->work);
-}
-
 static void gss_init(struct gss_data *drv)
 {
 	void __iomem *base = drv->base;
@@ -171,6 +153,9 @@
 		return ret;
 	}
 
+	/* Make sure bus port is halted. */
+	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
+
 	/*
 	 * Vote PLL on in GSS's voting register and wait for it to enable.
 	 * The PLL must be enable to switch the GFMUX to a low-power source.
@@ -205,7 +190,6 @@
 	mb();
 
 	clk_disable_unprepare(drv->xo);
-	remove_gss_proxy_votes_now(drv);
 
 	return 0;
 }
@@ -217,9 +201,12 @@
 	unsigned long start_addr = drv->start_addr;
 	int ret;
 
-	ret = make_gss_proxy_votes(pil->dev);
-	if (ret)
+	/* Unhalt bus port. */
+	ret = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV);
+	if (ret) {
+		dev_err(pil->dev, "Failed to unhalt bus port\n");
 		return ret;
+	}
 
 	/* Vote PLL on in GSS's voting register and wait for it to enable. */
 	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
@@ -257,9 +244,10 @@
 
 static struct pil_reset_ops pil_gss_ops = {
 	.init_image = pil_gss_init_image,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_gss_reset,
 	.shutdown = pil_gss_shutdown,
+	.proxy_vote = make_gss_proxy_votes,
+	.proxy_unvote = remove_gss_proxy_votes,
 };
 
 static int pil_gss_init_image_trusted(struct pil_desc *pil,
@@ -273,118 +261,58 @@
 	struct gss_data *drv = dev_get_drvdata(pil->dev);
 	int ret;
 
-	ret = pas_shutdown(PAS_GSS);
-	if (ret)
+	/*
+	 * CXO is used in the secure shutdown code to configure the processor
+	 * for low power mode.
+	 */
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
 		return ret;
+	}
 
-	remove_gss_proxy_votes_now(drv);
+	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
+	ret = pas_shutdown(PAS_GSS);
+	clk_disable_unprepare(drv->xo);
 
 	return ret;
 }
 
 static int pil_gss_reset_trusted(struct pil_desc *pil)
 {
-	struct gss_data *drv = dev_get_drvdata(pil->dev);
 	int err;
 
-	err = make_gss_proxy_votes(pil->dev);
-	if (err)
-		return err;
+	err = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV);
+	if (err) {
+		dev_err(pil->dev, "Failed to unhalt bus port\n");
+		goto out;
+	}
 
 	err =  pas_auth_and_reset(PAS_GSS);
 	if (err)
-		remove_gss_proxy_votes_now(drv);
+		goto halt_port;
 
-	if (cpu_is_apq8064() &&
-	    ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) &&
-	     (SOCINFO_VERSION_MINOR(socinfo_get_version()) == 0))) {
-		err = smp_call_function_single(0, cfg_qgic2_bus_access, drv, 1);
-		if (err) {
-			pr_err("Failed to configure QGIC2 bus access\n");
-			pil_gss_shutdown_trusted(pil);
-			return err;
-		}
-		/*
-		 * On 8064v1.0, pas_auth_and_reset() will not release the A5
-		 * from reset. Linux must do this after cfg_qgic2_bus_access()
-		 * is called on CPU0.
-		 */
-		writel_relaxed(0x0, drv->base + GSS_CSR_RESET);
-	}
+	return 0;
 
+halt_port:
+	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
+out:
 	return err;
 }
 
 static struct pil_reset_ops pil_gss_ops_trusted = {
 	.init_image = pil_gss_init_image_trusted,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_gss_reset_trusted,
 	.shutdown = pil_gss_shutdown_trusted,
+	.proxy_vote = make_gss_proxy_votes,
+	.proxy_unvote = remove_gss_proxy_votes,
 };
 
-static void configure_gss_pll(struct gss_data *drv)
-{
-	u32 regval, is_pll_enabled;
-
-	/* Check if PLL5 is enabled by FSM. */
-	is_pll_enabled = readl_relaxed(PLL5_STATUS) & PLL_STATUS;
-	if (!is_pll_enabled) {
-		/* Enable XO reference for PLL5 */
-		clk_prepare_enable(drv->xo);
-
-		/*
-		 * Assert a vote to hold PLL5 on in RPM register until other
-		 * voters are in place.
-		 */
-		regval = readl_relaxed(PLL_ENA_RPM);
-		regval |= PLL5_VOTE;
-		writel_relaxed(regval, PLL_ENA_RPM);
-
-		/* Ref clk = 27MHz and program pll5 to 288MHz */
-		writel_relaxed(0xF, PLL5_L_VAL);
-		writel_relaxed(0x0, PLL5_M_VAL);
-		writel_relaxed(0x1, PLL5_N_VAL);
-
-		regval = readl_relaxed(PLL5_CONFIG);
-		/* Disable the MN accumulator and enable the main output. */
-		regval &= ~BIT(22);
-		regval |= BIT(23);
-
-		/* Set pre-divider and post-divider values to 1 and 1 */
-		regval &= ~BIT(19);
-		regval &= ~(BIT(21)|BIT(20));
-
-		/* Set VCO frequency */
-		regval &= ~(BIT(17)|BIT(16));
-		writel_relaxed(regval, PLL5_CONFIG);
-
-		regval = readl_relaxed(PLL5_MODE);
-		/* De-assert reset to FSM */
-		regval &= ~BIT(21);
-		writel_relaxed(regval, PLL5_MODE);
-
-		/* Program bias count */
-		regval &= ~(0x3F << 14);
-		regval |= (0x1 << 14);
-		writel_relaxed(regval, PLL5_MODE);
-
-		/* Program lock count */
-		regval &= ~(0x3F << 8);
-		regval |= (0x8 << 8);
-		writel_relaxed(regval, PLL5_MODE);
-
-		/* Enable PLL FSM voting */
-		regval |= BIT(20);
-		writel_relaxed(regval, PLL5_MODE);
-	}
-}
-
 static int __devinit pil_gss_probe(struct platform_device *pdev)
 {
 	struct gss_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
-	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -418,6 +346,8 @@
 
 	desc->name = "gss";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
 
 	if (pas_supported(PAS_GSS) > 0) {
 		desc->ops = &pil_gss_ops_trusted;
@@ -427,23 +357,18 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
-
-	/* FIXME: Remove when PLL is configured by bootloaders. */
-	configure_gss_pll(drv);
-
-	ret = msm_pil_register(desc);
-	if (ret) {
-		flush_delayed_work_sync(&drv->work);
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
 		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);
-	flush_delayed_work_sync(&drv->work);
+	msm_pil_unregister(drv->pil);
 	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..998e606 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -18,7 +18,6 @@
 #include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/workqueue.h>
 #include <linux/clk.h>
 
 #include <mach/msm_iomap.h>
@@ -48,46 +47,32 @@
 #define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
 #define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
 
-#define PROXY_VOTE_TIMEOUT		10000
-
 struct modem_data {
 	void __iomem *base;
 	unsigned long start_addr;
+	struct pil_device *pil;
 	struct clk *xo;
-	struct delayed_work work;
 };
 
-static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
-	return 0;
-}
-
-static int make_modem_proxy_votes(struct device *dev)
+static int make_modem_proxy_votes(struct pil_desc *pil)
 {
 	int ret;
-	struct modem_data *drv = dev_get_drvdata(dev);
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
 
 	ret = clk_prepare_enable(drv->xo);
 	if (ret) {
-		dev_err(dev, "Failed to enable XO\n");
+		dev_err(pil->dev, "Failed to enable XO\n");
 		return ret;
 	}
-	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 	return 0;
 }
 
-static void remove_modem_proxy_votes(struct work_struct *work)
+static void remove_modem_proxy_votes(struct pil_desc *pil)
 {
-	struct modem_data *drv;
-	drv = container_of(work, struct modem_data, work.work);
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
 	clk_disable_unprepare(drv->xo);
 }
 
-static void remove_modem_proxy_votes_now(struct modem_data *drv)
-{
-	flush_delayed_work(&drv->work);
-}
-
 static int modem_init_image(struct pil_desc *pil, const u8 *metadata,
 		size_t size)
 {
@@ -100,13 +85,8 @@
 static int modem_reset(struct pil_desc *pil)
 {
 	u32 reg;
-	int ret;
 	const struct modem_data *drv = dev_get_drvdata(pil->dev);
 
-	ret = make_modem_proxy_votes(pil->dev);
-	if (ret)
-		return ret;
-
 	/* Put modem AHB0,1,2 clocks into reset */
 	writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
 	writel_relaxed(BIT(7), MAHB1_CLK_CTL);
@@ -184,7 +164,6 @@
 static int modem_shutdown(struct pil_desc *pil)
 {
 	u32 reg;
-	struct modem_data *drv = dev_get_drvdata(pil->dev);
 
 	/* Put modem into reset */
 	writel_relaxed(0x1, MARM_RESET);
@@ -218,16 +197,15 @@
 	/* Clear modem's votes for PLLs */
 	writel_relaxed(0x0, PLL_ENA_MARM);
 
-	remove_modem_proxy_votes_now(drv);
-
 	return 0;
 }
 
 static struct pil_reset_ops pil_modem_ops = {
 	.init_image = modem_init_image,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = modem_reset,
 	.shutdown = modem_shutdown,
+	.proxy_vote = make_modem_proxy_votes,
+	.proxy_unvote = remove_modem_proxy_votes,
 };
 
 static int modem_init_image_trusted(struct pil_desc *pil, const u8 *metadata,
@@ -238,38 +216,20 @@
 
 static int modem_reset_trusted(struct pil_desc *pil)
 {
-	int ret;
-	struct modem_data *drv = dev_get_drvdata(pil->dev);
-
-	ret = make_modem_proxy_votes(pil->dev);
-	if (ret)
-		return ret;
-
-	ret = pas_auth_and_reset(PAS_MODEM);
-	if (ret)
-		remove_modem_proxy_votes_now(drv);
-
-	return ret;
+	return pas_auth_and_reset(PAS_MODEM);
 }
 
 static int modem_shutdown_trusted(struct pil_desc *pil)
 {
-	int ret;
-	struct modem_data *drv = dev_get_drvdata(pil->dev);
-
-	ret = pas_shutdown(PAS_MODEM);
-	if (ret)
-		return ret;
-
-	remove_modem_proxy_votes_now(drv);
-	return 0;
+	return pas_shutdown(PAS_MODEM);
 }
 
 static struct pil_reset_ops pil_modem_ops_trusted = {
 	.init_image = modem_init_image_trusted,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = modem_reset_trusted,
 	.shutdown = modem_shutdown_trusted,
+	.proxy_vote = make_modem_proxy_votes,
+	.proxy_unvote = remove_modem_proxy_votes,
 };
 
 static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
@@ -277,7 +237,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 +262,8 @@
 	desc->name = "modem";
 	desc->depends_on = "q6";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
 
 	if (pas_supported(PAS_MODEM) > 0) {
 		desc->ops = &pil_modem_ops_trusted;
@@ -311,20 +272,18 @@
 		desc->ops = &pil_modem_ops;
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
-	INIT_DELAYED_WORK(&drv->work, remove_modem_proxy_votes);
-
-	ret = msm_pil_register(desc);
-	if (ret) {
-		flush_delayed_work_sync(&drv->work);
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
 		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);
-	flush_delayed_work_sync(&drv->work);
+	msm_pil_unregister(drv->pil);
 	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..235d881 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -19,7 +19,6 @@
 #include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/clk.h>
-#include <linux/workqueue.h>
 
 #include <mach/msm_iomap.h>
 
@@ -61,20 +60,13 @@
 #define Q6_STRAP_TCM_BASE	(0x28C << 15)
 #define Q6_STRAP_TCM_CONFIG	0x28B
 
-#define PROXY_VOTE_TIMEOUT	10000
-
 struct q6v3_data {
 	void __iomem *base;
 	unsigned long start_addr;
+	struct pil_device *pil;
 	struct clk *pll;
-	struct delayed_work work;
 };
 
-static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
-	return 0;
-}
-
 static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
 		size_t size)
 {
@@ -84,41 +76,30 @@
 	return 0;
 }
 
-static void q6v3_remove_proxy_votes(struct work_struct *work)
+static void pil_q6v3_remove_proxy_votes(struct pil_desc *pil)
 {
-	struct q6v3_data *drv = container_of(work, struct q6v3_data, work.work);
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
 	clk_disable_unprepare(drv->pll);
 }
 
-static int q6v3_make_proxy_votes(struct device *dev)
+static int pil_q6v3_make_proxy_votes(struct pil_desc *pil)
 {
 	int ret;
-	struct q6v3_data *drv = dev_get_drvdata(dev);
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
 
 	ret = clk_prepare_enable(drv->pll);
 	if (ret) {
-		dev_err(dev, "Failed to enable PLL\n");
+		dev_err(pil->dev, "Failed to enable PLL\n");
 		return ret;
 	}
-	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 	return 0;
 }
 
-static void q6v3_remove_proxy_votes_now(struct q6v3_data *drv)
-{
-	flush_delayed_work(&drv->work);
-}
-
 static int pil_q6v3_reset(struct pil_desc *pil)
 {
 	u32 reg;
-	int ret;
 	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
 
-	ret = q6v3_make_proxy_votes(pil->dev);
-	if (ret)
-		return ret;
-
 	/* Put Q6 into reset */
 	reg = readl_relaxed(LCC_Q6_FUNC);
 	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
@@ -163,7 +144,6 @@
 static int pil_q6v3_shutdown(struct pil_desc *pil)
 {
 	u32 reg;
-	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
 
 	/* Put Q6 into reset */
 	reg = readl_relaxed(LCC_Q6_FUNC);
@@ -183,16 +163,15 @@
 	reg |= CLAMP_IO;
 	writel_relaxed(reg, LCC_Q6_FUNC);
 
-	q6v3_remove_proxy_votes_now(drv);
-
 	return 0;
 }
 
 static struct pil_reset_ops pil_q6v3_ops = {
 	.init_image = pil_q6v3_init_image,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_q6v3_reset,
 	.shutdown = pil_q6v3_shutdown,
+	.proxy_vote = pil_q6v3_make_proxy_votes,
+	.proxy_unvote = pil_q6v3_remove_proxy_votes,
 };
 
 static int pil_q6v3_init_image_trusted(struct pil_desc *pil,
@@ -203,32 +182,20 @@
 
 static int pil_q6v3_reset_trusted(struct pil_desc *pil)
 {
-	int ret;
-	ret = q6v3_make_proxy_votes(pil->dev);
-	if (ret)
-		return ret;
 	return pas_auth_and_reset(PAS_Q6);
 }
 
 static int pil_q6v3_shutdown_trusted(struct pil_desc *pil)
 {
-	int ret;
-	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
-
-	ret = pas_shutdown(PAS_Q6);
-	if (ret)
-		return ret;
-
-	q6v3_remove_proxy_votes_now(drv);
-
-	return 0;
+	return pas_shutdown(PAS_Q6);
 }
 
 static struct pil_reset_ops pil_q6v3_ops_trusted = {
 	.init_image = pil_q6v3_init_image_trusted,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_q6v3_reset_trusted,
 	.shutdown = pil_q6v3_shutdown_trusted,
+	.proxy_vote = pil_q6v3_make_proxy_votes,
+	.proxy_unvote = pil_q6v3_remove_proxy_votes,
 };
 
 static int __devinit pil_q6v3_driver_probe(struct platform_device *pdev)
@@ -260,6 +227,8 @@
 
 	desc->name = "q6";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
 
 	if (pas_supported(PAS_Q6) > 0) {
 		desc->ops = &pil_q6v3_ops_trusted;
@@ -269,11 +238,9 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	INIT_DELAYED_WORK(&drv->work, q6v3_remove_proxy_votes);
-
-	if (msm_pil_register(desc)) {
-		flush_delayed_work_sync(&drv->work);
-		return -EINVAL;
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
+		return PTR_ERR(drv->pil);
 	}
 	return 0;
 }
@@ -281,7 +248,7 @@
 static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
 {
 	struct q6v3_data *drv = platform_get_drvdata(pdev);
-	flush_delayed_work_sync(&drv->work);
+	msm_pil_unregister(drv->pil);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index b0bce02..b6ea03b 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -19,7 +19,6 @@
 #include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/workqueue.h>
 #include <linux/clk.h>
 
 #include <mach/msm_bus.h>
@@ -29,8 +28,6 @@
 #include "pil-q6v4.h"
 #include "scm-pas.h"
 
-#define PROXY_VOTE_TIMEOUT	10000
-
 #define QDSP6SS_RST_EVB		0x0
 #define QDSP6SS_RESET		0x04
 #define QDSP6SS_STRAP_TCM	0x1C
@@ -70,7 +67,7 @@
 	struct regulator *pll_supply;
 	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,
@@ -82,29 +79,23 @@
 	return 0;
 }
 
-static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+static int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
 {
-	return 0;
-}
-
-static int pil_q6v4_make_proxy_votes(struct device *dev)
-{
-	struct q6v4_data *drv = dev_get_drvdata(dev);
+	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
 	int ret;
 
 	ret = clk_prepare_enable(drv->xo);
 	if (ret) {
-		dev_err(dev, "Failed to enable XO\n");
+		dev_err(pil->dev, "Failed to enable XO\n");
 		goto err;
 	}
 	if (drv->pll_supply) {
 		ret = regulator_enable(drv->pll_supply);
 		if (ret) {
-			dev_err(dev, "Failed to enable pll supply\n");
+			dev_err(pil->dev, "Failed to enable pll supply\n");
 			goto err_regulator;
 		}
 	}
-	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 	return 0;
 err_regulator:
 	clk_disable_unprepare(drv->xo);
@@ -112,20 +103,14 @@
 	return ret;
 }
 
-static void pil_q6v4_remove_proxy_votes(struct work_struct *work)
+static void pil_q6v4_remove_proxy_votes(struct pil_desc *pil)
 {
-	struct q6v4_data *drv = container_of(work, struct q6v4_data, work.work);
+	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
 	if (drv->pll_supply)
 		regulator_disable(drv->pll_supply);
 	clk_disable_unprepare(drv->xo);
 }
 
-static void pil_q6v4_remove_proxy_votes_now(struct device *dev)
-{
-	struct q6v4_data *drv = dev_get_drvdata(dev);
-	flush_delayed_work(&drv->work);
-}
-
 static int pil_q6v4_power_up(struct device *dev)
 {
 	int err;
@@ -196,14 +181,10 @@
 
 static int pil_q6v4_reset(struct pil_desc *pil)
 {
-	u32 reg, err = 0;
+	u32 reg, err;
 	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
 	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
 
-	err = pil_q6v4_make_proxy_votes(pil->dev);
-	if (err)
-		return err;
-
 	err = pil_q6v4_power_up(pil->dev);
 	if (err)
 		return err;
@@ -299,16 +280,15 @@
 		drv->vreg_enabled = false;
 	}
 
-	pil_q6v4_remove_proxy_votes_now(pil->dev);
-
 	return 0;
 }
 
 static struct pil_reset_ops pil_q6v4_ops = {
 	.init_image = pil_q6v4_init_image,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_q6v4_reset,
 	.shutdown = pil_q6v4_shutdown,
+	.proxy_vote = pil_q6v4_make_proxy_votes,
+	.proxy_unvote = pil_q6v4_remove_proxy_votes,
 };
 
 static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
@@ -323,10 +303,6 @@
 	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
 	int err;
 
-	err = pil_q6v4_make_proxy_votes(pil->dev);
-	if (err)
-		return err;
-
 	err = pil_q6v4_power_up(pil->dev);
 	if (err)
 		return err;
@@ -356,16 +332,15 @@
 		drv->vreg_enabled = false;
 	}
 
-	pil_q6v4_remove_proxy_votes_now(pil->dev);
-
 	return ret;
 }
 
 static struct pil_reset_ops pil_q6v4_ops_trusted = {
 	.init_image = pil_q6v4_init_image_trusted,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_q6v4_reset_trusted,
 	.shutdown = pil_q6v4_shutdown_trusted,
+	.proxy_vote = pil_q6v4_make_proxy_votes,
+	.proxy_unvote = pil_q6v4_remove_proxy_votes,
 };
 
 static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
@@ -401,7 +376,7 @@
 	if (!desc)
 		return -ENOMEM;
 
-	drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+	drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
 	if (IS_ERR(drv->pll_supply)) {
 		drv->pll_supply = NULL;
 	} else {
@@ -421,6 +396,8 @@
 	desc->name = pdata->name;
 	desc->depends_on = pdata->depends;
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
 
 	if (pas_supported(pdata->pas_id) > 0) {
 		desc->ops = &pil_q6v4_ops_trusted;
@@ -430,7 +407,7 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	drv->vreg = regulator_get(&pdev->dev, "core_vdd");
+	drv->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
 	if (IS_ERR(drv->vreg)) {
 		ret = PTR_ERR(drv->vreg);
 		goto err;
@@ -439,31 +416,26 @@
 	drv->xo = clk_get(&pdev->dev, "xo");
 	if (IS_ERR(drv->xo)) {
 		ret = PTR_ERR(drv->xo);
-		goto err_xo;
+		goto err;
 	}
-	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);
 	clk_put(drv->xo);
-err_xo:
-	regulator_put(drv->vreg);
 err:
-	regulator_put(drv->pll_supply);
 	return ret;
 }
 
 static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
 {
 	struct q6v4_data *drv = platform_get_drvdata(pdev);
-	flush_delayed_work_sync(&drv->work);
 	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..ecbbcb9 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -19,7 +19,6 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
 #include <linux/clk.h>
 
 #include <mach/msm_iomap.h>
@@ -27,8 +26,6 @@
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
-#define PROXY_VOTE_TIMEOUT		10000
-
 #define RIVA_PMU_A2XB_CFG		0xB8
 #define RIVA_PMU_A2XB_CFG_EN		BIT(0)
 
@@ -83,29 +80,32 @@
 	void __iomem *base;
 	unsigned long start_addr;
 	struct clk *xo;
-	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)
+static bool cxo_is_needed(struct riva_data *drv)
 {
-	struct riva_data *drv = dev_get_drvdata(dev);
+	u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
+	return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
+		!= RIVA_PMU_CFG_IRIS_XO_MODE_48;
+}
+
+static int pil_riva_make_proxy_vote(struct pil_desc *pil)
+{
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	int ret;
 
 	ret = regulator_enable(drv->pll_supply);
 	if (ret) {
-		dev_err(dev, "failed to enable pll supply\n");
+		dev_err(pil->dev, "failed to enable pll supply\n");
 		goto err;
 	}
-	if (drv->use_cxo) {
-		ret = clk_prepare_enable(drv->xo);
-		if (ret) {
-			dev_err(dev, "failed to enable xo\n");
-			goto err_clk;
-		}
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "failed to enable xo\n");
+		goto err_clk;
 	}
-	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 	return 0;
 err_clk:
 	regulator_disable(drv->pll_supply);
@@ -113,23 +113,11 @@
 	return ret;
 }
 
-static void pil_riva_remove_proxy_votes(struct work_struct *work)
+static void pil_riva_remove_proxy_vote(struct pil_desc *pil)
 {
-	struct riva_data *drv = container_of(work, struct riva_data, work.work);
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	regulator_disable(drv->pll_supply);
-	if (drv->use_cxo)
-		clk_disable_unprepare(drv->xo);
-}
-
-static void pil_riva_remove_proxy_votes_now(struct device *dev)
-{
-	struct riva_data *drv = dev_get_drvdata(dev);
-	flush_delayed_work(&drv->work);
-}
-
-static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
-	return 0;
+	clk_disable_unprepare(drv->xo);
 }
 
 static int pil_riva_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -141,45 +129,25 @@
 	return 0;
 }
 
-static bool cxo_is_needed(struct riva_data *drv)
-{
-	u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
-	return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
-		!= RIVA_PMU_CFG_IRIS_XO_MODE_48;
-}
-
 static int pil_riva_reset(struct pil_desc *pil)
 {
 	u32 reg, sel;
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *base = drv->base;
 	unsigned long start_addr = drv->start_addr;
-	int ret;
+	bool use_cxo = cxo_is_needed(drv);
 
-	ret = clk_prepare_enable(drv->xo);
-	if (ret)
-		return ret;
 	/* Enable A2XB bridge */
 	reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
 	reg |= RIVA_PMU_A2XB_CFG_EN;
 	writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
 
-	drv->use_cxo = cxo_is_needed(drv);
-	ret = pil_riva_make_proxy_votes(pil->dev);
-	if (ret) {
-		reg &= ~RIVA_PMU_A2XB_CFG_EN;
-		writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
-		mb();
-		clk_disable_unprepare(drv->xo);
-		return ret;
-	}
-
 	/* Program PLL 13 to 960 MHz */
 	reg = readl_relaxed(RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
 	writel_relaxed(reg, RIVA_PLL_MODE);
 
-	if (drv->use_cxo)
+	if (use_cxo)
 		writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
 	else
 		writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
@@ -189,7 +157,7 @@
 
 	reg = readl_relaxed(RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_REF_XO_SEL);
-	reg |= drv->use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
+	reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
 	writel_relaxed(reg, RIVA_PLL_MODE);
 
 	/* Enable PLL 13 */
@@ -254,7 +222,6 @@
 	/* Take cCPU out of reset */
 	reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
 	writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
-	clk_disable_unprepare(drv->xo);
 
 	return 0;
 }
@@ -263,11 +230,7 @@
 {
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	u32 reg;
-	int ret;
 
-	ret = clk_prepare_enable(drv->xo);
-	if (ret)
-		return ret;
 	/* Put cCPU and cCPU clock into reset */
 	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
 	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
@@ -286,17 +249,15 @@
 	writel_relaxed(0, RIVA_RESET);
 	mb();
 
-	clk_disable_unprepare(drv->xo);
-	pil_riva_remove_proxy_votes_now(pil->dev);
-
 	return 0;
 }
 
 static struct pil_reset_ops pil_riva_ops = {
 	.init_image = pil_riva_init_image,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_riva_reset,
 	.shutdown = pil_riva_shutdown,
+	.proxy_vote = pil_riva_make_proxy_vote,
+	.proxy_unvote = pil_riva_remove_proxy_vote,
 };
 
 static int pil_riva_init_image_trusted(struct pil_desc *pil,
@@ -307,40 +268,20 @@
 
 static int pil_riva_reset_trusted(struct pil_desc *pil)
 {
-	struct riva_data *drv = dev_get_drvdata(pil->dev);
-	int ret;
-
-	ret = clk_prepare_enable(drv->xo);
-	if (ret)
-		return ret;
-	/* Proxy-vote for resources RIVA needs */
-	ret = pil_riva_make_proxy_votes(pil->dev);
-	if (!ret)
-		ret = pas_auth_and_reset(PAS_RIVA);
-	clk_disable_unprepare(drv->xo);
-	return ret;
+	return pas_auth_and_reset(PAS_RIVA);
 }
 
 static int pil_riva_shutdown_trusted(struct pil_desc *pil)
 {
-	int ret;
-	struct riva_data *drv = dev_get_drvdata(pil->dev);
-
-	ret = clk_prepare_enable(drv->xo);
-	if (ret)
-		return ret;
-	ret = pas_shutdown(PAS_RIVA);
-	pil_riva_remove_proxy_votes_now(pil->dev);
-	clk_disable_unprepare(drv->xo);
-
-	return ret;
+	return pas_shutdown(PAS_RIVA);
 }
 
 static struct pil_reset_ops pil_riva_ops_trusted = {
 	.init_image = pil_riva_init_image_trusted,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_riva_reset_trusted,
 	.shutdown = pil_riva_shutdown_trusted,
+	.proxy_vote = pil_riva_make_proxy_vote,
+	.proxy_unvote = pil_riva_remove_proxy_vote,
 };
 
 static int __devinit pil_riva_probe(struct platform_device *pdev)
@@ -367,7 +308,7 @@
 	if (!desc)
 		return -ENOMEM;
 
-	drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+	drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
 	if (IS_ERR(drv->pll_supply)) {
 		dev_err(&pdev->dev, "failed to get pll supply\n");
 		return PTR_ERR(drv->pll_supply);
@@ -390,6 +331,8 @@
 
 	desc->name = "wcnss";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
 
 	if (pas_supported(PAS_RIVA) > 0) {
 		desc->ops = &pil_riva_ops_trusted;
@@ -404,26 +347,24 @@
 		ret = PTR_ERR(drv->xo);
 		goto err;
 	}
-	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);
 	clk_put(drv->xo);
 err:
-	regulator_put(drv->pll_supply);
 	return ret;
 }
 
 static int __devexit pil_riva_remove(struct platform_device *pdev)
 {
 	struct riva_data *drv = platform_get_drvdata(pdev);
-	flush_delayed_work_sync(&drv->work);
+	msm_pil_unregister(drv->pil);
 	clk_put(drv->xo);
-	regulator_put(drv->pll_supply);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
index 90ac1d9..2345453 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
@@ -19,11 +19,6 @@
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
-static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
-	return 0;
-}
-
 static int pil_tzapps_init_image(struct pil_desc *pil, const u8 *metadata,
 		size_t size)
 {
@@ -42,7 +37,6 @@
 
 static struct pil_reset_ops pil_tzapps_ops = {
 	.init_image = pil_tzapps_init_image,
-	.verify_blob = nop_verify_blob,
 	.auth_and_reset = pil_tzapps_reset,
 	.shutdown = pil_tzapps_shutdown,
 };
@@ -50,6 +44,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 +56,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 534fc0e..82aeb16 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -17,6 +17,7 @@
 #include <linux/jiffies.h>
 #include <linux/smp.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 
 #include <asm/cacheflush.h>
 #include <asm/hardware/gic.h>
@@ -28,6 +29,8 @@
 #include "pm.h"
 
 #define MSM_CORE1_RESET		0xA8600590
+#define MSM_CORE1_STATUS_MSK	0x02800000
+
 /*
  * control for which core is the next to come out of the secondary
  * boot "holding pen"
@@ -57,9 +60,85 @@
 }
 
 static DEFINE_SPINLOCK(boot_lock);
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+/*
+ * MP_CORE_IPC will be used to generate interrupt and can be used by either
+ * of core.
+ * To bring core1 out of GDFS we need to raise the SPI using the MP_CORE_IPC.
+ */
+static void raise_clear_spi(unsigned int cpu, bool set)
+{
+	int value;
+
+	value = __raw_readl(MSM_CSR_BASE + 0x54);
+	if (set)
+		__raw_writel(value | BIT(cpu), MSM_CSR_BASE + 0x54);
+	else
+		__raw_writel(value & ~BIT(cpu), MSM_CSR_BASE + 0x54);
+	mb();
+}
+
+/*
+ * Configure the GIC after we come out of power collapse.
+ * This function will configure some of the GIC registers so as to prepare the
+ * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
+ * core1 out of GDFS.
+ */
+static void core1_gic_configure_and_raise(void)
+{
+	unsigned int value = 0;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	value = __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_ACTIVE_BIT + 0x4);
+	value |= BIT(8);
+	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_ACTIVE_BIT + 0x4);
+	mb();
+
+	value = __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x24);
+	value |= BIT(13);
+	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x24);
+	mb();
+
+	value = __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x28);
+	value |= BIT(1);
+	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x28);
+	mb();
+
+	value =  __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET + 0x4);
+	value |= BIT(8);
+	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET + 0x4);
+	mb();
+
+	value =  __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET + 0x4);
+	value |= BIT(8);
+	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET + 0x4);
+	mb();
+
+	raise_clear_spi(1, true);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+void clear_pending_spi(unsigned int irq)
+{
+	struct irq_data *d = irq_get_irq_data(irq);
+	struct irq_chip *c = irq_data_get_irq_chip(d);
+
+	/* Clear the IRQ from the ENABLE_SET */
+	c->irq_mask(d);
+	local_irq_disable();
+	gic_clear_spi_pending(irq);
+	c->irq_unmask(d);
+	local_irq_enable();
+}
 
 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
@@ -80,20 +159,53 @@
 	spin_unlock(&boot_lock);
 }
 
+static int  __cpuinit msm8625_release_secondary(void)
+{
+	void __iomem *base_ptr;
+	int value = 0;
+	unsigned long timeout;
+
+	/*
+	 * loop to ensure that the GHS_STATUS_CORE1 bit in the
+	 * MPA5_STATUS_REG(0x3c) is set. The timeout for the while
+	 * loop can be set as 20us as of now
+	 */
+	timeout = jiffies + usecs_to_jiffies(20);
+	while (time_before(jiffies, timeout)) {
+		value = __raw_readl(MSM_CFG_CTL_BASE + 0x3c);
+		if ((value & MSM_CORE1_STATUS_MSK) ==
+				MSM_CORE1_STATUS_MSK)
+			break;
+			udelay(1);
+	}
+
+	if (!value) {
+		pr_err("Core 1 cannot be brought out of Reset!!!\n");
+		return -ENODEV;
+	}
+
+	base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+	if (!base_ptr)
+		return -ENODEV;
+	/* Reset core 1 out of reset */
+	__raw_writel(0x0, base_ptr);
+	mb();
+
+	iounmap(base_ptr);
+
+	return 0;
+}
+
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
 	unsigned long timeout;
-	void __iomem *base_ptr;
 
 	if (cold_boot_done == false) {
-		base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
-		if (!base_ptr)
+		if (msm8625_release_secondary()) {
+			pr_err("Failed to release secondary core\n");
 			return -ENODEV;
-		/* Reset core 1 out of reset */
-		__raw_writel(0x0, base_ptr);
-		mb();
+		}
 		cold_boot_done = true;
-		iounmap(base_ptr);
 	}
 
 	/*
@@ -114,8 +226,16 @@
 	 * Send the secondary CPU a soft interrupt, thereby causing
 	 * the boot monitor to read the system wide flags register,
 	 * and branch to the address found there.
+	 *
+	 * power_collapsed is the flag which will be updated for Powercollapse.
+	 * Once we are out of PC, as Core1 will be in the state of GDFS which
+	 * needs to be brought out by raising an SPI.
 	 */
-	gic_raise_softirq(cpumask_of(cpu), 1);
+
+	if (power_collapsed)
+		core1_gic_configure_and_raise();
+	else
+		gic_raise_softirq(cpumask_of(cpu), 1);
 
 	timeout = jiffies + (1 * HZ);
 	while (time_before(jiffies, timeout)) {
@@ -126,6 +246,13 @@
 		udelay(10);
 	}
 
+	/* Now we should clear the pending SPI */
+	if (power_collapsed) {
+		raise_clear_spi(1, false);
+		clear_pending_spi(MSM8625_INT_ACSR_MP_CORE_IPC1);
+		power_collapsed = 0;
+	}
+
 	/*
 	 * now the secondary core is starting up let it run its
 	 * calibrations, then wait for it to finish
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 6b48d57..668e0c2 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -61,9 +61,9 @@
 	return 0;
 }
 
-static int __cpuinit krait_release_secondary_sim(int cpu)
+static int __cpuinit krait_release_secondary_sim(unsigned long base, int cpu)
 {
-	void *base_ptr = ioremap_nocache(0x02088000 + (cpu * 0x10000), SZ_4K);
+	void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
 	if (!base_ptr)
 		return -ENODEV;
 
@@ -75,14 +75,17 @@
 	if (machine_is_apq8064_sim())
 		writel_relaxed(0xf0000, base_ptr+0x04);
 
+	if (machine_is_copper_sim())
+		writel_relaxed(0x9, base_ptr+0x04);
+
 	mb();
 	iounmap(base_ptr);
 	return 0;
 }
 
-static int __cpuinit krait_release_secondary(int cpu)
+static int __cpuinit krait_release_secondary(unsigned long base, int cpu)
 {
-	void *base_ptr = ioremap_nocache(0x02088000 + (cpu * 0x10000), SZ_4K);
+	void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
 	if (!base_ptr)
 		return -ENODEV;
 
@@ -116,10 +119,13 @@
 
 	if (machine_is_msm8960_sim() || machine_is_msm8960_rumi3() ||
 	    machine_is_apq8064_sim())
-		return krait_release_secondary_sim(cpu);
+		return krait_release_secondary_sim(0x02088000, cpu);
+
+	if (machine_is_copper_sim())
+		return krait_release_secondary_sim(0xf9088000, cpu);
 
 	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064())
-		return krait_release_secondary(cpu);
+		return krait_release_secondary(0x02088000, cpu);
 
 	WARN(1, "unknown CPU case in release_secondary\n");
 	return -EINVAL;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index b3c6d1e..b0fbebb 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -49,7 +49,6 @@
 #include "scm-boot.h"
 #include "spm.h"
 #include "timer.h"
-#include "qdss.h"
 #include "pm-boot.h"
 
 /******************************************************************************
@@ -655,6 +654,10 @@
 	void *entry;
 	bool collapsed = 0;
 	int ret;
+	unsigned int saved_gic_cpu_ctrl;
+
+	saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+	mb();
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: notify_rpm %d\n",
@@ -686,7 +689,9 @@
 #endif
 		cpu_init();
 		writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
-		writel(1, MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+		writel_relaxed(saved_gic_cpu_ctrl,
+				MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+		mb();
 		local_fiq_enable();
 	}
 
@@ -1177,6 +1182,17 @@
 	pmd[0] = __pmd(pmdval);
 	pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
 
+	msm_saved_state_phys =
+		allocate_contiguous_ebi_nomap(CPU_SAVED_STATE_SIZE *
+					      num_possible_cpus(), 4);
+	if (!msm_saved_state_phys)
+		return -ENOMEM;
+	msm_saved_state = ioremap_nocache(msm_saved_state_phys,
+					  CPU_SAVED_STATE_SIZE *
+					  num_possible_cpus());
+	if (!msm_saved_state)
+		return -ENOMEM;
+
 	/* It is remotely possible that the code in msm_pm_collapse_exit()
 	 * which turns on the MMU with this mapping is in the
 	 * next even-numbered megabyte beyond the
@@ -1186,6 +1202,8 @@
 	pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
 	flush_pmd_entry(pmd);
 	msm_pm_pc_pgd = virt_to_phys(pc_pgd);
+	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
+		     virt_to_phys(&msm_pm_pc_pgd));
 
 	ret = request_irq(rpm_cpu0_wakeup_irq,
 			msm_pm_rpm_wakeup_interrupt, IRQF_TRIGGER_RISING,
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index ce09f9f..b5f0fdc 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -28,6 +28,14 @@
 static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
 static void (*msm_pm_boot_after_pc)(unsigned int cpu);
 
+static void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address)
+{
+	msm_pm_boot_vector[cpu] = address;
+	clean_caches((unsigned long)&msm_pm_boot_vector[cpu],
+		     sizeof(msm_pm_boot_vector[cpu]),
+		     virt_to_phys(&msm_pm_boot_vector[cpu]));
+}
+
 #ifdef CONFIG_MSM_SCM
 static int __init msm_pm_tz_boot_init(void)
 {
@@ -101,6 +109,8 @@
 int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
 {
 	int ret = 0;
+	unsigned long entry;
+	void __iomem *warm_boot_ptr;
 
 	switch (pdata->mode) {
 	case MSM_PM_BOOT_CONFIG_TZ:
@@ -123,22 +133,66 @@
 			= msm_pm_config_rst_vector_after_pc;
 		break;
 	case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
-		/*
-		 * Set the boot remap address and enable remapping of
-		 * reset vector
-		 */
-		if (!pdata->p_addr || !pdata->v_addr)
-			return -ENODEV;
+		if (!cpu_is_msm8625()) {
+			void *remapped;
 
-		__raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
-				pdata->v_addr);
+			/*
+			 * Set the boot remap address and enable remapping of
+			 * reset vector
+			 */
+			if (!pdata->p_addr || !pdata->v_addr)
+				return -ENODEV;
 
-		ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
+			remapped = ioremap_nocache(pdata->p_addr, SZ_8);
+			ret = msm_pm_boot_reset_vector_init(remapped);
 
-		msm_pm_boot_before_pc
-			= msm_pm_config_rst_vector_before_pc;
-		msm_pm_boot_after_pc
-			= msm_pm_config_rst_vector_after_pc;
+			__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 {
+			warm_boot_ptr = ioremap_nocache(
+						MSM8625_WARM_BOOT_PHYS, SZ_64);
+			ret = msm_pm_boot_reset_vector_init(warm_boot_ptr);
+
+			entry = virt_to_phys(msm_pm_boot_entry);
+
+			/* Below sequence is a work around for cores
+			 * to come out of GDFS properly on 8625 target.
+			 * On 8625 while cores coming out of GDFS observed
+			 * the memory corruption at very first memory read.
+			 */
+			msm_pm_reset_vector[0] = 0xE59F000C; /* ldr r0, 0x14 */
+			msm_pm_reset_vector[1] = 0xE59F1008; /* ldr r1, 0x14 */
+			msm_pm_reset_vector[2] = 0xE1500001; /* cmp r0, r1 */
+			msm_pm_reset_vector[3] = 0x1AFFFFFB; /* bne 0x0 */
+			msm_pm_reset_vector[4] = 0xE12FFF10; /* bx  r0 */
+			msm_pm_reset_vector[5] = entry; /* 0x14 */
+
+			/* Here upper 16bits[16:31] used by CORE1
+			 * lower 16bits[0:15] used by CORE0
+			 */
+			entry = (MSM8625_WARM_BOOT_PHYS |
+				((MSM8625_WARM_BOOT_PHYS & 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/pm.h b/arch/arm/mach-msm/pm.h
index 892472b..caafbdd 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -27,6 +27,22 @@
 #define msm_secondary_startup NULL
 #endif
 
+extern int power_collapsed;
+
+struct msm_pm_irq_calls {
+	unsigned int (*irq_pending)(void);
+	int (*idle_sleep_allowed)(void);
+	void (*enter_sleep1)(bool modem_wake, int from_idle, uint32_t
+								*irq_mask);
+	int (*enter_sleep2)(bool modem_wake, int from_idle);
+	void (*exit_sleep1)(uint32_t irq_mask, uint32_t wakeup_reason,
+							uint32_t pending_irqs);
+	void (*exit_sleep2)(uint32_t irq_mask, uint32_t wakeup_reason,
+							uint32_t pending_irqs);
+	void (*exit_sleep3)(uint32_t irq_mask, uint32_t wakeup_reason,
+							uint32_t pending_irqs);
+};
+
 enum msm_pm_sleep_mode {
 	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
 	MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
@@ -58,6 +74,7 @@
 };
 
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
+void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
 int msm_pm_idle_prepare(struct cpuidle_device *dev);
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
 void msm_pm_cpu_enter_lowpower(unsigned int cpu);
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 7977d22..a5e52be 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -28,6 +28,7 @@
 #include <linux/reboot.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/tick.h>
 #include <linux/memory.h>
 #ifdef CONFIG_HAS_WAKELOCK
 #include <linux/wakelock.h>
@@ -48,6 +49,8 @@
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN
 #include <mach/msm_migrate_pages.h>
 #endif
+#include <mach/socinfo.h>
+#include <asm/smp_scu.h>
 
 #include "smd_private.h"
 #include "smd_rpcrouter.h"
@@ -62,22 +65,25 @@
 #include "spm.h"
 #include "sirc.h"
 #include "pm-boot.h"
+#define MSM_CORE1_RESET		0xA8600590
 
 /******************************************************************************
  * Debug Definitions
  *****************************************************************************/
 
 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;
+int power_collapsed;
 module_param_named(
 	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
 );
@@ -142,7 +148,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",
@@ -153,6 +158,7 @@
 };
 
 static struct msm_pm_platform_data *msm_pm_modes;
+static struct msm_pm_irq_calls *msm_pm_irq_extns;
 
 struct msm_pm_kobj_attribute {
 	unsigned int cpu;
@@ -396,6 +402,19 @@
 	msm_pm_modes = data;
 }
 
+void __init msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls)
+{
+	/* sanity check */
+	BUG_ON(irq_calls == NULL || irq_calls->irq_pending == NULL ||
+		irq_calls->idle_sleep_allowed == NULL ||
+		irq_calls->enter_sleep1 == NULL ||
+		irq_calls->enter_sleep2 == NULL ||
+		irq_calls->exit_sleep1 == NULL ||
+		irq_calls->exit_sleep2 == NULL ||
+		irq_calls->exit_sleep3 == NULL);
+
+	msm_pm_irq_extns = irq_calls;
+}
 
 /******************************************************************************
  * Sleep Limitations
@@ -419,43 +438,113 @@
  *****************************************************************************/
 
 #if defined(CONFIG_ARCH_MSM7X30)
-#define APPS_CLK_SLEEP_EN (MSM_GCC_BASE + 0x020)
-#define APPS_PWRDOWN      (MSM_ACC_BASE + 0x01c)
+#define APPS_CLK_SLEEP_EN (MSM_APCS_GCC_BASE + 0x020)
+#define APPS_PWRDOWN      (MSM_ACC0_BASE + 0x01c)
 #define APPS_SECOP        (MSM_TCSR_BASE + 0x038)
-#else /* defined(CONFIG_ARCH_MSM7X30) */
+#define APPS_STANDBY_CTL  NULL
+#else
 #define APPS_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
 #define APPS_PWRDOWN      (MSM_CSR_BASE + 0x440)
 #define APPS_STANDBY_CTL  (MSM_CSR_BASE + 0x108)
-#endif /* defined(CONFIG_ARCH_MSM7X30) */
+#define APPS_SECOP	  NULL
+#endif
 
 /*
  * Configure hardware registers in preparation for Apps power down.
  */
 static void msm_pm_config_hw_before_power_down(void)
 {
-#if defined(CONFIG_ARCH_MSM7X30)
-	__raw_writel(1, APPS_PWRDOWN);
+	if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+		__raw_writel(1, APPS_PWRDOWN);
+		mb();
+		__raw_writel(4, APPS_SECOP);
+		mb();
+	} else if (cpu_is_msm7x27()) {
+		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+		mb();
+		__raw_writel(1, APPS_PWRDOWN);
+		mb();
+	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
+		   cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
+		mb();
+		__raw_writel(1, APPS_PWRDOWN);
+		mb();
+	} else {
+		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+		mb();
+		__raw_writel(1, APPS_PWRDOWN);
+		mb();
+		__raw_writel(0, APPS_STANDBY_CTL);
+		mb();
+	}
+}
+
+/*
+ * Program the top csr from core0 context to put the
+ * core1 into GDFS, as core1 is not running yet.
+ */
+static void configure_top_csr(void)
+{
+	void __iomem *base_ptr;
+	unsigned int value = 0;
+
+	base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+	if (!base_ptr)
+		return;
+
+	/* bring the core1 out of reset */
+	__raw_writel(0x3, base_ptr);
 	mb();
-	__raw_writel(4, APPS_SECOP);
+	/*
+	 * override DBGNOPOWERDN and program the GDFS
+	 * count val
+	 */
+
+	 __raw_writel(0x00030002, (MSM_CFG_CTL_BASE + 0x38));
 	mb();
-#elif defined(CONFIG_ARCH_MSM7X27)
-	__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+
+	/* Initialize the SPM0 and SPM1 registers */
+	msm_spm_reinit();
+
+	/* enable TCSR for core1 */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(22);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
 	mb();
-	__raw_writel(1, APPS_PWRDOWN);
+
+	/* set reset bit for SPM1 */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(20);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
 	mb();
-#elif defined(CONFIG_ARCH_MSM7x27A)
-	__raw_writel(0x7, APPS_CLK_SLEEP_EN);
+
+	/* set CLK_OFF bit */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(18);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
 	mb();
-	__raw_writel(1, APPS_PWRDOWN);
+
+	/* set clamps bit */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(21);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
 	mb();
-#else
-	__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+
+	/* set power_up bit */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(19);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
 	mb();
-	__raw_writel(1, APPS_PWRDOWN);
+
+	/* Disable TSCR for core0 */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value &= ~BIT(22);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
 	mb();
-	__raw_writel(0, APPS_STANDBY_CTL);
+	__raw_writel(0x0, base_ptr);
 	mb();
-#endif
+	iounmap(base_ptr);
 }
 
 /*
@@ -463,23 +552,31 @@
  */
 static void msm_pm_config_hw_after_power_up(void)
 {
-#if defined(CONFIG_ARCH_MSM7X30)
-	__raw_writel(0, APPS_SECOP);
-	mb();
-	__raw_writel(0, APPS_PWRDOWN);
-	mb();
-	msm_spm_reinit();
-#elif defined(CONFIG_ARCH_MSM7x27A)
-	__raw_writel(0, APPS_PWRDOWN);
-	mb();
-	__raw_writel(0, APPS_CLK_SLEEP_EN);
-	mb();
-#else
-	__raw_writel(0, APPS_PWRDOWN);
-	mb();
-	__raw_writel(0, APPS_CLK_SLEEP_EN);
-	mb();
-#endif
+
+	if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+		__raw_writel(0, APPS_SECOP);
+		mb();
+		__raw_writel(0, APPS_PWRDOWN);
+		mb();
+		msm_spm_reinit();
+	} else {
+		__raw_writel(0, APPS_PWRDOWN);
+		mb();
+		__raw_writel(0, APPS_CLK_SLEEP_EN);
+		mb();
+
+		if (cpu_is_msm8625()) {
+			/*
+			 * enable the SCU while coming out of power
+			 * collapse.
+			 */
+			scu_enable(MSM_SCU_BASE);
+			/*
+			 * Program the top csr to put the core1 into GDFS.
+			 */
+			configure_top_csr();
+		}
+	}
 }
 
 /*
@@ -487,16 +584,17 @@
  */
 static void msm_pm_config_hw_before_swfi(void)
 {
-#if defined(CONFIG_ARCH_QSD8X50)
-	__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
-	mb();
-#elif defined(CONFIG_ARCH_MSM7X27)
-	__raw_writel(0x0f, APPS_CLK_SLEEP_EN);
-	mb();
-#elif defined(CONFIG_ARCH_MSM7X27A)
-	__raw_writel(0x7, APPS_CLK_SLEEP_EN);
-	mb();
-#endif
+	if (cpu_is_qsd8x50()) {
+		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+		mb();
+	} else if (cpu_is_msm7x27()) {
+		__raw_writel(0x0f, APPS_CLK_SLEEP_EN);
+		mb();
+	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
+		   cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
+		mb();
+	}
 }
 
 /*
@@ -682,8 +780,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,7 +1104,15 @@
 
 	memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
 
-	msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask);
+	if (cpu_is_msm8625()) {
+		/* Program the SPM */
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE,
+									false);
+		WARN_ON(ret);
+	}
+
+	msm_pm_irq_extns->enter_sleep1(true, from_idle,
+						&msm_pm_smem_data->irq_mask);
 	msm_sirc_enter_sleep();
 	msm_gpio_enter_sleep(from_idle);
 
@@ -1054,7 +1158,7 @@
 
 	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA");
 
-	ret = msm_irq_enter_sleep2(true, from_idle);
+	ret = msm_pm_irq_extns->enter_sleep2(true, from_idle);
 	if (ret < 0) {
 		MSM_PM_DPRINTK(
 			MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
@@ -1090,6 +1194,8 @@
 #endif
 
 	collapsed = msm_pm_collapse();
+	if (collapsed)
+		power_collapsed = 1;
 
 #ifdef CONFIG_CACHE_L2X0
 	l2x0_resume(collapsed);
@@ -1118,7 +1224,7 @@
 		printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n",
 			__func__, saved_acpuclk_rate);
 
-	msm_irq_exit_sleep1(msm_pm_smem_data->irq_mask,
+	msm_pm_irq_extns->exit_sleep1(msm_pm_smem_data->irq_mask,
 		msm_pm_smem_data->wakeup_reason,
 		msm_pm_smem_data->pending_irqs);
 
@@ -1195,10 +1301,10 @@
 	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN");
 	MSM_PM_DEBUG_PRINT_SLEEP_INFO();
 
-	msm_irq_exit_sleep2(msm_pm_smem_data->irq_mask,
+	msm_pm_irq_extns->exit_sleep2(msm_pm_smem_data->irq_mask,
 		msm_pm_smem_data->wakeup_reason,
 		msm_pm_smem_data->pending_irqs);
-	msm_irq_exit_sleep3(msm_pm_smem_data->irq_mask,
+	msm_pm_irq_extns->exit_sleep3(msm_pm_smem_data->irq_mask,
 		msm_pm_smem_data->wakeup_reason,
 		msm_pm_smem_data->pending_irqs);
 	msm_gpio_exit_sleep();
@@ -1210,6 +1316,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 +1376,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 +1391,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 +1403,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());
@@ -1317,19 +1442,7 @@
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
 	WARN_ON(ret);
 
-	return 0;
-}
-
-/*
- * 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;
+	return !collapsed;
 }
 
 /*
@@ -1353,7 +1466,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) {
@@ -1383,19 +1498,17 @@
 	bool allow[MSM_PM_SLEEP_MODE_NR];
 	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
 
-	int latency_qos;
 	int64_t timer_expiration;
-
-	int low_power;
+	int latency_qos;
 	int ret;
 	int i;
 	unsigned int cpu;
 
 #ifdef CONFIG_MSM_IDLE_STATS
 	int64_t t1;
-	static int64_t t2;
+	static DEFINE_PER_CPU(int64_t, t2);
 	int exit_stat;
- #endif /* CONFIG_MSM_IDLE_STATS */
+ #endif
 
 	if (!atomic_read(&msm_pm_init_done))
 		return;
@@ -1403,28 +1516,27 @@
 	cpu = smp_processor_id();
 
 	latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-	timer_expiration = msm_timer_enter_idle();
+	/* get the next timer expiration */
+	timer_expiration = ktime_to_ns(tick_nohz_get_sleep_length());
 
 #ifdef CONFIG_MSM_IDLE_STATS
 	t1 = ktime_to_ns(ktime_get());
-	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
+	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - __get_cpu_var(t2));
 	msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
-
 	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()) {
+		!msm_pm_irq_extns->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++) {
@@ -1467,10 +1579,16 @@
 
 	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
+		/* Sync the timer with SCLK, it is needed only for modem
+		 * assissted pollapse case.
+		 */
+		int64_t next_timer_exp = msm_timer_enter_idle();
 		uint32_t sleep_delay;
+		bool low_power = false;
 
 		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
-			timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+			next_timer_exp, MSM_PM_SLEEP_TICK_LIMIT);
+
 		if (sleep_delay == 0) /* 0 would mean infinite time */
 			sleep_delay = 1;
 
@@ -1485,6 +1603,7 @@
 
 		ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit);
 		low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
+		msm_timer_exit_idle(low_power);
 
 #ifdef CONFIG_MSM_IDLE_STATS
 		if (ret)
@@ -1493,68 +1612,46 @@
 			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();
-		low_power = 0;
+		ret = msm_pm_power_collapse_standalone(true);
 #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)
-			while (!msm_irq_pending())
+			while (!msm_pm_irq_extns->irq_pending())
 				udelay(1);
-		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())
+		while (!msm_pm_irq_extns->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);
-
 #ifdef CONFIG_MSM_IDLE_STATS
-	t2 = ktime_to_ns(ktime_get());
-	msm_pm_add_stat(exit_stat, t2 - t1);
-#endif /* CONFIG_MSM_IDLE_STATS */
+	__get_cpu_var(t2) = ktime_to_ns(ktime_get());
+	msm_pm_add_stat(exit_stat, __get_cpu_var(t2) - t1);
+#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 +1663,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 +1693,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,16 +1749,17 @@
 		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)
-			while (!msm_irq_pending())
+			while (!msm_pm_irq_extns->irq_pending())
 				udelay(1);
 	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
 		msm_pm_swfi(false);
 	}
 
+suspend_exit:
 	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
 		"%s(): return %d\n", __func__, ret);
 
@@ -1673,7 +1776,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 +1848,6 @@
 };
 
 
-/******************************************************************************
- *
- *****************************************************************************/
-
 /*
  * Initialize the power management subsystem.
  *
@@ -1743,6 +1862,7 @@
 	unsigned int cpu;
 #endif
 	int ret;
+	int val;
 #ifdef CONFIG_CPU_V7
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
@@ -1760,6 +1880,17 @@
 	pmd[0] = __pmd(pmdval);
 	pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
 
+	msm_saved_state_phys =
+		allocate_contiguous_ebi_nomap(CPU_SAVED_STATE_SIZE *
+					      num_possible_cpus(), 4);
+	if (!msm_saved_state_phys)
+		return -ENOMEM;
+	msm_saved_state = ioremap_nocache(msm_saved_state_phys,
+					  CPU_SAVED_STATE_SIZE *
+					  num_possible_cpus());
+	if (!msm_saved_state)
+		return -ENOMEM;
+
 	/* It is remotely possible that the code in msm_pm_collapse_exit()
 	 * which turns on the MMU with this mapping is in the
 	 * next even-numbered megabyte beyond the
@@ -1769,6 +1900,8 @@
 	pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
 	flush_pmd_entry(pmd);
 	msm_pm_pc_pgd = virt_to_phys(pc_pgd);
+	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
+		     virt_to_phys(&msm_pm_pc_pgd));
 #endif
 
 	pm_power_off = msm_pm_power_off;
@@ -1793,6 +1926,19 @@
 		return ret;
 	}
 
+	if (cpu_is_msm8625()) {
+		target_type = TARGET_IS_8625;
+		clean_caches((unsigned long)&target_type, sizeof(target_type),
+				virt_to_phys(&target_type));
+
+		/* Override the DBGNOPOWERDN for each cpu in
+		 * MPA5_GDFS_CNT_VAL register
+		 */
+		val = __raw_readl((MSM_CFG_CTL_BASE + 0x38));
+		val = val | 0x00030000;
+		__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
+	}
+
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
 	/* The wakeup_reason field is overloaded during initialization time
 	   to signal Modem that Apps will control the low power modes of
@@ -1804,7 +1950,6 @@
 
 	BUG_ON(msm_pm_modes == NULL);
 
-	atomic_set(&msm_pm_init_done, 1);
 	suspend_set_ops(&msm_pm_ops);
 
 	msm_pm_mode_sysfs_add();
@@ -1837,15 +1982,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 =
@@ -1869,6 +2005,9 @@
 		stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
 			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
 	}
+
+	atomic_set(&msm_pm_init_done, 1);
+
 	d_entry = create_proc_entry("msm_pm_stats",
 			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
 	if (d_entry) {
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 81d4e5b..1f82468 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.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
@@ -14,24 +14,28 @@
 #include <asm/pmu.h>
 #include <mach/irqs.h>
 
-static struct resource cpu_pmu_resource = {
-	.start = INT_ARMQC_PERFMON,
-	.end = INT_ARMQC_PERFMON,
-	.flags	= IORESOURCE_IRQ,
+static struct resource cpu_pmu_resource[] = {
+	{
+		.start = INT_ARMQC_PERFMON,
+		.end = INT_ARMQC_PERFMON,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 #ifdef CONFIG_CPU_HAS_L2_PMU
-static struct resource l2_pmu_resource = {
-	.start = SC_SICL2PERFMONIRPTREQ,
-	.end = SC_SICL2PERFMONIRPTREQ,
-	.flags = IORESOURCE_IRQ,
+static struct resource l2_pmu_resource[] = {
+	{
+		.start = SC_SICL2PERFMONIRPTREQ,
+		.end = SC_SICL2PERFMONIRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
 static struct platform_device l2_pmu_device = {
 	.name		= "l2-arm-pmu",
 	.id		= ARM_PMU_DEVICE_L2,
-	.resource	= &l2_pmu_resource,
-	.num_resources	= 1,
+	.resource	= l2_pmu_resource,
+	.num_resources	= ARRAY_SIZE(l2_pmu_resource),
 };
 
 #endif
@@ -39,8 +43,8 @@
 static struct platform_device cpu_pmu_device = {
 	.name		= "cpu-arm-pmu",
 	.id		= ARM_PMU_DEVICE_CPU,
-	.resource	= &cpu_pmu_resource,
-	.num_resources	= 1,
+	.resource	= cpu_pmu_resource,
+	.num_resources	= ARRAY_SIZE(cpu_pmu_resource),
 };
 
 static struct platform_device *pmu_devices[] = {
diff --git a/arch/arm/mach-msm/proc_comm.c b/arch/arm/mach-msm/proc_comm.c
index 6f92b27..05b574b 100644
--- a/arch/arm/mach-msm/proc_comm.c
+++ b/arch/arm/mach-msm/proc_comm.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/proc_comm.c
  *
  * Copyright (C) 2007-2008 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -31,7 +31,7 @@
 	/* Make sure the write completes before interrupt */
 	wmb();
 #if defined(CONFIG_ARCH_MSM7X30)
-	__raw_writel(1 << 6, MSM_GCC_BASE + 0x8);
+	__raw_writel(1 << 6, MSM_APCS_GCC_BASE + 0x8);
 #elif defined(CONFIG_ARCH_MSM8X60)
 	__raw_writel(1 << 5, MSM_GCC_BASE + 0x8);
 #else
diff --git a/arch/arm/mach-msm/proccomm-regulator.c b/arch/arm/mach-msm/proccomm-regulator.c
index ba10d38..fff3a11 100644
--- a/arch/arm/mach-msm/proccomm-regulator.c
+++ b/arch/arm/mach-msm/proccomm-regulator.c
@@ -196,7 +196,7 @@
 static struct regulator_dev *__devinit create_proccomm_rdev(
 	struct proccomm_regulator_info *info, struct device *parent)
 {
-	char *name;
+	const char *name;
 	struct proccomm_regulator_drvdata *d;
 	struct regulator_dev *rdev;
 	int rc = 0;
@@ -247,7 +247,7 @@
 	d->negative	= info->negative;
 	d->rdesc.n_voltages = info->n_voltages;
 
-	rdev = regulator_register(&d->rdesc, parent, &info->init_data, d);
+	rdev = regulator_register(&d->rdesc, parent, &info->init_data, d, NULL);
 
 	if (IS_ERR(rdev)) {
 		rc = PTR_ERR(rdev);
diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile
index a4a43ed..2ce0031 100644
--- a/arch/arm/mach-msm/qdsp5/Makefile
+++ b/arch/arm/mach-msm/qdsp5/Makefile
@@ -17,3 +17,4 @@
 obj-y += snd.o snd_adie.o
 obj-$(CONFIG_ARCH_MSM7X27A) += audio_fm.o
 obj-$(CONFIG_ARCH_MSM7X27A) += audio_mvs.o
+obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 33c5a53..71e0409 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -3,7 +3,7 @@
  * Register/Interrupt access for userspace aDSP library.
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -58,8 +58,6 @@
 #include <mach/msm_adsp.h>
 #include "adsp.h"
 
-#define INT_ADSP INT_ADSP_A9_A11
-
 static struct adsp_info adsp_info;
 static struct msm_rpc_endpoint *rpc_cb_server_client;
 static struct msm_adsp_module *adsp_modules;
@@ -280,6 +278,7 @@
 	int rc = 0;
 	static uint32_t init_info_cmd_sent;
 
+	mutex_lock(&adsp_info.lock);
 	if (!init_info_cmd_sent) {
 		init_waitqueue_head(&adsp_info.init_info_wait);
 		msm_get_init_info();
@@ -288,10 +287,13 @@
 			5 * HZ);
 		if (!rc) {
 			MM_ERR("INIT_INFO failed\n");
+			mutex_unlock(&adsp_info.lock);
 			return -ETIMEDOUT;
+
 		}
 		init_info_cmd_sent++;
 	}
+	mutex_unlock(&adsp_info.lock);
 
 	module = find_adsp_module_by_name(&adsp_info, name);
 	if (!module)
@@ -1016,16 +1018,50 @@
 
 int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
 {
+	if (!module)
+		return -EINVAL;
+
 	if (module->clk && clk_rate)
 		return clk_set_rate(module->clk, clk_rate);
 
 	return -EINVAL;
 }
 
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg)
+{
+	unsigned long flags;
+	void (*func)(void *, size_t);
+
+	if (!mod)
+		return -EINVAL;
+
+	if (event_size == sizeof(uint32_t))
+		func = read_event_32;
+	else if (event_size == sizeof(uint16_t))
+		func = read_event_16;
+	else
+		return -EINVAL;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+	read_event_addr = msg;
+	read_event_size = event_length;
+	mod->ops->event(data, event_id, event_length, func);
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return 0;
+}
+
 int msm_adsp_enable(struct msm_adsp_module *module)
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	MM_INFO("enable '%s'state[%d] id[%d]\n",
 				module->name, module->state, module->id);
 
@@ -1049,11 +1085,11 @@
 			rc = -ETIMEDOUT;
 		}
 		if (module->open_count++ == 0 && module->clk)
-			clk_enable(module->clk);
+			clk_prepare_enable(module->clk);
 
 		mutex_lock(&adsp_open_lock);
 		if (adsp_open_count++ == 0) {
-			enable_irq(INT_ADSP);
+			enable_irq(adsp_info.int_adsp);
 			prevent_suspend();
 		}
 		mutex_unlock(&adsp_open_lock);
@@ -1078,6 +1114,9 @@
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	mutex_lock(&module->lock);
 
 	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
@@ -1092,6 +1131,9 @@
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	switch (module->state) {
 	case ADSP_STATE_DISABLED:
 		MM_DBG("module '%s' already disabled\n", module->name);
@@ -1102,10 +1144,10 @@
 						module->id, module);
 		module->state = ADSP_STATE_DISABLED;
 		if (--module->open_count == 0 && module->clk)
-			clk_disable(module->clk);
+			clk_disable_unprepare(module->clk);
 		mutex_lock(&adsp_open_lock);
 		if (--adsp_open_count == 0) {
-			disable_irq(INT_ADSP);
+			disable_irq(adsp_info.int_adsp);
 			allow_suspend();
 			MM_DBG("disable interrupt\n");
 		}
@@ -1117,6 +1159,10 @@
 int msm_adsp_disable(struct msm_adsp_module *module)
 {
 	int rc;
+
+	if (!module)
+		return -EINVAL;
+
 	MM_INFO("disable '%s'\n", module->name);
 	mutex_lock(&module->lock);
 	rc = msm_adsp_disable_locked(module);
@@ -1130,8 +1176,11 @@
 	unsigned count;
 	int rc, i;
 
-	if (pdev->id != (rpc_adsp_rtos_atom_vers & RPC_VERSION_MAJOR_MASK))
-		return -EINVAL;
+	adsp_info.int_adsp = platform_get_irq(pdev, 0);
+	if (adsp_info.int_adsp < 0) {
+		MM_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
 
 	wake_lock_init(&adsp_wake_lock, WAKE_LOCK_SUSPEND, "adsp");
 	adsp_info.init_info_ptr = kzalloc(
@@ -1157,12 +1206,13 @@
 
 	spin_lock_init(&adsp_cmd_lock);
 	spin_lock_init(&adsp_write_lock);
+	mutex_init(&adsp_info.lock);
 
-	rc = request_irq(INT_ADSP, adsp_irq_handler, IRQF_TRIGGER_RISING,
-			 "adsp", 0);
+	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);
 
 	rpc_cb_server_client = msm_rpc_open();
 	if (IS_ERR(rpc_cb_server_client)) {
@@ -1214,8 +1264,8 @@
 	msm_rpc_close(rpc_cb_server_client);
 	rpc_cb_server_client = NULL;
 fail_rpc_open:
-	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);
@@ -1344,7 +1394,7 @@
 	},
 };
 
-static char msm_adsp_driver_name[] = "rs00000000";
+static const char msm_adsp_driver_name[] = "msm_adsp";
 
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations adsp_debug_fops = {
@@ -1383,9 +1433,6 @@
 	rpc_adsp_rtos_mtoa_vers_comp = 0x00030001;
 #endif
 
-	snprintf(msm_adsp_driver_name, sizeof(msm_adsp_driver_name),
-		"rs%08x",
-		rpc_adsp_rtos_atom_prog);
 	msm_adsp_driver.driver.name = msm_adsp_driver_name;
 	rc = platform_driver_register(&msm_adsp_driver);
 	MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 0ef27b9..0f16111 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/qdsp5/adsp.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, 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
@@ -117,6 +117,10 @@
 	struct adsp_rtos_mp_mtoa_init_info_type	*init_info_ptr;
 	wait_queue_head_t	init_info_wait;
 	unsigned 		init_info_state;
+	struct mutex lock;
+
+	/* Interrupt value */
+	int int_adsp;
 };
 
 #define RPC_ADSP_RTOS_ATOM_NULL_PROC 0
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 5e1e655..de756eb 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-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
@@ -298,6 +298,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -672,24 +673,31 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static int audaac_validate_usr_config(struct msm_audio_aac_config *config)
@@ -990,7 +998,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index c9e60d8..456a8ff 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -2,7 +2,7 @@
  *
  * aac audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_aac_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -320,9 +320,10 @@
 
 		audaac_in_dsp_enable(audio, 0);
 
-		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -697,21 +698,23 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audaac_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audaac_out_flush(audio);
+	audaac_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audaac_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audaac_in_flush(struct audio_aac_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
@@ -720,6 +723,7 @@
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -729,15 +733,18 @@
 static void audaac_out_flush(struct audio_aac_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -777,7 +784,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audaac_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 476a63d..d66a270 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * amrnb audio decoder device
  *
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -302,6 +302,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -628,24 +629,31 @@
 
 static void audamrnb_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audamrnb_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audamrnb_ioport_reset(struct audio *audio)
@@ -876,7 +884,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audamrnb_disable(audio);
-		audio->stopped = 1;
 		audamrnb_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index e811731..b566c60 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -6,7 +6,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -299,6 +299,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -616,25 +617,32 @@
 
 static void audamrwb_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audamrwb_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audamrwb_ioport_reset(struct audio *audio)
@@ -865,7 +873,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audamrwb_disable(audio);
-		audio->stopped = 1;
 		audamrwb_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 3c39b6d..86035db 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/audio_evrc.c
  *
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This code also borrows from audio_aac.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -291,6 +291,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -615,24 +616,30 @@
 
 static void audevrc_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audevrc_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
-
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audevrc_ioport_reset(struct audio *audio)
@@ -863,7 +870,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audevrc_disable(audio);
-		audio->stopped = 1;
 		audevrc_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 7a5536a..0bdbf5d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -2,7 +2,7 @@
  *
  * evrc audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -281,6 +281,8 @@
 		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -655,21 +657,23 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audevrc_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audevrc_out_flush(audio);
+	audevrc_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audevrc_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audevrc_in_flush(struct audio_evrc_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
@@ -678,6 +682,7 @@
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -687,15 +692,18 @@
 static void audevrc_out_flush(struct audio_evrc_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -735,7 +743,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audevrc_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
new file mode 100644
index 0000000..8760e443
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -0,0 +1,1485 @@
+
+/* audio_lpa.c - low power audio driver
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the PCM decoder driver in arch/arm/mach-msm/qdsp5/audio_pcm.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_subsystem_map.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+
+#define MSM_MAX_VOLUME 0x2000
+/* 17 added to avoid more deviation */
+#define MSM_VOLUME_STEP (MSM_MAX_VOLUME+17)
+#define MSM_VOLUME_FACTOR (10000)
+
+/* Size must be power of 2 */
+#define MAX_BUF 2
+#define BUFSZ (1024000)
+
+#define AUDDEC_DEC_PCM 0
+
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define  AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDPCM_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct audio;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audpcm_suspend_ctl {
+struct early_suspend node;
+struct audio *audio;
+};
+#endif
+
+struct audpcm_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audlpa_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audpcm_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	struct list_head out_queue; /* queue to retain output buffers */
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_bits; /* bits per sample */
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;
+	struct msm_mapped_buffer *map_v_write;
+
+	uint32_t drv_status;
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	int rmt_resource_released;
+	enum msm_aud_decoder_state dec_state; /* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+
+	unsigned long volume;
+
+	uint16_t dec_id;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audpcm_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	struct list_head pmem_region_queue;
+	int buffer_count;
+	int buffer_size;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+	unsigned long len, int ref_up);
+static void audpcm_async_send_data(struct audio *audio,
+	unsigned needed);
+
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_PCM;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_PCM;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc)
+			MM_ERR("ADSP resources are not available");
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audpcm_async_send_data(audio, 1);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder\n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason =0x%04x\n",
+						reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+						|| (reason ==
+						AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+					0);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_ERR("CFG_MSG %d?\n",	msg[0]);
+		}
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+
+struct msm_adsp_ops audlpadec_adsp_ops = {
+	.event = audplay_dsp_event,
+};
+
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_PCM;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	audpp_cmd_cfg_adec_params_wav cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.stereo_cfg = audio->out_channel_mode;
+	cmd.pcm_width = audio->out_bits;
+	cmd.sign = 0;
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+static void audpcm_async_send_data(struct audio *audio, unsigned needed)
+{
+	unsigned long flags;
+
+	if (!audio->running)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload payload;
+			struct audpcm_buffer_node *used_buf;
+
+			MM_DBG("consumed\n");
+
+			BUG_ON(list_empty(&audio->out_queue));
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audpcm_buffer_node, list);
+			list_del(&used_buf->list);
+			payload.aio_buf = used_buf->buf;
+			audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+			kfree(used_buf);
+			audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		}
+	}
+	if (audio->out_needed) {
+		struct audpcm_buffer_node *next_buf;
+		audplay_cmd_bitstream_data_avail cmd;
+		if (!list_empty(&audio->out_queue)) {
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audpcm_buffer_node, list);
+			MM_DBG("next_buf %p\n", next_buf);
+			if (next_buf) {
+				MM_DBG("next buf phy %lx len %d\n",
+				next_buf->paddr, next_buf->buf.data_len);
+
+				cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+				if (next_buf->buf.data_len)
+					cmd.decoder_id = audio->dec_id;
+				else {
+					cmd.decoder_id = -1;
+					MM_DBG("input EOS signaled\n");
+				}
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				/* complete writes to the input buffer */
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static void audpcm_async_flush(struct audio *audio)
+{
+	struct audpcm_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audpcm_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+static void audio_ioport_reset(struct audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			MM_DBG("fsync in progress\n");
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audpcm_async_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		} else
+			audpcm_async_flush(audio);
+	} else {
+		/* Make sure read/write thread are free from
+		 * sleep and knowing that system is not able
+		 * to process io request at the moment
+		 */
+		wake_up(&audio->write_wait);
+		mutex_lock(&audio->write_lock);
+		audpcm_async_flush(audio);
+		mutex_unlock(&audio->write_lock);
+	}
+}
+
+static int audpcm_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audpcm_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audpcm_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audpcm_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audpcm_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audpcm_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audpcm_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt && drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		mutex_lock(&audio->lock);
+		audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audlpa_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audlpa_pmem_region *region_elt;
+	struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				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)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audlpa_pmem_region *region;
+	int rc = -EINVAL;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audlpa_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
+			region->vaddr, region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+end:
+	return rc;
+}
+
+static int audlpa_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+		    (region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				MM_DBG("region %p in use ref_cnt %d\n",
+						region, region->ref_cnt);
+				break;
+			}
+			MM_DBG("remove region fd %d vaddr %p\n",
+				info->fd, info->vaddr);
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audlpa_pmem_region **region)
+{
+	struct audlpa_pmem_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) {
+		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
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("multiple hits for vaddr %p, len %ld\n", 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)
+				MM_ERR("\t%p, %ld --> %p\n", 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)
+{
+	struct audlpa_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audlpa_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	MM_DBG("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audlpa_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	unsigned long flags;
+	struct audpcm_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	MM_DBG("node %p dir %x buf_addr %p buf_len %d data_len"
+			"%d\n", buf_node, dir,
+			buf_node->buf.buf_addr, buf_node->buf.buf_len,
+			buf_node->buf.data_len);
+
+	buf_node->paddr = audlpa_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		audpcm_async_send_data(audio, 0);
+	}
+	MM_DBG("Add buf_node %p paddr %lx\n", buf_node, buf_node->paddr);
+
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+
+		audio->volume = MSM_VOLUME_STEP * arg;
+		audio->volume /= MSM_VOLUME_FACTOR;
+
+		if (audio->volume > MSM_MAX_VOLUME)
+			audio->volume = MSM_MAX_VOLUME;
+
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id,
+			audio->volume, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audpcm_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.bits == 8)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_8;
+		else if (config.bits == 16)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+		else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_bits = config.bits;
+		audio->buffer_count = config.buffer_count;
+		audio->buffer_size = config.buffer_size;
+		MM_DBG("AUDIO_SET_CONFIG\n");
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_count = audio->buffer_count;
+		config.buffer_size = audio->buffer_size;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_8)
+			config.bits = 8;
+		else if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_16)
+			config.bits = 16;
+		else
+			config.bits = 16;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		MM_DBG("AUDIO_GET_CONFIG\n");
+		break;
+	}
+
+
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_REGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_remove(audio, &info);
+			break;
+		}
+
+	case AUDIO_ASYNC_WRITE:
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audlpa_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_ASYNC_READ:
+		MM_ERR("AUDIO_ASYNC_READ not supported\n");
+		rc = -EPERM;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audlpa_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->teos && audio->out_needed &&
+		list_empty(&audio->out_queue))
+		|| audio->wflush || audio->stopped);
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audlpa_sync_fsync(struct audio *audio)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audpcm_async_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+int audlpa_fsync(struct file *file, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	if (!audio->running)
+		return -EINVAL;
+
+	return audlpa_async_fsync(audio);
+}
+
+static void audpcm_reset_pmem_region(struct audio *audio)
+{
+	struct audlpa_pmem_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_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audpcm_async_flush(audio);
+	audpcm_reset_pmem_region(audio);
+
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audpcm_reset_event_queue(audio);
+	MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
+	if (audio->data) {
+		msm_subsystem_unmap_buffer(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audpcm_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audpcm_suspend(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audpcm_resume(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audpcm_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audpcm_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %lx\n", audio->volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d\n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d\n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d\n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				"dec state %d\n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d\n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d\n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d\n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d\n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d\n", audio->out[1].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audpcm_debug_fops = {
+	.read = audpcm_debug_read,
+	.open = audpcm_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb, decid;
+	struct audpcm_event *e_node = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_lpa_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_PCM;
+	if (file->f_mode & FMODE_READ) {
+		MM_ERR("Non-Tunneled mode not supported\n");
+		rc = -EPERM;
+		kfree(audio);
+		goto done;
+	} else
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available\n");
+		rc = -ENODEV;
+		MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->buffer_size = BUFSZ;
+	audio->buffer_count = MAX_BUF;
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto err;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audlpadec_adsp_ops, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module\n", audio->module_name);
+		audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for PCM session");
+		audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	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->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+	audio->volume = 0x2000;
+	audpcm_async_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_pcm_lp_dec_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+		NULL, (void *) audio, &audpcm_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audpcm_resume;
+	audio->suspend_ctl.node.suspend = audpcm_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDPCM_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	audpp_adec_free(audio->dec_id);
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_pcm_lp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync = audlpa_fsync,
+};
+
+struct miscdevice audio_lpa_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_lp_dec",
+	.fops	= &audio_pcm_lp_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_lpa_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index c4b464a..f6fa62a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.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 software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -368,6 +368,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -853,12 +854,16 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -885,13 +890,15 @@
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
-
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -1366,7 +1373,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 9c27485..5ccd18b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -25,7 +25,7 @@
 
 #define MVS_PROG 0x30000014
 #define MVS_VERS 0x00030001
-#define MVS_VERS_COMP_VER2 0x00020001
+#define MVS_VERS_COMP_VER2 0x00060001
 #define MVS_VERS_COMP_VER3 0x00030001
 
 
@@ -67,6 +67,8 @@
 #define MVS_FRAME_MODE_G711_DL 10
 #define MVS_FRAME_MODE_PCM_UL 13
 #define MVS_FRAME_MODE_PCM_DL 14
+#define MVS_FRAME_MODE_PCM_WB_UL 23
+#define MVS_FRAME_MODE_PCM_WB_DL 24
 #define MVS_FRAME_MODE_G729A_UL 17
 #define MVS_FRAME_MODE_G729A_DL 18
 #define MVS_FRAME_MODE_G711A_UL 19
@@ -404,6 +406,11 @@
 		audio->frame_mode = MVS_FRAME_MODE_PCM_DL;
 		break;
 	}
+	case MVS_MODE_PCM_WB: {
+		audio->rate_type = MVS_AMR_MODE_UNDEF;
+		audio->frame_mode = MVS_FRAME_MODE_PCM_WB_DL;
+		break;
+	}
 	case MVS_MODE_IS127:
 	case MVS_MODE_IS733:
 	case MVS_MODE_4GV_NB:
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 7c56037..8fe8cf66 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 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
@@ -21,6 +22,7 @@
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
 #include <linux/kthread.h>
+#include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
@@ -46,6 +48,21 @@
 #define LOG_AUDIO_EVENTS 1
 #define LOG_AUDIO_FAULTS 0
 
+#define SRS_ID_GLOBAL			0x00000001
+#define SRS_ID_WOWHD			0x00000002
+#define SRS_ID_CSHP			0x00000003
+#define SRS_ID_HPF			0x00000004
+#define SRS_ID_PEQ			0x00000005
+#define SRS_ID_HL			0x00000006
+
+#define SRS_MASK_G 1
+#define SRS_MASK_W 2
+#define SRS_MASK_C 4
+#define SRS_MASK_HP 8
+#define SRS_MASK_P 16
+#define SRS_MASK_HL 32
+
+
 enum {
 	EV_NULL,
 	EV_OPEN,
@@ -163,6 +180,10 @@
 
 	int qconcert_plus_enable;
 	int qconcert_plus_needs_commit;
+
+	int srs_enable;
+	int srs_needs_commit;
+	int srs_feature_mask;
 	audpp_cmd_cfg_object_params_qconcert qconcert_plus;
 
 	int status;
@@ -170,6 +191,13 @@
 	struct mutex lock;
 
 	struct audpp_event_callback ecb;
+
+	struct audpp_cmd_cfg_object_params_srstm_g g;
+	struct audpp_cmd_cfg_object_params_srstm_w w;
+	struct audpp_cmd_cfg_object_params_srstm_c c;
+	struct audpp_cmd_cfg_object_params_srstm_h h;
+	struct audpp_cmd_cfg_object_params_srstm_p p;
+	struct audpp_cmd_cfg_object_params_srstm_l l;
 } the_audio_copp;
 
 static void audio_prevent_sleep(struct audio *audio)
@@ -190,7 +218,7 @@
 static int audio_dsp_send_buffer(struct audio *audio, unsigned id, unsigned len);
 
 static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
-
+static int audio_enable_srs_trumedia(struct audio_copp *audio_copp, int enable);
 /* must be called with audio->lock held */
 static int audio_enable(struct audio *audio)
 {
@@ -247,6 +275,7 @@
 
 		audpp_disable(-1, audio);
 
+		audio->stopped = 1;
 		wake_up(&audio->wait);
 		audmgr_disable(&audio->audmgr);
 		audio->out_needed = 0;
@@ -278,6 +307,7 @@
 	audpp_dsp_set_qconcert_plus(COMMON_OBJ_ID,
 				audio_copp->qconcert_plus_enable,
 				&audio_copp->qconcert_plus);
+	audio_enable_srs_trumedia(audio_copp, true);
 }
 EXPORT_SYMBOL(audio_commit_pending_pp_params);
 
@@ -447,6 +477,37 @@
 	return 0;
 }
 
+static int audio_enable_srs_trumedia(struct audio_copp *audio_copp, int enable)
+{
+
+	if (!audio_copp->srs_needs_commit)
+		return 0;
+
+	audio_copp->srs_enable = enable;
+
+	MM_DBG("Enable SRS flags 0x%x enable %d\n",
+		audio_copp->srs_feature_mask, enable);
+	if (is_audpp_enable()) {
+		MM_DBG("Updating audpp for srs\n");
+		if (audio_copp->srs_feature_mask & SRS_MASK_W)
+			audpp_dsp_set_rx_srs_trumedia_w(&audio_copp->w);
+		if (audio_copp->srs_feature_mask & SRS_MASK_C)
+			audpp_dsp_set_rx_srs_trumedia_c(&audio_copp->c);
+		if (audio_copp->srs_feature_mask & SRS_MASK_HP)
+			audpp_dsp_set_rx_srs_trumedia_h(&audio_copp->h);
+		if (audio_copp->srs_feature_mask & SRS_MASK_P)
+			audpp_dsp_set_rx_srs_trumedia_p(&audio_copp->p);
+		if (audio_copp->srs_feature_mask & SRS_MASK_HL)
+			audpp_dsp_set_rx_srs_trumedia_l(&audio_copp->l);
+		if (audio_copp->srs_feature_mask & SRS_MASK_G)
+			audpp_dsp_set_rx_srs_trumedia_g(&audio_copp->g);
+
+		audio_copp->srs_needs_commit = 0;
+		audio_copp->srs_feature_mask = 0;
+	}
+	return 0;
+}
+
 static int audio_enable_vol_pan(struct audio_copp *audio_copp)
 {
 	if (is_audpp_enable())
@@ -519,7 +580,6 @@
 		break;
 	case AUDIO_STOP:
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		break;
 	case AUDIO_FLUSH:
 		if (audio->stopped) {
@@ -785,6 +845,8 @@
 	int rc = 0, enable;
 	uint16_t enable_mask;
 	int prev_state;
+	uint32_t to_set, size = 0;
+	void *tmpbuf, *srs_params = NULL;
 
 	mutex_lock(&audio_copp->lock);
 	switch (cmd) {
@@ -804,6 +866,8 @@
 		audio_enable_rx_iir(audio_copp, enable);
 		enable = (enable_mask & QCONCERT_PLUS_ENABLE) ? 1 : 0;
 		audio_enable_qconcert_plus(audio_copp, enable);
+		enable = (enable_mask & SRS_ENABLE) ? 1 : 0;
+		audio_enable_srs_trumedia(audio_copp, enable);
 		break;
 
 	case AUDIO_SET_MBADRC: {
@@ -916,6 +980,75 @@
 		audio_copp->qconcert_plus_needs_commit = 1;
 		break;
 
+	case AUDIO_SET_SRS_TRUMEDIA_PARAM: {
+		prev_state = audio_copp->srs_enable;
+		audio_copp->srs_enable = 0;
+
+		if (copy_from_user(&to_set, (void *)arg, sizeof(uint32_t))) {
+			rc = -EFAULT;
+			break;
+		}
+		switch (to_set) {
+		case SRS_ID_GLOBAL:
+			srs_params = (void *)audio_copp->g.v;
+			size = sizeof(audio_copp->g.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_G;
+			break;
+		case SRS_ID_WOWHD:
+			srs_params = (void *)audio_copp->w.v;
+			size = sizeof(audio_copp->w.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_W;
+			break;
+		case SRS_ID_CSHP:
+			srs_params = (void *)audio_copp->c.v;
+			size = sizeof(audio_copp->c.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_C;
+			break;
+		case SRS_ID_HPF:
+			srs_params = (void *)audio_copp->h.v;
+			size = sizeof(audio_copp->h.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_HP;
+			break;
+		case SRS_ID_PEQ:
+			srs_params = (void *)audio_copp->p.v;
+			size = sizeof(audio_copp->p.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_P;
+			break;
+		case SRS_ID_HL:
+			srs_params = (void *)audio_copp->l.v;
+			size = sizeof(audio_copp->l.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_HL;
+			break;
+		default:
+			MM_ERR("SRS TruMedia error: invalid ioctl\n");
+			rc = -EINVAL;
+		}
+
+		if (rc >= 0) {
+			tmpbuf = kzalloc(sizeof(uint32_t) + size , GFP_KERNEL);
+			if (!tmpbuf) {
+				MM_ERR("SRS TruMedia error: no kernel mem\n");
+				rc = -ENOMEM;
+			} else {
+				if (copy_from_user(tmpbuf, (void *)arg,
+						sizeof(uint32_t) + size))
+					rc = -EFAULT;
+				memcpy(srs_params,
+					&(((uint32_t *)tmpbuf)[1]), size);
+				kfree(tmpbuf);
+			}
+		}
+
+		MM_DBG("Ioctl SRS flags=0x%x\n", audio_copp->srs_feature_mask);
+		if (rc < 0)
+			MM_ERR("SRS TruMedia error setting params failed.\n");
+		else{
+			audio_copp->srs_needs_commit = 1;
+			audio_copp->srs_enable = prev_state;
+		}
+		break;
+	}
+
 	default:
 		rc = -EINVAL;
 	}
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 02103fc..6468e93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -1,7 +1,7 @@
 
 /* audio_pcm.c - pcm audio decoder driver
  *
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 decoder driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -336,6 +336,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
@@ -639,12 +640,16 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -1041,7 +1046,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 81813a0..16c70ce 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -218,6 +218,7 @@
 
 		audpcm_in_dsp_enable(audio, 0);
 
+		audio->stopped = 1;
 		wake_up(&audio->wait);
 
 		msm_adsp_disable(audio->audrec);
@@ -613,7 +614,6 @@
 	}
 	case AUDIO_STOP:
 		rc = audpcm_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	case AUDIO_FLUSH:
 		if (audio->stopped) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index b12e713..2be5144 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -2,7 +2,7 @@
  *
  * qcelp 13k audio decoder device
  *
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on audio_mp3.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -288,6 +288,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -612,23 +613,30 @@
 
 static void audqcelp_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audqcelp_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audqcelp_ioport_reset(struct audio *audio)
@@ -859,7 +867,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audqcelp_disable(audio);
-		audio->stopped = 1;
 		audqcelp_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index a339825..a79f721 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -2,7 +2,7 @@
  *
  * qcelp audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -279,9 +279,10 @@
 
 		audqcelp_in_dsp_enable(audio, 0);
 
-		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -657,29 +658,32 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audqcelp_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audqcelp_out_flush(audio);
+	audqcelp_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audqcelp_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audqcelp_in_flush(struct audio_qcelp_in *audio)
 {
 	int i;
+	unsigned long flags;
 
+	audio->eos_ack = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->dsp_cnt = 0;
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
-	audio->eos_ack = 0;
 	for (i = FRAME_NUM-1; i >= 0; i--) {
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -689,15 +693,18 @@
 static void audqcelp_out_flush(struct audio_qcelp_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -737,7 +744,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audqcelp_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index b7e8e1c..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
  *
@@ -266,7 +266,9 @@
 		audio->in[index].used = 0;
 
 	audio->read_next = 0;
+	mutex_lock(&audio->dsp_lock);
 	audio->fill_next = 0;
+	mutex_unlock(&audio->dsp_lock);
 }
 
 static void audvoicememo_ioport_reset(struct audio_voicememo *audio)
@@ -387,6 +389,7 @@
 		rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
 		wait_event_timeout(audio->wait, audio->stopped == 0,
 				1 * HZ);
+		audio->stopped = 1;
 		wake_up(&audio->read_wait);
 		audmgr_disable(&audio->audmgr);
 		audio->enabled = 0;
@@ -536,12 +539,14 @@
 					callback time\n");
 		else if (rec_status == RPC_VOC_REC_STAT_AUTO_STOP) {
 			MM_DBG(" Voice Record AUTO STOP\n");
+			mutex_lock(&audio->lock);
+			audio->stopped = 1;
 			wake_up(&audio->read_wait);
 			audmgr_disable(&audio->audmgr);
-			audio->stopped = 1;
 			audvoicememo_ioport_reset(audio);
 			audio->stopped = 0;
 			audio->enabled = 0;
+			mutex_unlock(&audio->lock);
 		}
 			break;
 		}
@@ -648,7 +653,6 @@
 	case AUDIO_STOP: {
 			MM_DBG("AUDIO_STOP\n");
 			rc = audvoicememo_disable(audio);
-			audio->stopped = 1;
 			audvoicememo_ioport_reset(audio);
 			audio->stopped = 0;
 			MM_DBG("AUDIO_STOP rc %d\n", rc);
@@ -832,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/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index cf2ade4..674ee4f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -1,6 +1,6 @@
 /* audio_wma.c - wma audio decoder driver
  *
- * Copyright (c) 2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -306,6 +306,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -659,11 +660,15 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -671,11 +676,15 @@
 {
 	uint8_t index;
 
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -905,7 +914,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index d9b384a..c2a0b93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.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.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -301,6 +301,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -648,23 +649,30 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -894,7 +902,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.h b/arch/arm/mach-msm/qdsp5/audmgr.h
index 225beef..34c8488 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/qdsp5/audmgr.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -253,6 +253,20 @@
 			audpp_cmd_cfg_object_params_eqalizer *eq);
 int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
 				audpp_cmd_cfg_object_params_pcm *iir);
+
+int audpp_dsp_set_rx_srs_trumedia_g
+	(struct audpp_cmd_cfg_object_params_srstm_g *srstm);
+int audpp_dsp_set_rx_srs_trumedia_w
+	(struct audpp_cmd_cfg_object_params_srstm_w *srstm);
+int audpp_dsp_set_rx_srs_trumedia_c
+	(struct audpp_cmd_cfg_object_params_srstm_c *srstm);
+int audpp_dsp_set_rx_srs_trumedia_h
+	(struct audpp_cmd_cfg_object_params_srstm_h *srstm);
+int audpp_dsp_set_rx_srs_trumedia_p
+	(struct audpp_cmd_cfg_object_params_srstm_p *srstm);
+int audpp_dsp_set_rx_srs_trumedia_l
+	(struct audpp_cmd_cfg_object_params_srstm_l *srstm);
+
 int audpp_dsp_set_vol_pan(unsigned id,
 				audpp_cmd_cfg_object_params_volume *vol_pan);
 int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index 3e834d8..1616ad0 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -4,7 +4,7 @@
  * common code to deal with the AUDPP dsp task (audio postproc)
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -71,6 +71,14 @@
 #define AUDPP_CLNT_MAX_COUNT 6
 #define AUDPP_AVSYNC_INFO_SIZE 7
 
+#define AUDPP_SRS_PARAMS 2
+#define AUDPP_SRS_PARAMS_G 0
+#define AUDPP_SRS_PARAMS_W 1
+#define AUDPP_SRS_PARAMS_C 2
+#define AUDPP_SRS_PARAMS_H 3
+#define AUDPP_SRS_PARAMS_P 4
+#define AUDPP_SRS_PARAMS_L 5
+
 #define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
 #define AUDPP_CMD_EQ_FLAG_DIS	0x0000
 #define AUDPP_CMD_EQ_FLAG_ENA	-1
@@ -124,6 +132,8 @@
 	uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
 	struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
 
+	spinlock_t avsync_lock;
+
 	wait_queue_head_t event_wait;
 };
 
@@ -237,13 +247,24 @@
 	}
 }
 
+static void audpp_fake_event(struct audpp_state *audpp, int id,
+			     unsigned event, unsigned arg)
+{
+	uint16_t msg[1];
+	msg[0] = arg;
+	audpp->func[id] (audpp->private[id], event, msg);
+}
+
 static void audpp_dsp_event(void *data, unsigned id, size_t len,
 			    void (*getevent) (void *ptr, size_t len))
 {
 	struct audpp_state *audpp = data;
+	unsigned long flags;
 	uint16_t msg[8];
+	int cid = 0;
 
 	if (id == AUDPP_MSG_AVSYNC_MSG) {
+		spin_lock_irqsave(&audpp->avsync_lock, flags);
 		getevent(audpp->avsync, sizeof(audpp->avsync));
 
 		/* mask off any channels we're not watching to avoid
@@ -252,6 +273,7 @@
 		 * we next read...
 		 */
 		audpp->avsync[0] &= audpp->avsync_mask;
+		spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 		return;
 	}
 
@@ -278,13 +300,28 @@
 	case AUDPP_MSG_CFG_MSG:
 		if (msg[0] == AUDPP_MSG_ENA_ENA) {
 			MM_INFO("ENABLE\n");
-			audpp->enabled = 1;
-			audpp_broadcast(audpp, id, msg);
+			if (!audpp->enabled) {
+				audpp->enabled = 1;
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_ENA);
+			}
+
 		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
-			MM_INFO("DISABLE\n");
-			audpp->enabled = 0;
-			wake_up(&audpp->event_wait);
-			audpp_broadcast(audpp, id, msg);
+			if (audpp->open_count == 0) {
+				MM_INFO("DISABLE\n");
+				audpp->enabled = 0;
+				wake_up(&audpp->event_wait);
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_DIS);
+				audpp->func[cid] = NULL;
+				audpp->private[cid] = NULL;
+			}
 		} else {
 			MM_ERR("invalid config msg %d\n", msg[0]);
 		}
@@ -307,17 +344,10 @@
 	.event = audpp_dsp_event,
 };
 
-static void audpp_fake_event(struct audpp_state *audpp, int id,
-			     unsigned event, unsigned arg)
-{
-	uint16_t msg[1];
-	msg[0] = arg;
-	audpp->func[id] (audpp->private[id], event, msg);
-}
-
 int audpp_enable(int id, audpp_event_func func, void *private)
 {
 	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t msg[8];
 	int res = 0;
 
 	if (id < -1 || id > 4)
@@ -350,12 +380,15 @@
 		msm_adsp_enable(audpp->mod);
 		audpp_dsp_config(1);
 	} else {
-		unsigned long flags;
-		local_irq_save(flags);
-		if (audpp->enabled)
-			audpp_fake_event(audpp, id,
-					 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
-		local_irq_restore(flags);
+		if (audpp->enabled) {
+			msg[0] = AUDPP_MSG_ENA_ENA;
+			msg[1] = id;
+			res = msm_adsp_generate_event(audpp, audpp->mod,
+					 AUDPP_MSG_CFG_MSG, sizeof(msg),
+					 sizeof(uint16_t), (void *)msg);
+			if (res < 0)
+				goto out;
+		}
 	}
 
 	res = 0;
@@ -368,7 +401,7 @@
 void audpp_disable(int id, void *private)
 {
 	struct audpp_state *audpp = &the_audpp_state;
-	unsigned long flags;
+	uint16_t msg[8];
 	int rc;
 
 	if (id < -1 || id > 4)
@@ -384,11 +417,13 @@
 	if (audpp->private[id] != private)
 		goto out;
 
-	local_irq_save(flags);
-	audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
-	audpp->func[id] = NULL;
-	audpp->private[id] = NULL;
-	local_irq_restore(flags);
+	msg[0] = AUDPP_MSG_ENA_DIS;
+	msg[1] = id;
+	rc = msm_adsp_generate_event(audpp, audpp->mod,
+				 AUDPP_MSG_CFG_MSG, sizeof(msg),
+				 sizeof(uint16_t), (void *)msg);
+	if (rc < 0)
+		goto out;
 
 	if (--audpp->open_count == 0) {
 		MM_DBG("disable\n");
@@ -420,13 +455,13 @@
 	if (BAD_ID(id))
 		return;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
 	if (rate)
 		the_audpp_state.avsync_mask |= (1 << id);
 	else
 		the_audpp_state.avsync_mask &= (~(1 << id));
 	the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
 
 	cmd.cmd_id = AUDPP_CMD_AVSYNC;
 	cmd.object_number = id;
@@ -438,7 +473,8 @@
 
 unsigned audpp_avsync_sample_count(int id)
 {
-	uint16_t *avsync = the_audpp_state.avsync;
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
 	unsigned val;
 	unsigned long flags;
 	unsigned mask;
@@ -448,12 +484,12 @@
 
 	mask = 1 << id;
 	id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
-	local_irq_save(flags);
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
 	if (avsync[0] & mask)
 		val = (avsync[id] << 16) | avsync[id + 1];
 	else
 		val = 0;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 
 	return val;
 }
@@ -461,7 +497,8 @@
 
 unsigned audpp_avsync_byte_count(int id)
 {
-	uint16_t *avsync = the_audpp_state.avsync;
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
 	unsigned val;
 	unsigned long flags;
 	unsigned mask;
@@ -471,12 +508,12 @@
 
 	mask = 1 << id;
 	id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
-	local_irq_save(flags);
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
 	if (avsync[0] & mask)
 		val = (avsync[id] << 16) | avsync[id + 1];
 	else
 		val = 0;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 
 	return val;
 }
@@ -575,6 +612,108 @@
 }
 EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
 
+int audpp_dsp_set_rx_srs_trumedia_g(
+	struct audpp_cmd_cfg_object_params_srstm_g *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_g cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_G;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_g);
+
+int audpp_dsp_set_rx_srs_trumedia_w(
+	struct audpp_cmd_cfg_object_params_srstm_w *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_w cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_W;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_w);
+
+int audpp_dsp_set_rx_srs_trumedia_c(
+	struct audpp_cmd_cfg_object_params_srstm_c *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_c cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_C;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_c);
+
+int audpp_dsp_set_rx_srs_trumedia_h(
+	struct audpp_cmd_cfg_object_params_srstm_h *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_h cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_H;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_h);
+
+int audpp_dsp_set_rx_srs_trumedia_p(
+	struct audpp_cmd_cfg_object_params_srstm_p *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_p cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_P;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_p);
+
+int audpp_dsp_set_rx_srs_trumedia_l(
+	struct audpp_cmd_cfg_object_params_srstm_l *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_l cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_L;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_l);
+
 /* Implementation Of COPP + POPP */
 int audpp_dsp_set_eq(unsigned id, unsigned enable,
 		     audpp_cmd_cfg_object_params_eqalizer *eq)
@@ -826,6 +965,8 @@
 
 	init_waitqueue_head(&audpp->event_wait);
 
+	spin_lock_init(&audpp->avsync_lock);
+
 	for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
 		audpp->dec_info_table[idx].codec = -1;
 		audpp->dec_info_table[idx].pid = 0;
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/qdsp5v2/audio_lpa.c b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
index d43c961..c8f0590 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
@@ -559,6 +559,8 @@
 
 			if ((signed)(temp >= 0) &&
 			((signed)(next_buf->buf.data_len - temp) >= 0)) {
+				MM_DBG("audlpa_async_send_buffer - sending the"
+					"rest of the buffer bassedon AV sync");
 				cmd.buf_ptr	= (unsigned) (next_buf->paddr +
 						  (next_buf->buf.data_len -
 						   temp));
@@ -570,6 +572,21 @@
 				audplay_send_queue0(audio, &cmd, sizeof(cmd));
 				audio->out_needed = 0;
 				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			} else if ((signed)(temp >= 0) &&
+				((signed)(next_buf->buf.data_len -
+							temp) < 0)) {
+				MM_DBG("audlpa_async_send_buffer - else case:"
+					"sending the rest of the buffer bassedon"
+					"AV sync");
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				audio->bytecount_given = audio->bytecount_head +
+					next_buf->buf.data_len;
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
 			}
 		}
 	}
@@ -606,15 +623,19 @@
 			temp = audio->bytecount_head;
 			used_buf = list_first_entry(&audio->out_queue,
 					struct audlpa_buffer_node, list);
-
-			audio->bytecount_head += used_buf->buf.data_len;
-			temp = audio->bytecount_head;
-			list_del(&used_buf->list);
-			evt_payload.aio_buf = used_buf->buf;
-			audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
-					  evt_payload);
-			kfree(used_buf);
-			audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+			if (audio->device_switch !=
+				DEVICE_SWITCH_STATE_COMPLETE) {
+				audio->bytecount_head +=
+						used_buf->buf.data_len;
+				temp = audio->bytecount_head;
+				list_del(&used_buf->list);
+				evt_payload.aio_buf = used_buf->buf;
+				audlpa_post_event(audio,
+						AUDIO_EVENT_WRITE_DONE,
+						  evt_payload);
+				kfree(used_buf);
+				audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+			}
 		}
 	}
 	if (audio->out_needed) {
@@ -1150,6 +1171,15 @@
 		audio->wflush = 1;
 		audio_ioport_reset(audio);
 		if (audio->running) {
+			if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+				rc = audpp_pause(audio->dec_id, (int) arg);
+				if (rc < 0) {
+					MM_ERR("%s: pause cmd failed rc=%d\n",
+						__func__, rc);
+					rc = -EINTR;
+					break;
+				}
+			}
 			audpp_flush(audio->dec_id);
 			rc = wait_event_interruptible(audio->write_wait,
 				!audio->wflush);
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 6d36495..083a9f1 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -14,7 +14,9 @@
 endif
 obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
 obj-y += audio_acdb.o
+ifndef CONFIG_ARCH_MSM9615
 obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
 obj-y += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
 obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
 obj-y += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+endif
diff --git a/arch/arm/mach-msm/qdsp6v2/amrwb_in.c b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
index 030d08f..5df976d 100644
--- a/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
@@ -193,8 +193,8 @@
 	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
 
 	if (audio == NULL) {
-		pr_err("%s:session id %d: Could not allocate memory for amrwb"
-			"driver\n", __func__, audio->ac->session);
+		pr_err("%s: Could not allocate memory for amrwb driver\n",
+								__func__);
 		return -ENOMEM;
 	}
 	/* Allocate memory for encoder config param */
@@ -235,8 +235,8 @@
 				(void *)audio);
 
 	if (!audio->ac) {
-		pr_err("%s:session id %d: Could not allocate memory for audio"
-			"client\n", __func__, audio->ac->session);
+		pr_err("%s:audio[%p]: Could not allocate memory for audio"
+			"client\n", __func__, audio);
 		kfree(audio->enc_cfg);
 		kfree(audio);
 		return -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 541f62f..b5f071f 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -255,9 +255,9 @@
 	if (!dest || !svc_name || !svc_fn)
 		return NULL;
 
-	if (!strcmp(dest, "ADSP"))
+	if (!strncmp(dest, "ADSP", 4))
 		dest_id = APR_DEST_QDSP6;
-	else if (!strcmp(dest, "MODEM")) {
+	else if (!strncmp(dest, "MODEM", 5)) {
 		dest_id = APR_DEST_MODEM;
 	} else {
 		pr_err("APR: wrong destination\n");
@@ -286,23 +286,23 @@
 		pr_info("%s: modem Up\n", __func__);
 	}
 
-	if (!strcmp(svc_name, "AFE")) {
+	if (!strncmp(svc_name, "AFE", 3)) {
 		client_id = APR_CLIENT_AUDIO;
 		svc_idx = 0;
 		svc_id = APR_SVC_AFE;
-	} else if (!strcmp(svc_name, "ASM")) {
+	} else if (!strncmp(svc_name, "ASM", 3)) {
 		client_id = APR_CLIENT_AUDIO;
 		svc_idx = 1;
 		svc_id = APR_SVC_ASM;
-	} else if (!strcmp(svc_name, "ADM")) {
+	} else if (!strncmp(svc_name, "ADM", 3)) {
 		client_id = APR_CLIENT_AUDIO;
 		svc_idx = 2;
 		svc_id = APR_SVC_ADM;
-	} else if (!strcmp(svc_name, "CORE")) {
+	} else if (!strncmp(svc_name, "CORE", 4)) {
 		client_id = APR_CLIENT_AUDIO;
 		svc_idx = 3;
 		svc_id = APR_SVC_ADSP_CORE;
-	} else if (!strcmp(svc_name, "TEST")) {
+	} else if (!strncmp(svc_name, "TEST", 4)) {
 		if (dest_id == APR_DEST_QDSP6) {
 			client_id = APR_CLIENT_AUDIO;
 			svc_idx = 4;
@@ -311,19 +311,19 @@
 			svc_idx = 7;
 		}
 		svc_id = APR_SVC_TEST_CLIENT;
-	} else if (!strcmp(svc_name, "VSM")) {
+	} else if (!strncmp(svc_name, "VSM", 3)) {
 		client_id = APR_CLIENT_VOICE;
 		svc_idx = 0;
 		svc_id = APR_SVC_VSM;
-	} else if (!strcmp(svc_name, "VPM")) {
+	} else if (!strncmp(svc_name, "VPM", 3)) {
 		client_id = APR_CLIENT_VOICE;
 		svc_idx = 1;
 		svc_id = APR_SVC_VPM;
-	} else if (!strcmp(svc_name, "MVS")) {
+	} else if (!strncmp(svc_name, "MVS", 3)) {
 		client_id = APR_CLIENT_VOICE;
 		svc_idx = 2;
 		svc_id = APR_SVC_MVS;
-	} else if (!strcmp(svc_name, "MVM")) {
+	} else if (!strncmp(svc_name, "MVM", 3)) {
 		if (dest_id == APR_DEST_MODEM) {
 			client_id = APR_CLIENT_VOICE;
 			svc_idx = 3;
@@ -333,7 +333,7 @@
 			svc_idx = 5;
 			svc_id = APR_SVC_ADSP_MVM;
 		}
-	} else if (!strcmp(svc_name, "CVS")) {
+	} else if (!strncmp(svc_name, "CVS", 3)) {
 		if (dest_id == APR_DEST_MODEM) {
 			client_id = APR_CLIENT_VOICE;
 			svc_idx = 4;
@@ -343,7 +343,7 @@
 			svc_idx = 6;
 			svc_id = APR_SVC_ADSP_CVS;
 		}
-	} else if (!strcmp(svc_name, "CVP")) {
+	} else if (!strncmp(svc_name, "CVP", 3)) {
 		if (dest_id == APR_DEST_MODEM) {
 			client_id = APR_CLIENT_VOICE;
 			svc_idx = 5;
@@ -353,7 +353,7 @@
 			svc_idx = 7;
 			svc_id = APR_SVC_ADSP_CVP;
 		}
-	} else if (!strcmp(svc_name, "SRD")) {
+	} else if (!strncmp(svc_name, "SRD", 3)) {
 		client_id = APR_CLIENT_VOICE;
 		svc_idx = 6;
 		svc_id = APR_SVC_SRD;
@@ -679,16 +679,13 @@
 
 static int __init apr_late_init(void)
 {
-	void *ret;
+	int ret = 0;
 	init_waitqueue_head(&dsp_wait);
 	init_waitqueue_head(&modem_wait);
 	atomic_set(&dsp_state, 1);
 	atomic_set(&modem_state, 1);
-	ret = subsys_notif_register_notifier("modem", &mnb);
-	pr_debug("subsys_register_notifier: ret1 = %p\n", ret);
-	ret = subsys_notif_register_notifier("lpass", &lnb);
-	pr_debug("subsys_register_notifier: ret2 = %p\n", ret);
-
-	return 0;
+	subsys_notif_register_notifier("modem", &mnb);
+	subsys_notif_register_notifier("lpass", &lnb);
+	return ret;
 }
 late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index ce5d084..e7a81d3 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,79 @@
 	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;
+	void                    *kvptr;
+	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__);
+		result = PTR_ERR(acdb_data.ion_client);
+		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__);
+		result = PTR_ERR(acdb_data.ion_handle);
+		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;
+	}
+
+	kvptr = ion_map_kernel(acdb_data.ion_client,
+		acdb_data.ion_handle, 0);
+	if (IS_ERR_OR_NULL(kvptr)) {
+		pr_err("%s: Could not get kernel virt addr!!!\n", __func__);
+		result = PTR_ERR(kvptr);
+		goto err_ion_handle;
+	}
+	kvaddr = (unsigned long)kvptr;
+	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 +693,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 +701,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 +869,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 +879,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 +903,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 3225d61..41a7387 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -2,7 +2,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 software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -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>
@@ -45,7 +45,7 @@
 #include <mach/debug_mm.h>
 #include <linux/fs.h>
 
-#define MAX_BUF 3
+#define MAX_BUF 4
 #define BUFSZ (524288)
 
 #define AUDDEC_DEC_PCM 0
@@ -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 ffc27ad..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_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 75af881..ee32b80 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -69,7 +69,7 @@
 			/* Configure PCM output block */
 			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
 				0, /*native sampling rate*/
-				(audio->pcm_cfg.channel_count <= 2) ? 0 : 2);
+				0 /*native channel count*/);
 			if (rc < 0) {
 				pr_err("pcm output block config failed\n");
 				break;
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 a4a6b72..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/qdsp6v2/rtac.c b/arch/arm/mach-msm/qdsp6v2/rtac.c
index 9823209..a3a14c4 100644
--- a/arch/arm/mach-msm/qdsp6v2/rtac.c
+++ b/arch/arm/mach-msm/qdsp6v2/rtac.c
@@ -442,8 +442,7 @@
 	}
 
 
-	if ((payload_size < 0) ||
-		(payload_size > MAX_PAYLOAD_SIZE)) {
+	if (payload_size > MAX_PAYLOAD_SIZE) {
 
 			pr_err("%s: Invalid payload size = %d\n",
 				__func__, payload_size);
@@ -614,8 +613,7 @@
 		goto done;
 	}
 
-	if ((payload_size < 0) ||
-		(payload_size > MAX_PAYLOAD_SIZE)) {
+	if (payload_size > MAX_PAYLOAD_SIZE) {
 
 			pr_err("%s: Invalid payload size = %d\n",
 				__func__, payload_size);
@@ -627,15 +625,17 @@
 			__func__);
 		goto done;
 	}
-	if (session_id >= AFE_MAX_PORTS) {
+	if (session_id > (SESSION_MAX + 1)) {
 		pr_err("%s: Invalid Session = %d\n", __func__, session_id);
 		goto done;
 	}
 
 	mutex_lock(&rtac_asm_apr_mutex);
-	if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
-		pr_err("%s: APR not initialized\n", __func__);
-		goto err;
+	if (session_id < SESSION_MAX+1) {
+		if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
+			pr_err("%s: APR not initialized\n", __func__);
+			goto err;
+		}
 	}
 
 	/* Set globals for copy of returned payload */
@@ -664,7 +664,8 @@
 	asm_params.opcode = opcode;
 
 	memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
-	atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+	if (session_id < SESSION_MAX+1)
+		atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
 
 	pr_debug("%s: Sending RTAC command size = %d, session_id=%d\n",
 		__func__, asm_params.pkt_size, session_id);
@@ -723,7 +724,7 @@
 bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
 {
 	if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
-			(mode < 0) || (mode >= RTAC_VOICE_MODES))
+			(mode >= RTAC_VOICE_MODES))
 		return false;
 
 	pr_debug("%s\n", __func__);
@@ -782,10 +783,8 @@
 		goto done;
 	}
 
-	if ((payload_size < 0) ||
-		(payload_size > MAX_PAYLOAD_SIZE)) {
-
-			pr_err("%s: Invalid payload size = %d\n",
+	if (payload_size > MAX_PAYLOAD_SIZE) {
+		pr_err("%s: Invalid payload size = %d\n",
 				__func__, payload_size);
 		goto done;
 	}
diff --git a/arch/arm/mach-msm/qdss-etb.c b/arch/arm/mach-msm/qdss-etb.c
index 39b7670..96eba26 100644
--- a/arch/arm/mach-msm/qdss-etb.c
+++ b/arch/arm/mach-msm/qdss-etb.c
@@ -25,7 +25,7 @@
 #include <linux/delay.h>
 #include <linux/mutex.h>
 
-#include "qdss.h"
+#include "qdss-priv.h"
 
 #define etb_writel(etb, val, off)	__raw_writel((val), etb.base + off)
 #define etb_readl(etb, off)		__raw_readl(etb.base + off)
@@ -69,9 +69,11 @@
 	void __iomem	*base;
 	bool		enabled;
 	bool		reading;
-	struct mutex	lock;
+	struct mutex	mutex;
 	atomic_t	in_use;
 	struct device	*dev;
+	struct kobject	*kobj;
+	uint32_t	trigger_cntr;
 };
 
 static struct etb_ctx etb;
@@ -89,6 +91,7 @@
 	etb_writel(etb, 0x0, ETB_RAM_WRITE_POINTER);
 	etb_writel(etb, 0x0, ETB_RAM_READ_POINTER);
 
+	etb_writel(etb, etb.trigger_cntr, ETB_TRG);
 	etb_writel(etb, BIT(13) | BIT(0), ETB_FFCR);
 	etb_writel(etb, BIT(0), ETB_CTL_REG);
 
@@ -97,37 +100,48 @@
 
 void etb_enable(void)
 {
-	mutex_lock(&etb.lock);
+	mutex_lock(&etb.mutex);
 	__etb_enable();
 	etb.enabled = true;
-	dev_info(etb.dev, "etb enabled\n");
-	mutex_unlock(&etb.lock);
+	dev_info(etb.dev, "ETB enabled\n");
+	mutex_unlock(&etb.mutex);
 }
 
 static void __etb_disable(void)
 {
 	int count;
+	uint32_t ffcr;
 
 	ETB_UNLOCK();
 
-	etb_writel(etb, BIT(12) | BIT(13), ETB_FFCR);
+	ffcr = etb_readl(etb, ETB_FFCR);
+	ffcr |= (BIT(12) | BIT(6));
+	etb_writel(etb, ffcr, ETB_FFCR);
+
+	for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFCR), 6) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while flushing ETB, ETB_FFCR: %#x\n",
+	     etb_readl(etb, ETB_FFCR));
+
 	etb_writel(etb, 0x0, ETB_CTL_REG);
 
 	for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFSR), 1) != 1
 				&& count > 0; count--)
 		udelay(1);
-	WARN(count == 0, "timeout while disabling etb\n");
+	WARN(count == 0, "timeout while disabling ETB, ETB_FFSR: %#x\n",
+	     etb_readl(etb, ETB_FFSR));
 
 	ETB_LOCK();
 }
 
 void etb_disable(void)
 {
-	mutex_lock(&etb.lock);
+	mutex_lock(&etb.mutex);
 	__etb_disable();
 	etb.enabled = false;
-	dev_info(etb.dev, "etb disabled\n");
-	mutex_unlock(&etb.lock);
+	dev_info(etb.dev, "ETB disabled\n");
+	mutex_unlock(&etb.mutex);
 }
 
 static void __etb_dump(void)
@@ -186,15 +200,15 @@
 
 void etb_dump(void)
 {
-	mutex_lock(&etb.lock);
+	mutex_lock(&etb.mutex);
 	if (etb.enabled) {
 		__etb_disable();
 		__etb_dump();
 		__etb_enable();
 
-		dev_info(etb.dev, "etb dumped\n");
+		dev_info(etb.dev, "ETB dumped\n");
 	}
-	mutex_unlock(&etb.lock);
+	mutex_unlock(&etb.mutex);
 }
 
 static int etb_open(struct inode *inode, struct file *file)
@@ -254,6 +268,62 @@
 	.fops =		&etb_fops,
 };
 
+#define ETB_ATTR(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+
+static ssize_t trigger_cntr_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	etb.trigger_cntr = val;
+	return n;
+}
+static ssize_t trigger_cntr_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = etb.trigger_cntr;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETB_ATTR(trigger_cntr);
+
+static int __init etb_sysfs_init(void)
+{
+	int ret;
+
+	etb.kobj = kobject_create_and_add("etb", qdss_get_modulekobj());
+	if (!etb.kobj) {
+		dev_err(etb.dev, "failed to create ETB sysfs kobject\n");
+		ret = -ENOMEM;
+		goto err_create;
+	}
+
+	ret = sysfs_create_file(etb.kobj, &trigger_cntr_attr.attr);
+	if (ret) {
+		dev_err(etb.dev, "failed to create ETB sysfs trigger_cntr"
+		" attribute\n");
+		goto err_file;
+	}
+
+	return 0;
+err_file:
+	kobject_put(etb.kobj);
+err_create:
+	return ret;
+}
+
+static void __exit etb_sysfs_exit(void)
+{
+	sysfs_remove_file(etb.kobj, &trigger_cntr_attr.attr);
+	kobject_put(etb.kobj);
+}
+
 static int __devinit etb_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -273,6 +343,8 @@
 
 	etb.dev = &pdev->dev;
 
+	mutex_init(&etb.mutex);
+
 	ret = misc_register(&etb_misc);
 	if (ret)
 		goto err_misc;
@@ -283,26 +355,30 @@
 		goto err_alloc;
 	}
 
-	mutex_init(&etb.lock);
+	etb_sysfs_init();
 
+	dev_info(etb.dev, "ETB initialized\n");
 	return 0;
 
 err_alloc:
 	misc_deregister(&etb_misc);
 err_misc:
+	mutex_destroy(&etb.mutex);
 	iounmap(etb.base);
 err_ioremap:
 err_res:
+	dev_err(etb.dev, "ETB init failed\n");
 	return ret;
 }
 
-static int etb_remove(struct platform_device *pdev)
+static int __devexit etb_remove(struct platform_device *pdev)
 {
 	if (etb.enabled)
 		etb_disable();
-	mutex_destroy(&etb.lock);
+	etb_sysfs_exit();
 	kfree(etb.buf);
 	misc_deregister(&etb_misc);
+	mutex_destroy(&etb.mutex);
 	iounmap(etb.base);
 
 	return 0;
@@ -310,18 +386,23 @@
 
 static struct platform_driver etb_driver = {
 	.probe          = etb_probe,
-	.remove         = etb_remove,
+	.remove         = __devexit_p(etb_remove),
 	.driver         = {
 		.name   = "msm_etb",
 	},
 };
 
-int __init etb_init(void)
+static int __init etb_init(void)
 {
 	return platform_driver_register(&etb_driver);
 }
+module_init(etb_init);
 
-void etb_exit(void)
+static void __exit etb_exit(void)
 {
 	platform_driver_unregister(&etb_driver);
 }
+module_exit(etb_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
diff --git a/arch/arm/mach-msm/qdss-etm.c b/arch/arm/mach-msm/qdss-etm.c
new file mode 100644
index 0000000..251db45
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-etm.c
@@ -0,0 +1,1329 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/wakelock.h>
+#include <linux/pm_qos_params.h>
+#include <linux/sysfs.h>
+#include <linux/stat.h>
+#include <asm/sections.h>
+#include <mach/socinfo.h>
+
+#include "qdss-priv.h"
+
+#define etm_writel(etm, cpu, val, off)	\
+			__raw_writel((val), etm.base + (SZ_4K * cpu) + off)
+#define etm_readl(etm, cpu, off)	\
+			__raw_readl(etm.base + (SZ_4K * cpu) + off)
+
+/*
+ * Device registers:
+ * 0x000 - 0x2FC: Trace		registers
+ * 0x300 - 0x314: Management	registers
+ * 0x318 - 0xEFC: Trace		registers
+ *
+ * Coresight registers
+ * 0xF00 - 0xF9C: Management	registers
+ * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
+ *		  Trace		registers in PFTv1.1
+ * 0xFA8 - 0xFFC: Management	registers
+ */
+
+/* Trace registers (0x000-0x2FC) */
+#define ETMCR			(0x000)
+#define ETMCCR			(0x004)
+#define ETMTRIGGER		(0x008)
+#define ETMSR			(0x010)
+#define ETMSCR			(0x014)
+#define ETMTSSCR		(0x018)
+#define ETMTEEVR		(0x020)
+#define ETMTECR1		(0x024)
+#define ETMFFLR			(0x02C)
+#define ETMACVRn(n)		(0x040 + (n * 4))
+#define ETMACTRn(n)		(0x080 + (n * 4))
+#define ETMCNTRLDVRn(n)		(0x140 + (n * 4))
+#define ETMCNTENRn(n)		(0x150 + (n * 4))
+#define ETMCNTRLDEVRn(n)	(0x160 + (n * 4))
+#define ETMCNTVRn(n)		(0x170 + (n * 4))
+#define ETMSQ12EVR		(0x180)
+#define ETMSQ21EVR		(0x184)
+#define ETMSQ23EVR		(0x188)
+#define ETMSQ31EVR		(0x18C)
+#define ETMSQ32EVR		(0x190)
+#define ETMSQ13EVR		(0x194)
+#define ETMSQR			(0x19C)
+#define ETMEXTOUTEVRn(n)	(0x1A0 + (n * 4))
+#define ETMCIDCVRn(n)		(0x1B0 + (n * 4))
+#define ETMCIDCMR		(0x1BC)
+#define ETMIMPSPEC0		(0x1C0)
+#define ETMIMPSPEC1		(0x1C4)
+#define ETMIMPSPEC2		(0x1C8)
+#define ETMIMPSPEC3		(0x1CC)
+#define ETMIMPSPEC4		(0x1D0)
+#define ETMIMPSPEC5		(0x1D4)
+#define ETMIMPSPEC6		(0x1D8)
+#define ETMIMPSPEC7		(0x1DC)
+#define ETMSYNCFR		(0x1E0)
+#define ETMIDR			(0x1E4)
+#define ETMCCER			(0x1E8)
+#define ETMEXTINSELR		(0x1EC)
+#define ETMTESSEICR		(0x1F0)
+#define ETMEIBCR		(0x1F4)
+#define ETMTSEVR		(0x1F8)
+#define ETMAUXCR		(0x1FC)
+#define ETMTRACEIDR		(0x200)
+#define ETMVMIDCVR		(0x240)
+/* Management registers (0x300-0x314) */
+#define ETMOSLAR		(0x300)
+#define ETMOSLSR		(0x304)
+#define ETMOSSRR		(0x308)
+#define ETMPDCR			(0x310)
+#define ETMPDSR			(0x314)
+
+#define ETM_MAX_ADDR_CMP	(16)
+#define ETM_MAX_CNTR		(4)
+#define ETM_MAX_CTXID_CMP	(3)
+
+#define ETM_MODE_EXCLUDE	BIT(0)
+#define ETM_MODE_CYCACC		BIT(1)
+#define ETM_MODE_STALL		BIT(2)
+#define ETM_MODE_TIMESTAMP	BIT(3)
+#define ETM_MODE_CTXID		BIT(4)
+#define ETM_MODE_ALL		(0x1F)
+
+#define ETM_EVENT_MASK		(0x1FFFF)
+#define ETM_SYNC_MASK		(0xFFF)
+#define ETM_ALL_MASK		(0xFFFFFFFF)
+
+#define ETM_SEQ_STATE_MAX_VAL	(0x2)
+
+enum {
+	ETM_ADDR_TYPE_NONE,
+	ETM_ADDR_TYPE_SINGLE,
+	ETM_ADDR_TYPE_RANGE,
+	ETM_ADDR_TYPE_START,
+	ETM_ADDR_TYPE_STOP,
+};
+
+#define ETM_LOCK(cpu)							\
+do {									\
+	mb();								\
+	etm_writel(etm, cpu, 0x0, CS_LAR);				\
+} while (0)
+#define ETM_UNLOCK(cpu)							\
+do {									\
+	etm_writel(etm, cpu, CS_UNLOCK_MAGIC, CS_LAR);			\
+	mb();								\
+} while (0)
+
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "qdss."
+
+#ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
+static int etm_boot_enable = 1;
+#else
+static int etm_boot_enable;
+#endif
+module_param_named(
+	etm_boot_enable, etm_boot_enable, int, S_IRUGO
+);
+
+struct etm_ctx {
+	void __iomem			*base;
+	bool				enabled;
+	struct wake_lock		wake_lock;
+	struct pm_qos_request_list	qos_req;
+	struct qdss_source		*src;
+	struct mutex			mutex;
+	struct device			*dev;
+	struct kobject			*kobj;
+	uint8_t				arch;
+	uint8_t				nr_addr_cmp;
+	uint8_t				nr_cntr;
+	uint8_t				nr_ext_inp;
+	uint8_t				nr_ext_out;
+	uint8_t				nr_ctxid_cmp;
+	uint8_t				reset;
+	uint32_t			mode;
+	uint32_t			ctrl;
+	uint32_t			trigger_event;
+	uint32_t			startstop_ctrl;
+	uint32_t			enable_event;
+	uint32_t			enable_ctrl1;
+	uint32_t			fifofull_level;
+	uint8_t				addr_idx;
+	uint32_t			addr_val[ETM_MAX_ADDR_CMP];
+	uint32_t			addr_acctype[ETM_MAX_ADDR_CMP];
+	uint32_t			addr_type[ETM_MAX_ADDR_CMP];
+	uint8_t				cntr_idx;
+	uint32_t			cntr_rld_val[ETM_MAX_CNTR];
+	uint32_t			cntr_event[ETM_MAX_CNTR];
+	uint32_t			cntr_rld_event[ETM_MAX_CNTR];
+	uint32_t			cntr_val[ETM_MAX_CNTR];
+	uint32_t			seq_12_event;
+	uint32_t			seq_21_event;
+	uint32_t			seq_23_event;
+	uint32_t			seq_31_event;
+	uint32_t			seq_32_event;
+	uint32_t			seq_13_event;
+	uint32_t			seq_curr_state;
+	uint8_t				ctxid_idx;
+	uint32_t			ctxid_val[ETM_MAX_CTXID_CMP];
+	uint32_t			ctxid_mask;
+	uint32_t			sync_freq;
+	uint32_t			timestamp_event;
+};
+
+static struct etm_ctx etm = {
+	.trigger_event		= 0x406F,
+	.enable_event		= 0x6F,
+	.enable_ctrl1		= 0x1,
+	.fifofull_level		= 0x28,
+	.addr_val		= {(uint32_t) _stext, (uint32_t) _etext},
+	.addr_type		= {ETM_ADDR_TYPE_RANGE, ETM_ADDR_TYPE_RANGE},
+	.cntr_event		= {[0 ... (ETM_MAX_CNTR - 1)] = 0x406F},
+	.cntr_rld_event		= {[0 ... (ETM_MAX_CNTR - 1)] = 0x406F},
+	.seq_12_event		= 0x406F,
+	.seq_21_event		= 0x406F,
+	.seq_23_event		= 0x406F,
+	.seq_31_event		= 0x406F,
+	.seq_32_event		= 0x406F,
+	.seq_13_event		= 0x406F,
+	.sync_freq		= 0x80,
+	.timestamp_event	= 0x406F,
+};
+
+
+/* ETM clock is derived from the processor clock and gets enabled on a
+ * logical OR of below items on Krait (pass2 onwards):
+ * 1.CPMR[ETMCLKEN] is 1
+ * 2.ETMCR[PD] is 0
+ * 3.ETMPDCR[PU] is 1
+ * 4.Reset is asserted (core or debug)
+ * 5.APB memory mapped requests (eg. EDAP access)
+ *
+ * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
+ * enables
+ *
+ * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
+ * clock vote in the driver and the save-restore code uses 1. above
+ * for its vote
+ */
+static void etm_set_pwrdwn(int cpu)
+{
+	uint32_t etmcr;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr |= BIT(0);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+}
+
+static void etm_clr_pwrdwn(int cpu)
+{
+	uint32_t etmcr;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr &= ~BIT(0);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+}
+
+static void etm_set_prog(int cpu)
+{
+	uint32_t etmcr;
+	int count;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr |= BIT(10);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+
+	for (count = TIMEOUT_US; BVAL(etm_readl(etm, cpu, ETMSR), 1) != 1
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while setting prog bit, ETMSR: %#x\n",
+	     etm_readl(etm, cpu, ETMSR));
+}
+
+static void etm_clr_prog(int cpu)
+{
+	uint32_t etmcr;
+	int count;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr &= ~BIT(10);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+
+	for (count = TIMEOUT_US; BVAL(etm_readl(etm, cpu, ETMSR), 1) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while clearing prog bit, ETMSR: %#x\n",
+	     etm_readl(etm, cpu, ETMSR));
+}
+
+static void __etm_enable(int cpu)
+{
+	int i;
+
+	ETM_UNLOCK(cpu);
+	/* Vote for ETM power/clock enable */
+	etm_clr_pwrdwn(cpu);
+	etm_set_prog(cpu);
+
+	etm_writel(etm, cpu, etm.ctrl | BIT(10), ETMCR);
+	etm_writel(etm, cpu, etm.trigger_event, ETMTRIGGER);
+	etm_writel(etm, cpu, etm.startstop_ctrl, ETMTSSCR);
+	etm_writel(etm, cpu, etm.enable_event, ETMTEEVR);
+	etm_writel(etm, cpu, etm.enable_ctrl1, ETMTECR1);
+	etm_writel(etm, cpu, etm.fifofull_level, ETMFFLR);
+	for (i = 0; i < etm.nr_addr_cmp; i++) {
+		etm_writel(etm, cpu, etm.addr_val[i], ETMACVRn(i));
+		etm_writel(etm, cpu, etm.addr_acctype[i], ETMACTRn(i));
+	}
+	for (i = 0; i < etm.nr_cntr; i++) {
+		etm_writel(etm, cpu, etm.cntr_rld_val[i], ETMCNTRLDVRn(i));
+		etm_writel(etm, cpu, etm.cntr_event[i], ETMCNTENRn(i));
+		etm_writel(etm, cpu, etm.cntr_rld_event[i], ETMCNTRLDEVRn(i));
+		etm_writel(etm, cpu, etm.cntr_val[i], ETMCNTVRn(i));
+	}
+	etm_writel(etm, cpu, etm.seq_12_event, ETMSQ12EVR);
+	etm_writel(etm, cpu, etm.seq_21_event, ETMSQ21EVR);
+	etm_writel(etm, cpu, etm.seq_23_event, ETMSQ23EVR);
+	etm_writel(etm, cpu, etm.seq_31_event, ETMSQ31EVR);
+	etm_writel(etm, cpu, etm.seq_32_event, ETMSQ32EVR);
+	etm_writel(etm, cpu, etm.seq_13_event, ETMSQ13EVR);
+	etm_writel(etm, cpu, etm.seq_curr_state, ETMSQR);
+	for (i = 0; i < etm.nr_ext_out; i++)
+		etm_writel(etm, cpu, 0x0000406F, ETMEXTOUTEVRn(i));
+	for (i = 0; i < etm.nr_ctxid_cmp; i++)
+		etm_writel(etm, cpu, etm.ctxid_val[i], ETMCIDCVRn(i));
+	etm_writel(etm, cpu, etm.ctxid_mask, ETMCIDCMR);
+	etm_writel(etm, cpu, etm.sync_freq, ETMSYNCFR);
+	etm_writel(etm, cpu, 0x00000000, ETMEXTINSELR);
+	etm_writel(etm, cpu, etm.timestamp_event, ETMTSEVR);
+	etm_writel(etm, cpu, 0x00000000, ETMAUXCR);
+	etm_writel(etm, cpu, cpu+1, ETMTRACEIDR);
+	etm_writel(etm, cpu, 0x00000000, ETMVMIDCVR);
+
+	etm_clr_prog(cpu);
+	ETM_LOCK(cpu);
+}
+
+static int etm_enable(void)
+{
+	int ret, cpu;
+
+	if (etm.enabled) {
+		dev_err(etm.dev, "ETM tracing already enabled\n");
+		ret = -EPERM;
+		goto err;
+	}
+
+	wake_lock(&etm.wake_lock);
+	/* 1. causes all online cpus to come out of idle PC
+	 * 2. prevents idle PC until save restore flag is enabled atomically
+	 *
+	 * we rely on the user to prevent hotplug on/off racing with this
+	 * operation and to ensure cores where trace is expected to be turned
+	 * on are already hotplugged on
+	 */
+	pm_qos_update_request(&etm.qos_req, 0);
+
+	ret = qdss_enable(etm.src);
+	if (ret)
+		goto err_qdss;
+
+	for_each_online_cpu(cpu)
+		__etm_enable(cpu);
+
+	etm.enabled = true;
+
+	pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm.wake_lock);
+
+	dev_info(etm.dev, "ETM tracing enabled\n");
+	return 0;
+
+err_qdss:
+	pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm.wake_lock);
+err:
+	return ret;
+}
+
+static void __etm_disable(int cpu)
+{
+	ETM_UNLOCK(cpu);
+	etm_set_prog(cpu);
+
+	/* program trace enable to low by using always false event */
+	etm_writel(etm, cpu, 0x6F | BIT(14), ETMTEEVR);
+
+	/* Vote for ETM power/clock disable */
+	etm_set_pwrdwn(cpu);
+	ETM_LOCK(cpu);
+}
+
+static int etm_disable(void)
+{
+	int ret, cpu;
+
+	if (!etm.enabled) {
+		dev_err(etm.dev, "ETM tracing already disabled\n");
+		ret = -EPERM;
+		goto err;
+	}
+
+	wake_lock(&etm.wake_lock);
+	/* 1. causes all online cpus to come out of idle PC
+	 * 2. prevents idle PC until save restore flag is disabled atomically
+	 *
+	 * we rely on the user to prevent hotplug on/off racing with this
+	 * operation and to ensure cores where trace is expected to be turned
+	 * off are already hotplugged on
+	 */
+	pm_qos_update_request(&etm.qos_req, 0);
+
+	for_each_online_cpu(cpu)
+		__etm_disable(cpu);
+
+	qdss_disable(etm.src);
+
+	etm.enabled = false;
+
+	pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm.wake_lock);
+
+	dev_info(etm.dev, "ETM tracing disabled\n");
+	return 0;
+err:
+	return ret;
+}
+
+/* Memory mapped writes to clear os lock not supported */
+static void etm_os_unlock(void *unused)
+{
+	unsigned long value = 0x0;
+
+	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
+	asm("isb\n\t");
+}
+
+#define ETM_STORE(__name, mask)						\
+static ssize_t __name##_store(struct kobject *kobj,			\
+			struct kobj_attribute *attr,			\
+			const char *buf, size_t n)			\
+{									\
+	unsigned long val;						\
+									\
+	if (sscanf(buf, "%lx", &val) != 1)				\
+		return -EINVAL;						\
+									\
+	etm.__name = val & mask;					\
+	return n;							\
+}
+
+#define ETM_SHOW(__name)						\
+static ssize_t __name##_show(struct kobject *kobj,			\
+			struct kobj_attribute *attr,			\
+			char *buf)					\
+{									\
+	unsigned long val = etm.__name;					\
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);		\
+}
+
+#define ETM_ATTR(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+#define ETM_ATTR_RO(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO, __name##_show, NULL)
+
+static ssize_t enabled_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	int ret = 0;
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	if (val)
+		ret = etm_enable();
+	else
+		ret = etm_disable();
+	mutex_unlock(&etm.mutex);
+
+	if (ret)
+		return ret;
+	return n;
+}
+ETM_SHOW(enabled);
+ETM_ATTR(enabled);
+
+ETM_SHOW(nr_addr_cmp);
+ETM_ATTR_RO(nr_addr_cmp);
+ETM_SHOW(nr_cntr);
+ETM_ATTR_RO(nr_cntr);
+ETM_SHOW(nr_ctxid_cmp);
+ETM_ATTR_RO(nr_ctxid_cmp);
+
+/* Reset to trace everything i.e. exclude nothing. */
+static ssize_t reset_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	int i;
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	if (val) {
+		etm.mode = ETM_MODE_EXCLUDE;
+		etm.ctrl = 0x0;
+		if (cpu_is_krait_v1()) {
+			etm.mode |= ETM_MODE_CYCACC;
+			etm.ctrl |= BIT(12);
+		}
+		etm.trigger_event = 0x406F;
+		etm.startstop_ctrl = 0x0;
+		etm.enable_event = 0x6F;
+		etm.enable_ctrl1 = 0x1000000;
+		etm.fifofull_level = 0x28;
+		etm.addr_idx = 0x0;
+		for (i = 0; i < etm.nr_addr_cmp; i++) {
+			etm.addr_val[i] = 0x0;
+			etm.addr_acctype[i] = 0x0;
+			etm.addr_type[i] = ETM_ADDR_TYPE_NONE;
+		}
+		etm.cntr_idx = 0x0;
+		for (i = 0; i < etm.nr_cntr; i++) {
+			etm.cntr_rld_val[i] = 0x0;
+			etm.cntr_event[i] = 0x406F;
+			etm.cntr_rld_event[i] = 0x406F;
+			etm.cntr_val[i] = 0x0;
+		}
+		etm.seq_12_event = 0x406F;
+		etm.seq_21_event = 0x406F;
+		etm.seq_23_event = 0x406F;
+		etm.seq_31_event = 0x406F;
+		etm.seq_32_event = 0x406F;
+		etm.seq_13_event = 0x406F;
+		etm.seq_curr_state = 0x0;
+		etm.ctxid_idx = 0x0;
+		for (i = 0; i < etm.nr_ctxid_cmp; i++)
+			etm.ctxid_val[i] = 0x0;
+		etm.ctxid_mask = 0x0;
+		etm.sync_freq = 0x80;
+		etm.timestamp_event = 0x406F;
+	}
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(reset);
+ETM_ATTR(reset);
+
+static ssize_t mode_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.mode = val & ETM_MODE_ALL;
+
+	if (etm.mode & ETM_MODE_EXCLUDE)
+		etm.enable_ctrl1 |= BIT(24);
+	else
+		etm.enable_ctrl1 &= ~BIT(24);
+
+	if (etm.mode & ETM_MODE_CYCACC)
+		etm.ctrl |= BIT(12);
+	else
+		etm.ctrl &= ~BIT(12);
+
+	if (etm.mode & ETM_MODE_STALL)
+		etm.ctrl |= BIT(7);
+	else
+		etm.ctrl &= ~BIT(7);
+
+	if (etm.mode & ETM_MODE_TIMESTAMP)
+		etm.ctrl |= BIT(28);
+	else
+		etm.ctrl &= ~BIT(28);
+	if (etm.mode & ETM_MODE_CTXID)
+		etm.ctrl |= (BIT(14) | BIT(15));
+	else
+		etm.ctrl &= ~(BIT(14) | BIT(15));
+	mutex_unlock(&etm.mutex);
+
+	return n;
+}
+ETM_SHOW(mode);
+ETM_ATTR(mode);
+
+ETM_STORE(trigger_event, ETM_EVENT_MASK);
+ETM_SHOW(trigger_event);
+ETM_ATTR(trigger_event);
+
+ETM_STORE(enable_event, ETM_EVENT_MASK);
+ETM_SHOW(enable_event);
+ETM_ATTR(enable_event);
+
+ETM_STORE(fifofull_level, ETM_ALL_MASK);
+ETM_SHOW(fifofull_level);
+ETM_ATTR(fifofull_level);
+
+static ssize_t addr_idx_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= etm.nr_addr_cmp)
+		return -EINVAL;
+
+	/* Use mutex to ensure index doesn't change while it gets dereferenced
+	 * multiple times within a mutex block elsewhere.
+	 */
+	mutex_lock(&etm.mutex);
+	etm.addr_idx = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(addr_idx);
+ETM_ATTR(addr_idx);
+
+static ssize_t addr_single_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_single_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val = etm.addr_val[idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_single);
+
+static ssize_t addr_range_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val1, val2;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+	/* lower address comparator cannot have a higher address value */
+	if (val1 > val2)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (idx % 2 != 0) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+	if (!((etm.addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (etm.addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val1;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_RANGE;
+	etm.addr_val[idx + 1] = val2;
+	etm.addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
+	etm.enable_ctrl1 |= (1 << (idx/2));
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_range_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val1, val2;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (idx % 2 != 0) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+	if (!((etm.addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (etm.addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val1 = etm.addr_val[idx];
+	val2 = etm.addr_val[idx + 1];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
+}
+ETM_ATTR(addr_range);
+
+static ssize_t addr_start_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_START;
+	etm.startstop_ctrl |= (1 << idx);
+	etm.enable_ctrl1 |= BIT(25);
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_start_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val = etm.addr_val[idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_start);
+
+static ssize_t addr_stop_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_STOP;
+	etm.startstop_ctrl |= (1 << (idx + 16));
+	etm.enable_ctrl1 |= BIT(25);
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_stop_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val = etm.addr_val[idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_stop);
+
+static ssize_t addr_acctype_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.addr_acctype[etm.addr_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_acctype_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.addr_acctype[etm.addr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_acctype);
+
+static ssize_t cntr_idx_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= etm.nr_cntr)
+		return -EINVAL;
+
+	/* Use mutex to ensure index doesn't change while it gets dereferenced
+	 * multiple times within a mutex block elsewhere.
+	 */
+	mutex_lock(&etm.mutex);
+	etm.cntr_idx = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(cntr_idx);
+ETM_ATTR(cntr_idx);
+
+static ssize_t cntr_rld_val_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_rld_val[etm.cntr_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_rld_val_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_rld_val[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_rld_val);
+
+static ssize_t cntr_event_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_event[etm.cntr_idx] = val & ETM_EVENT_MASK;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_event_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_event[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_event);
+
+static ssize_t cntr_rld_event_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_rld_event[etm.cntr_idx] = val & ETM_EVENT_MASK;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_rld_event_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_rld_event[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_rld_event);
+
+static ssize_t cntr_val_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_val[etm.cntr_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_val_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_val[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_val);
+
+ETM_STORE(seq_12_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_12_event);
+ETM_ATTR(seq_12_event);
+
+ETM_STORE(seq_21_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_21_event);
+ETM_ATTR(seq_21_event);
+
+ETM_STORE(seq_23_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_23_event);
+ETM_ATTR(seq_23_event);
+
+ETM_STORE(seq_31_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_31_event);
+ETM_ATTR(seq_31_event);
+
+ETM_STORE(seq_32_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_32_event);
+ETM_ATTR(seq_32_event);
+
+ETM_STORE(seq_13_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_13_event);
+ETM_ATTR(seq_13_event);
+
+static ssize_t seq_curr_state_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val > ETM_SEQ_STATE_MAX_VAL)
+		return -EINVAL;
+
+	etm.seq_curr_state = val;
+	return n;
+}
+ETM_SHOW(seq_curr_state);
+ETM_ATTR(seq_curr_state);
+
+static ssize_t ctxid_idx_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= etm.nr_ctxid_cmp)
+		return -EINVAL;
+
+	/* Use mutex to ensure index doesn't change while it gets dereferenced
+	 * multiple times within a mutex block elsewhere.
+	 */
+	mutex_lock(&etm.mutex);
+	etm.ctxid_idx = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(ctxid_idx);
+ETM_ATTR(ctxid_idx);
+
+static ssize_t ctxid_val_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.ctxid_val[etm.ctxid_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t ctxid_val_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.ctxid_val[etm.ctxid_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(ctxid_val);
+
+ETM_STORE(ctxid_mask, ETM_ALL_MASK);
+ETM_SHOW(ctxid_mask);
+ETM_ATTR(ctxid_mask);
+
+ETM_STORE(sync_freq, ETM_SYNC_MASK);
+ETM_SHOW(sync_freq);
+ETM_ATTR(sync_freq);
+
+ETM_STORE(timestamp_event, ETM_EVENT_MASK);
+ETM_SHOW(timestamp_event);
+ETM_ATTR(timestamp_event);
+
+static struct attribute *etm_attrs[] = {
+	&nr_addr_cmp_attr.attr,
+	&nr_cntr_attr.attr,
+	&nr_ctxid_cmp_attr.attr,
+	&reset_attr.attr,
+	&mode_attr.attr,
+	&trigger_event_attr.attr,
+	&enable_event_attr.attr,
+	&fifofull_level_attr.attr,
+	&addr_idx_attr.attr,
+	&addr_single_attr.attr,
+	&addr_range_attr.attr,
+	&addr_start_attr.attr,
+	&addr_stop_attr.attr,
+	&addr_acctype_attr.attr,
+	&cntr_idx_attr.attr,
+	&cntr_rld_val_attr.attr,
+	&cntr_event_attr.attr,
+	&cntr_rld_event_attr.attr,
+	&cntr_val_attr.attr,
+	&seq_12_event_attr.attr,
+	&seq_21_event_attr.attr,
+	&seq_23_event_attr.attr,
+	&seq_31_event_attr.attr,
+	&seq_32_event_attr.attr,
+	&seq_13_event_attr.attr,
+	&seq_curr_state_attr.attr,
+	&ctxid_idx_attr.attr,
+	&ctxid_val_attr.attr,
+	&ctxid_mask_attr.attr,
+	&sync_freq_attr.attr,
+	&timestamp_event_attr.attr,
+	NULL,
+};
+
+static struct attribute_group etm_attr_grp = {
+	.attrs = etm_attrs,
+};
+
+static int __init etm_sysfs_init(void)
+{
+	int ret;
+
+	etm.kobj = kobject_create_and_add("etm", qdss_get_modulekobj());
+	if (!etm.kobj) {
+		dev_err(etm.dev, "failed to create ETM sysfs kobject\n");
+		ret = -ENOMEM;
+		goto err_create;
+	}
+
+	ret = sysfs_create_file(etm.kobj, &enabled_attr.attr);
+	if (ret) {
+		dev_err(etm.dev, "failed to create ETM sysfs enabled"
+		" attribute\n");
+		goto err_file;
+	}
+
+	if (sysfs_create_group(etm.kobj, &etm_attr_grp))
+		dev_err(etm.dev, "failed to create ETM sysfs group\n");
+
+	return 0;
+err_file:
+	kobject_put(etm.kobj);
+err_create:
+	return ret;
+}
+
+static void __exit etm_sysfs_exit(void)
+{
+	sysfs_remove_group(etm.kobj, &etm_attr_grp);
+	sysfs_remove_file(etm.kobj, &enabled_attr.attr);
+	kobject_put(etm.kobj);
+}
+
+static bool __init etm_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case PFT_ARCH_V1_1:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static int __init etm_arch_init(void)
+{
+	int ret, i;
+	/* use cpu 0 for setup */
+	int cpu = 0;
+	uint32_t etmidr;
+	uint32_t etmccr;
+
+	/* Unlock OS lock first to allow memory mapped reads and writes */
+	etm_os_unlock(NULL);
+	smp_call_function(etm_os_unlock, NULL, 1);
+	ETM_UNLOCK(cpu);
+	/* Vote for ETM power/clock enable */
+	etm_clr_pwrdwn(cpu);
+	/* Set prog bit. It will be set from reset but this is included to
+	 * ensure it is set
+	 */
+	etm_set_prog(cpu);
+
+	/* find all capabilities */
+	etmidr = etm_readl(etm, cpu, ETMIDR);
+	etm.arch = BMVAL(etmidr, 4, 11);
+	if (etm_arch_supported(etm.arch) == false) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	etmccr = etm_readl(etm, cpu, ETMCCR);
+	etm.nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+	etm.nr_cntr = BMVAL(etmccr, 13, 15);
+	etm.nr_ext_inp = BMVAL(etmccr, 17, 19);
+	etm.nr_ext_out = BMVAL(etmccr, 20, 22);
+	etm.nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+
+	if (cpu_is_krait_v1()) {
+		/* Krait pass1 doesn't support include filtering and non-cycle
+		 * accurate tracing
+		 */
+		etm.mode = (ETM_MODE_EXCLUDE | ETM_MODE_CYCACC);
+		etm.ctrl = 0x1000;
+		etm.enable_ctrl1 = 0x1000000;
+		for (i = 0; i < etm.nr_addr_cmp; i++) {
+			etm.addr_val[i] = 0x0;
+			etm.addr_acctype[i] = 0x0;
+			etm.addr_type[i] = ETM_ADDR_TYPE_NONE;
+		}
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_set_pwrdwn(cpu);
+	ETM_LOCK(cpu);
+
+	return 0;
+err:
+	return ret;
+}
+
+static int __devinit etm_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto err_res;
+	}
+
+	etm.base = ioremap_nocache(res->start, resource_size(res));
+	if (!etm.base) {
+		ret = -EINVAL;
+		goto err_ioremap;
+	}
+
+	etm.dev = &pdev->dev;
+
+	mutex_init(&etm.mutex);
+	wake_lock_init(&etm.wake_lock, WAKE_LOCK_SUSPEND, "msm_etm");
+	pm_qos_add_request(&etm.qos_req, PM_QOS_CPU_DMA_LATENCY,
+						PM_QOS_DEFAULT_VALUE);
+	etm.src = qdss_get("msm_etm");
+	if (IS_ERR(etm.src)) {
+		ret = PTR_ERR(etm.src);
+		goto err_qdssget;
+	}
+
+	ret = qdss_clk_enable();
+	if (ret)
+		goto err_clk;
+
+	ret = etm_arch_init();
+	if (ret)
+		goto err_arch;
+
+	ret = etm_sysfs_init();
+	if (ret)
+		goto err_sysfs;
+
+	etm.enabled = false;
+
+	qdss_clk_disable();
+
+	dev_info(etm.dev, "ETM initialized\n");
+
+	if (etm_boot_enable)
+		etm_enable();
+
+	return 0;
+
+err_sysfs:
+err_arch:
+	qdss_clk_disable();
+err_clk:
+	qdss_put(etm.src);
+err_qdssget:
+	pm_qos_remove_request(&etm.qos_req);
+	wake_lock_destroy(&etm.wake_lock);
+	mutex_destroy(&etm.mutex);
+	iounmap(etm.base);
+err_ioremap:
+err_res:
+	dev_err(etm.dev, "ETM init failed\n");
+	return ret;
+}
+
+static int __devexit etm_remove(struct platform_device *pdev)
+{
+	if (etm.enabled)
+		etm_disable();
+	etm_sysfs_exit();
+	qdss_put(etm.src);
+	pm_qos_remove_request(&etm.qos_req);
+	wake_lock_destroy(&etm.wake_lock);
+	mutex_destroy(&etm.mutex);
+	iounmap(etm.base);
+
+	return 0;
+}
+
+static struct platform_driver etm_driver = {
+	.probe          = etm_probe,
+	.remove         = __devexit_p(etm_remove),
+	.driver         = {
+		.name   = "msm_etm",
+	},
+};
+
+int __init etm_init(void)
+{
+	return platform_driver_register(&etm_driver);
+}
+module_init(etm_init);
+
+void __exit etm_exit(void)
+{
+	platform_driver_unregister(&etm_driver);
+}
+module_exit(etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Program Flow Trace driver");
diff --git a/arch/arm/mach-msm/qdss-funnel.c b/arch/arm/mach-msm/qdss-funnel.c
index dd61c15..2d80603 100644
--- a/arch/arm/mach-msm/qdss-funnel.c
+++ b/arch/arm/mach-msm/qdss-funnel.c
@@ -19,19 +19,19 @@
 #include <linux/io.h>
 #include <linux/err.h>
 
-#include "qdss.h"
+#include "qdss-priv.h"
 
 #define funnel_writel(funnel, id, val, off)	\
 			__raw_writel((val), funnel.base + (SZ_4K * id) + off)
 #define funnel_readl(funnel, id, off)		\
 			__raw_readl(funnel.base + (SZ_4K * id) + off)
 
-#define CS_TFUNNEL_FUNCTL		(0x000)
-#define CS_TFUNNEL_PRICTL		(0x004)
-#define CS_TFUNNEL_ITATBDATA0		(0xEEC)
-#define CS_TFUNNEL_ITATBCTR2		(0xEF0)
-#define CS_TFUNNEL_ITATBCTR1		(0xEF4)
-#define CS_TFUNNEL_ITATBCTR0		(0xEF8)
+#define FUNNEL_FUNCTL			(0x000)
+#define FUNNEL_PRICTL			(0x004)
+#define FUNNEL_ITATBDATA0		(0xEEC)
+#define FUNNEL_ITATBCTR2		(0xEF0)
+#define FUNNEL_ITATBCTR1		(0xEF4)
+#define FUNNEL_ITATBCTR0		(0xEF8)
 
 
 #define FUNNEL_LOCK(id)							\
@@ -45,15 +45,17 @@
 	mb();								\
 } while (0)
 
-#define DEFAULT_HOLDTIME_MASK		(0xF00)
-#define DEFAULT_HOLDTIME_SHFT		(0x8)
-#define DEFAULT_HOLDTIME		(0x7 << DEFAULT_HOLDTIME_SHFT)
-#define DEFAULT_PRIORITY		(0xFAC680)
+#define FUNNEL_HOLDTIME_MASK		(0xF00)
+#define FUNNEL_HOLDTIME_SHFT		(0x8)
+#define FUNNEL_HOLDTIME			(0x7 << FUNNEL_HOLDTIME_SHFT)
 
 struct funnel_ctx {
 	void __iomem	*base;
 	bool		enabled;
+	struct mutex	mutex;
 	struct device	*dev;
+	struct kobject	*kobj;
+	uint32_t	priority;
 };
 
 static struct funnel_ctx funnel;
@@ -64,22 +66,24 @@
 
 	FUNNEL_UNLOCK(id);
 
-	functl = funnel_readl(funnel, id, CS_TFUNNEL_FUNCTL);
-	functl &= ~DEFAULT_HOLDTIME_MASK;
-	functl |= DEFAULT_HOLDTIME;
+	functl = funnel_readl(funnel, id, FUNNEL_FUNCTL);
+	functl &= ~FUNNEL_HOLDTIME_MASK;
+	functl |= FUNNEL_HOLDTIME;
 	functl |= port_mask;
-	funnel_writel(funnel, id, functl, CS_TFUNNEL_FUNCTL);
-	funnel_writel(funnel, id, DEFAULT_PRIORITY, CS_TFUNNEL_PRICTL);
+	funnel_writel(funnel, id, functl, FUNNEL_FUNCTL);
+	funnel_writel(funnel, id, funnel.priority, FUNNEL_PRICTL);
 
 	FUNNEL_LOCK(id);
 }
 
 void funnel_enable(uint8_t id, uint32_t port_mask)
 {
+	mutex_lock(&funnel.mutex);
 	__funnel_enable(id, port_mask);
 	funnel.enabled = true;
-	dev_info(funnel.dev, "funnel port mask 0x%lx enabled\n",
+	dev_info(funnel.dev, "FUNNEL port mask 0x%lx enabled\n",
 					(unsigned long) port_mask);
+	mutex_unlock(&funnel.mutex);
 }
 
 static void __funnel_disable(uint8_t id, uint32_t port_mask)
@@ -88,19 +92,77 @@
 
 	FUNNEL_UNLOCK(id);
 
-	functl = funnel_readl(funnel, id, CS_TFUNNEL_FUNCTL);
+	functl = funnel_readl(funnel, id, FUNNEL_FUNCTL);
 	functl &= ~port_mask;
-	funnel_writel(funnel, id, functl, CS_TFUNNEL_FUNCTL);
+	funnel_writel(funnel, id, functl, FUNNEL_FUNCTL);
 
 	FUNNEL_LOCK(id);
 }
 
 void funnel_disable(uint8_t id, uint32_t port_mask)
 {
+	mutex_lock(&funnel.mutex);
 	__funnel_disable(id, port_mask);
 	funnel.enabled = false;
-	dev_info(funnel.dev, "funnel port mask 0x%lx disabled\n",
+	dev_info(funnel.dev, "FUNNEL port mask 0x%lx disabled\n",
 					(unsigned long) port_mask);
+	mutex_unlock(&funnel.mutex);
+}
+
+#define FUNNEL_ATTR(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+
+static ssize_t priority_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	funnel.priority = val;
+	return n;
+}
+static ssize_t priority_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = funnel.priority;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+FUNNEL_ATTR(priority);
+
+static int __init funnel_sysfs_init(void)
+{
+	int ret;
+
+	funnel.kobj = kobject_create_and_add("funnel", qdss_get_modulekobj());
+	if (!funnel.kobj) {
+		dev_err(funnel.dev, "failed to create FUNNEL sysfs kobject\n");
+		ret = -ENOMEM;
+		goto err_create;
+	}
+
+	ret = sysfs_create_file(funnel.kobj, &priority_attr.attr);
+	if (ret) {
+		dev_err(funnel.dev, "failed to create FUNNEL sysfs priority"
+		" attribute\n");
+		goto err_file;
+	}
+
+	return 0;
+err_file:
+	kobject_put(funnel.kobj);
+err_create:
+	return ret;
+}
+
+static void __exit funnel_sysfs_exit(void)
+{
+	sysfs_remove_file(funnel.kobj, &priority_attr.attr);
+	kobject_put(funnel.kobj);
 }
 
 static int __devinit funnel_probe(struct platform_device *pdev)
@@ -122,17 +184,25 @@
 
 	funnel.dev = &pdev->dev;
 
+	mutex_init(&funnel.mutex);
+
+	funnel_sysfs_init();
+
+	dev_info(funnel.dev, "FUNNEL initialized\n");
 	return 0;
 
 err_ioremap:
 err_res:
+	dev_err(funnel.dev, "FUNNEL init failed\n");
 	return ret;
 }
 
-static int funnel_remove(struct platform_device *pdev)
+static int __devexit funnel_remove(struct platform_device *pdev)
 {
 	if (funnel.enabled)
 		funnel_disable(0x0, 0xFF);
+	funnel_sysfs_exit();
+	mutex_destroy(&funnel.mutex);
 	iounmap(funnel.base);
 
 	return 0;
@@ -140,18 +210,23 @@
 
 static struct platform_driver funnel_driver = {
 	.probe          = funnel_probe,
-	.remove         = funnel_remove,
+	.remove         = __devexit_p(funnel_remove),
 	.driver         = {
 		.name   = "msm_funnel",
 	},
 };
 
-int __init funnel_init(void)
+static int __init funnel_init(void)
 {
 	return platform_driver_register(&funnel_driver);
 }
+module_init(funnel_init);
 
-void funnel_exit(void)
+static void __exit funnel_exit(void)
 {
 	platform_driver_unregister(&funnel_driver);
 }
+module_exit(funnel_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Funnel driver");
diff --git a/arch/arm/mach-msm/qdss.h b/arch/arm/mach-msm/qdss-priv.h
similarity index 81%
rename from arch/arm/mach-msm/qdss.h
rename to arch/arm/mach-msm/qdss-priv.h
index 199222a..f39bc52 100644
--- a/arch/arm/mach-msm/qdss.h
+++ b/arch/arm/mach-msm/qdss-priv.h
@@ -14,6 +14,7 @@
 #define _ARCH_ARM_MACH_MSM_QDSS_H_
 
 #include <linux/bitops.h>
+#include <mach/qdss.h>
 
 /* Coresight management registers (0xF00-0xFCC)
  * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
@@ -51,37 +52,19 @@
 #define PFT_ARCH_V1_1		(0x31)
 
 #define TIMEOUT_US		(100)
-#define OSLOCK_MAGIC		(0xC5ACCE55)
 #define CS_UNLOCK_MAGIC		(0xC5ACCE55)
 
 #define BM(lsb, msb)		((BIT(msb) - BIT(lsb)) + BIT(msb))
 #define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
 #define BVAL(val, n)		((val & BIT(n)) >> n)
 
-int etb_init(void);
-void etb_exit(void);
-int tpiu_init(void);
-void tpiu_exit(void);
-int funnel_init(void);
-void funnel_exit(void);
-int ptm_init(void);
-void ptm_exit(void);
-
 void etb_enable(void);
 void etb_disable(void);
 void etb_dump(void);
 void tpiu_disable(void);
 void funnel_enable(uint8_t id, uint32_t port_mask);
 void funnel_disable(uint8_t id, uint32_t port_mask);
-int qdss_clk_enable(void);
-void qdss_clk_disable(void);
 
-#ifdef CONFIG_MSM_JTAG
-extern void msm_jtag_save_state(void);
-extern void msm_jtag_restore_state(void);
-#else
-static inline void msm_jtag_save_state(void) {}
-static inline void msm_jtag_restore_state(void) {}
-#endif
+struct kobject *qdss_get_modulekobj(void);
 
 #endif
diff --git a/arch/arm/mach-msm/qdss-ptm.c b/arch/arm/mach-msm/qdss-ptm.c
deleted file mode 100644
index c0dc58e..0000000
--- a/arch/arm/mach-msm/qdss-ptm.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/err.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/smp.h>
-#include <linux/wakelock.h>
-#include <linux/pm_qos_params.h>
-#include <asm/atomic.h>
-
-#include "qdss.h"
-
-#define ptm_writel(ptm, cpu, val, off)	\
-			__raw_writel((val), ptm.base + (SZ_4K * cpu) + off)
-#define ptm_readl(ptm, cpu, off)	\
-			__raw_readl(ptm.base + (SZ_4K * cpu) + off)
-
-/*
- * Device registers:
- * 0x000 - 0x2FC: Trace		registers
- * 0x300 - 0x314: Management	registers
- * 0x318 - 0xEFC: Trace		registers
- *
- * Coresight registers
- * 0xF00 - 0xF9C: Management	registers
- * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
- *		  Trace		registers in PFTv1.1
- * 0xFA8 - 0xFFC: Management	registers
- */
-
-/* Trace registers (0x000-0x2FC) */
-#define ETMCR			(0x000)
-#define ETMCCR			(0x004)
-#define ETMTRIGGER		(0x008)
-#define ETMSR			(0x010)
-#define ETMSCR			(0x014)
-#define ETMTSSCR		(0x018)
-#define ETMTEEVR		(0x020)
-#define ETMTECR1		(0x024)
-#define ETMFFLR			(0x02C)
-#define ETMACVRn(n)		(0x040 + (n * 4))
-#define ETMACTRn(n)		(0x080 + (n * 4))
-#define ETMCNTRLDVRn(n)		(0x140 + (n * 4))
-#define ETMCNTENRn(n)		(0x150 + (n * 4))
-#define ETMCNTRLDEVRn(n)	(0x160 + (n * 4))
-#define ETMCNTVRn(n)		(0x170 + (n * 4))
-#define ETMSQ12EVR		(0x180)
-#define ETMSQ21EVR		(0x184)
-#define ETMSQ23EVR		(0x188)
-#define ETMSQ31EVR		(0x18C)
-#define ETMSQ32EVR		(0x190)
-#define ETMSQ13EVR		(0x194)
-#define ETMSQR			(0x19C)
-#define ETMEXTOUTEVRn(n)	(0x1A0 + (n * 4))
-#define ETMCIDCVRn(n)		(0x1B0 + (n * 4))
-#define ETMCIDCMR		(0x1BC)
-#define ETMIMPSPEC0		(0x1C0)
-#define ETMIMPSPEC1		(0x1C4)
-#define ETMIMPSPEC2		(0x1C8)
-#define ETMIMPSPEC3		(0x1CC)
-#define ETMIMPSPEC4		(0x1D0)
-#define ETMIMPSPEC5		(0x1D4)
-#define ETMIMPSPEC6		(0x1D8)
-#define ETMIMPSPEC7		(0x1DC)
-#define ETMSYNCFR		(0x1E0)
-#define ETMIDR			(0x1E4)
-#define ETMCCER			(0x1E8)
-#define ETMEXTINSELR		(0x1EC)
-#define ETMTESSEICR		(0x1F0)
-#define ETMEIBCR		(0x1F4)
-#define ETMTSEVR		(0x1F8)
-#define ETMAUXCR		(0x1FC)
-#define ETMTRACEIDR		(0x200)
-#define ETMVMIDCVR		(0x240)
-/* Management registers (0x300-0x314) */
-#define ETMOSLAR		(0x300)
-#define ETMOSLSR		(0x304)
-#define ETMOSSRR		(0x308)
-#define ETMPDCR			(0x310)
-#define ETMPDSR			(0x314)
-
-#define PTM_LOCK(cpu)							\
-do {									\
-	mb();								\
-	ptm_writel(ptm, cpu, 0x0, CS_LAR);				\
-} while (0)
-#define PTM_UNLOCK(cpu)							\
-do {									\
-	ptm_writel(ptm, cpu, CS_UNLOCK_MAGIC, CS_LAR);			\
-	mb();								\
-} while (0)
-
-
-/* Forward declarations */
-static void ptm_cfg_rw_init(void);
-
-#ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
-static int trace_on_boot = 1;
-#else
-static int trace_on_boot;
-#endif
-module_param_named(
-	trace_on_boot, trace_on_boot, int, S_IRUGO
-);
-
-struct ptm_config {
-	/* read only config registers */
-	uint32_t	config_code;
-	/* derived values */
-	uint8_t		nr_addr_comp;
-	uint8_t		nr_cntr;
-	uint8_t		nr_ext_input;
-	uint8_t		nr_ext_output;
-	uint8_t		nr_context_id_comp;
-
-	uint32_t	config_code_extn;
-	/* derived values */
-	uint8_t		nr_extnd_ext_input_sel;
-	uint8_t		nr_instr_resources;
-
-	uint32_t	system_config;
-	/* derived values */
-	uint8_t		fifofull_supported;
-	uint8_t		nr_procs_supported;
-
-	/* read-write registers */
-	uint32_t	main_control;
-	uint32_t	trigger_event;
-	uint32_t	te_start_stop_control;
-	uint32_t	te_event;
-	uint32_t	te_control;
-	uint32_t	fifofull_level;
-	uint32_t	addr_comp_value[16];
-	uint32_t	addr_comp_access_type[16];
-	uint32_t	cntr_reload_value[4];
-	uint32_t	cntr_enable_event[4];
-	uint32_t	cntr_reload_event[4];
-	uint32_t	cntr_value[4];
-	uint32_t	seq_state_12_event;
-	uint32_t	seq_state_21_event;
-	uint32_t	seq_state_23_event;
-	uint32_t	seq_state_32_event;
-	uint32_t	seq_state_13_event;
-	uint32_t	seq_state_31_event;
-	uint32_t	current_seq_state;
-	uint32_t	ext_output_event[4];
-	uint32_t	context_id_comp_value[3];
-	uint32_t	context_id_comp_mask;
-	uint32_t	sync_freq;
-	uint32_t	extnd_ext_input_sel;
-	uint32_t	ts_event;
-	uint32_t	aux_control;
-	uint32_t	coresight_trace_id;
-	uint32_t	vmid_comp_value;
-};
-
-struct ptm_ctx {
-	struct ptm_config		cfg;
-	void __iomem			*base;
-	bool				trace_enabled;
-	struct wake_lock		wake_lock;
-	struct pm_qos_request_list	qos_req;
-	atomic_t			in_use;
-	struct device			*dev;
-};
-
-static struct ptm_ctx ptm;
-
-
-/* ETM clock is derived from the processor clock and gets enabled on a
- * logical OR of below items on Krait (pass2 onwards):
- * 1.CPMR[ETMCLKEN] is 1
- * 2.ETMCR[PD] is 0
- * 3.ETMPDCR[PU] is 1
- * 4.Reset is asserted (core or debug)
- * 5.APB memory mapped requests (eg. EDAP access)
- *
- * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
- * enables
- *
- * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
- * clock vote in the driver and the save-restore code uses 1. above
- * for its vote
- */
-static void ptm_set_powerdown(int cpu)
-{
-	uint32_t etmcr;
-
-	etmcr = ptm_readl(ptm, cpu, ETMCR);
-	etmcr |= BIT(0);
-	ptm_writel(ptm, cpu, etmcr, ETMCR);
-}
-
-static void ptm_clear_powerdown(int cpu)
-{
-	uint32_t etmcr;
-
-	etmcr = ptm_readl(ptm, cpu, ETMCR);
-	etmcr &= ~BIT(0);
-	ptm_writel(ptm, cpu, etmcr, ETMCR);
-}
-
-static void ptm_set_prog(int cpu)
-{
-	uint32_t etmcr;
-	int count;
-
-	etmcr = ptm_readl(ptm, cpu, ETMCR);
-	etmcr |= BIT(10);
-	ptm_writel(ptm, cpu, etmcr, ETMCR);
-
-	for (count = TIMEOUT_US; BVAL(ptm_readl(ptm, cpu, ETMSR), 1) != 1
-				&& count > 0; count--)
-		udelay(1);
-	WARN(count == 0, "timeout while setting prog bit\n");
-}
-
-static void ptm_clear_prog(int cpu)
-{
-	uint32_t etmcr;
-	int count;
-
-	etmcr = ptm_readl(ptm, cpu, ETMCR);
-	etmcr &= ~BIT(10);
-	ptm_writel(ptm, cpu, etmcr, ETMCR);
-
-	for (count = TIMEOUT_US; BVAL(ptm_readl(ptm, cpu, ETMSR), 1) != 0
-				&& count > 0; count--)
-		udelay(1);
-	WARN(count == 0, "timeout while clearing prog bit\n");
-}
-
-static void __ptm_trace_enable(int cpu)
-{
-	int i;
-
-	PTM_UNLOCK(cpu);
-	/* Vote for ETM power/clock enable */
-	ptm_clear_powerdown(cpu);
-	ptm_set_prog(cpu);
-
-	ptm_writel(ptm, cpu, ptm.cfg.main_control | BIT(10), ETMCR);
-	ptm_writel(ptm, cpu, ptm.cfg.trigger_event, ETMTRIGGER);
-	ptm_writel(ptm, cpu, ptm.cfg.te_start_stop_control, ETMTSSCR);
-	ptm_writel(ptm, cpu, ptm.cfg.te_event, ETMTEEVR);
-	ptm_writel(ptm, cpu, ptm.cfg.te_control, ETMTECR1);
-	ptm_writel(ptm, cpu, ptm.cfg.fifofull_level, ETMFFLR);
-	for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
-		ptm_writel(ptm, cpu, ptm.cfg.addr_comp_value[i], ETMACVRn(i));
-		ptm_writel(ptm, cpu, ptm.cfg.addr_comp_access_type[i],
-							ETMACTRn(i));
-	}
-	for (i = 0; i < ptm.cfg.nr_cntr; i++) {
-		ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_value[i],
-							ETMCNTRLDVRn(i));
-		ptm_writel(ptm, cpu, ptm.cfg.cntr_enable_event[i],
-							ETMCNTENRn(i));
-		ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_event[i],
-							ETMCNTRLDEVRn(i));
-		ptm_writel(ptm, cpu, ptm.cfg.cntr_value[i], ETMCNTVRn(i));
-	}
-	ptm_writel(ptm, cpu, ptm.cfg.seq_state_12_event, ETMSQ12EVR);
-	ptm_writel(ptm, cpu, ptm.cfg.seq_state_21_event, ETMSQ21EVR);
-	ptm_writel(ptm, cpu, ptm.cfg.seq_state_23_event, ETMSQ23EVR);
-	ptm_writel(ptm, cpu, ptm.cfg.seq_state_32_event, ETMSQ32EVR);
-	ptm_writel(ptm, cpu, ptm.cfg.seq_state_13_event, ETMSQ13EVR);
-	ptm_writel(ptm, cpu, ptm.cfg.seq_state_31_event, ETMSQ31EVR);
-	ptm_writel(ptm, cpu, ptm.cfg.current_seq_state, ETMSQR);
-	for (i = 0; i < ptm.cfg.nr_ext_output; i++)
-		ptm_writel(ptm, cpu, ptm.cfg.ext_output_event[i],
-							ETMEXTOUTEVRn(i));
-	for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
-		ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_value[i],
-							ETMCIDCVRn(i));
-	ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_mask, ETMCIDCMR);
-	ptm_writel(ptm, cpu, ptm.cfg.sync_freq, ETMSYNCFR);
-	ptm_writel(ptm, cpu, ptm.cfg.extnd_ext_input_sel, ETMEXTINSELR);
-	ptm_writel(ptm, cpu, ptm.cfg.ts_event, ETMTSEVR);
-	ptm_writel(ptm, cpu, ptm.cfg.aux_control, ETMAUXCR);
-	ptm_writel(ptm, cpu, cpu+1, ETMTRACEIDR);
-	ptm_writel(ptm, cpu, ptm.cfg.vmid_comp_value, ETMVMIDCVR);
-
-	ptm_clear_prog(cpu);
-	PTM_LOCK(cpu);
-}
-
-static int ptm_trace_enable(void)
-{
-	int ret, cpu;
-
-	ret = qdss_clk_enable();
-	if (ret)
-		return ret;
-
-	wake_lock(&ptm.wake_lock);
-	/* 1. causes all online cpus to come out of idle PC
-	 * 2. prevents idle PC until save restore flag is enabled atomically
-	 *
-	 * we rely on the user to prevent hotplug on/off racing with this
-	 * operation and to ensure cores where trace is expected to be turned
-	 * on are already hotplugged on
-	 */
-	pm_qos_update_request(&ptm.qos_req, 0);
-
-	etb_disable();
-	tpiu_disable();
-	/* enable ETB first to avoid loosing any trace data */
-	etb_enable();
-	funnel_enable(0x0, 0x3);
-	for_each_online_cpu(cpu)
-		__ptm_trace_enable(cpu);
-
-	ptm.trace_enabled = true;
-
-	pm_qos_update_request(&ptm.qos_req, PM_QOS_DEFAULT_VALUE);
-	wake_unlock(&ptm.wake_lock);
-
-	return 0;
-}
-
-static void __ptm_trace_disable(int cpu)
-{
-	PTM_UNLOCK(cpu);
-	ptm_set_prog(cpu);
-
-	/* program trace enable to low by using always false event */
-	ptm_writel(ptm, cpu, 0x6F | BIT(14), ETMTEEVR);
-
-	/* Vote for ETM power/clock disable */
-	ptm_set_powerdown(cpu);
-	PTM_LOCK(cpu);
-}
-
-static void ptm_trace_disable(void)
-{
-	int cpu;
-
-	wake_lock(&ptm.wake_lock);
-	/* 1. causes all online cpus to come out of idle PC
-	 * 2. prevents idle PC until save restore flag is disabled atomically
-	 *
-	 * we rely on the user to prevent hotplug on/off racing with this
-	 * operation and to ensure cores where trace is expected to be turned
-	 * off are already hotplugged on
-	 */
-	pm_qos_update_request(&ptm.qos_req, 0);
-
-	for_each_online_cpu(cpu)
-		__ptm_trace_disable(cpu);
-	etb_dump();
-	etb_disable();
-	funnel_disable(0x0, 0x3);
-
-	ptm.trace_enabled = false;
-
-	pm_qos_update_request(&ptm.qos_req, PM_QOS_DEFAULT_VALUE);
-	wake_unlock(&ptm.wake_lock);
-
-	qdss_clk_disable();
-}
-
-static int ptm_open(struct inode *inode, struct file *file)
-{
-	if (atomic_cmpxchg(&ptm.in_use, 0, 1))
-		return -EBUSY;
-
-	dev_dbg(ptm.dev, "%s: successfully opened\n", __func__);
-	return 0;
-}
-
-static void ptm_range_filter(char range, uint32_t reg1,
-				uint32_t addr1, uint32_t reg2, uint32_t addr2)
-{
-	ptm.cfg.addr_comp_value[reg1] = addr1;
-	ptm.cfg.addr_comp_value[reg2] = addr2;
-
-	ptm.cfg.te_control |= (1 << (reg1/2));
-	if (range == 'i')
-		ptm.cfg.te_control &= ~BIT(24);
-	else if (range == 'e')
-		ptm.cfg.te_control |= BIT(24);
-}
-
-static void ptm_start_stop_filter(char start_stop,
-				uint32_t reg, uint32_t addr)
-{
-	ptm.cfg.addr_comp_value[reg] = addr;
-
-	if (start_stop == 's')
-		ptm.cfg.te_start_stop_control |= (1 << reg);
-	else if (start_stop == 't')
-		ptm.cfg.te_start_stop_control |= (1 << (reg + 16));
-
-	ptm.cfg.te_control |= BIT(25);
-}
-
-#define MAX_COMMAND_STRLEN  40
-static ssize_t ptm_write(struct file *file, const char __user *data,
-				size_t len, loff_t *ppos)
-{
-	char command[MAX_COMMAND_STRLEN];
-	int str_len;
-	unsigned long reg1, reg2;
-	unsigned long addr1, addr2;
-
-	str_len = strnlen_user(data, MAX_COMMAND_STRLEN);
-	dev_dbg(ptm.dev, "string length: %d", str_len);
-	if (str_len == 0 || str_len == (MAX_COMMAND_STRLEN+1)) {
-		dev_err(ptm.dev, "error in str_len: %d", str_len);
-		return -EFAULT;
-	}
-	/* includes the null character */
-	if (copy_from_user(command, data, str_len)) {
-		dev_err(ptm.dev, "error in copy_from_user: %d", str_len);
-		return -EFAULT;
-	}
-
-	dev_dbg(ptm.dev, "input = %s", command);
-
-	switch (command[0]) {
-	case '0':
-		if (ptm.trace_enabled) {
-			ptm_trace_disable();
-			dev_info(ptm.dev, "tracing disabled\n");
-		} else
-			dev_err(ptm.dev, "trace already disabled\n");
-
-		break;
-	case '1':
-		if (!ptm.trace_enabled) {
-			if (!ptm_trace_enable())
-				dev_info(ptm.dev, "tracing enabled\n");
-			else
-				dev_err(ptm.dev, "error enabling trace\n");
-		} else
-			dev_err(ptm.dev, "trace already enabled\n");
-		break;
-	case 'f':
-		switch (command[2]) {
-		case 'i':
-			switch (command[4]) {
-			case 'i':
-				if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
-					&reg1, &addr1, &reg2, &addr2) != 4)
-					goto err_out;
-				if (reg1 > 7 || reg2 > 7 || (reg1 % 2))
-					goto err_out;
-				ptm_range_filter('i',
-						reg1, addr1, reg2, addr2);
-				break;
-			case 'e':
-				if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
-					&reg1, &addr1, &reg2, &addr2) != 4)
-					goto err_out;
-				if (reg1 > 7 || reg2 > 7 || (reg1 % 2)
-					|| command[2] == 'd')
-					goto err_out;
-				ptm_range_filter('e',
-						reg1, addr1, reg2, addr2);
-				break;
-			case 's':
-				if (sscanf(&command[6], "%lx:%lx\\0",
-					&reg1, &addr1) != 2)
-					goto err_out;
-				if (reg1 > 7)
-					goto err_out;
-				ptm_start_stop_filter('s', reg1, addr1);
-				break;
-			case 't':
-				if (sscanf(&command[6], "%lx:%lx\\0",
-						&reg1, &addr1) != 2)
-					goto err_out;
-				if (reg1 > 7)
-					goto err_out;
-				ptm_start_stop_filter('t', reg1, addr1);
-				break;
-			default:
-				goto err_out;
-			}
-			break;
-		case 'r':
-			ptm_cfg_rw_init();
-			break;
-		default:
-			goto err_out;
-		}
-		break;
-	default:
-		goto err_out;
-	}
-
-	return len;
-
-err_out:
-	return -EFAULT;
-}
-
-static int ptm_release(struct inode *inode, struct file *file)
-{
-	atomic_set(&ptm.in_use, 0);
-	dev_dbg(ptm.dev, "%s: released\n", __func__);
-	return 0;
-}
-
-static const struct file_operations ptm_fops = {
-	.owner =	THIS_MODULE,
-	.open =		ptm_open,
-	.write =	ptm_write,
-	.release =	ptm_release,
-};
-
-static struct miscdevice ptm_misc = {
-	.name =		"msm_ptm",
-	.minor =	MISC_DYNAMIC_MINOR,
-	.fops =		&ptm_fops,
-};
-
-static void ptm_cfg_rw_init(void)
-{
-	int i;
-
-	ptm.cfg.main_control =				0x00001000;
-	ptm.cfg.trigger_event =				0x0000406F;
-	ptm.cfg.te_start_stop_control =			0x00000000;
-	ptm.cfg.te_event =				0x0000006F;
-	ptm.cfg.te_control =				0x01000000;
-	ptm.cfg.fifofull_level =			0x00000028;
-	for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
-		ptm.cfg.addr_comp_value[i] =		0x00000000;
-		ptm.cfg.addr_comp_access_type[i] =	0x00000000;
-	}
-	for (i = 0; i < ptm.cfg.nr_cntr; i++) {
-		ptm.cfg.cntr_reload_value[i] =		0x00000000;
-		ptm.cfg.cntr_enable_event[i] =		0x0000406F;
-		ptm.cfg.cntr_reload_event[i] =		0x0000406F;
-		ptm.cfg.cntr_value[i] =			0x00000000;
-	}
-	ptm.cfg.seq_state_12_event =			0x0000406F;
-	ptm.cfg.seq_state_21_event =			0x0000406F;
-	ptm.cfg.seq_state_23_event =			0x0000406F;
-	ptm.cfg.seq_state_32_event =			0x0000406F;
-	ptm.cfg.seq_state_13_event =			0x0000406F;
-	ptm.cfg.seq_state_31_event =			0x0000406F;
-	ptm.cfg.current_seq_state =			0x00000000;
-	for (i = 0; i < ptm.cfg.nr_ext_output; i++)
-		ptm.cfg.ext_output_event[i] =		0x0000406F;
-	for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
-		ptm.cfg.context_id_comp_value[i] =	0x00000000;
-	ptm.cfg.context_id_comp_mask =			0x00000000;
-	ptm.cfg.sync_freq =				0x00000080;
-	ptm.cfg.extnd_ext_input_sel =			0x00000000;
-	ptm.cfg.ts_event =				0x0000406F;
-	ptm.cfg.aux_control =				0x00000000;
-	ptm.cfg.vmid_comp_value =			0x00000000;
-}
-
-/* Memory mapped writes to clear os lock not supported */
-static void ptm_os_unlock(void *unused)
-{
-	unsigned long value = 0x0;
-
-	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
-	asm("isb\n\t");
-}
-
-static void ptm_cfg_ro_init(void)
-{
-	/* use cpu 0 for setup */
-	int cpu = 0;
-
-	/* Unlock OS lock first to allow memory mapped reads and writes */
-	ptm_os_unlock(NULL);
-	smp_call_function(ptm_os_unlock, NULL, 1);
-	PTM_UNLOCK(cpu);
-	/* Vote for ETM power/clock enable */
-	ptm_clear_powerdown(cpu);
-	ptm_set_prog(cpu);
-
-	/* find all capabilities */
-	ptm.cfg.config_code	=	ptm_readl(ptm, cpu, ETMCCR);
-	ptm.cfg.nr_addr_comp =		BMVAL(ptm.cfg.config_code, 0, 3) * 2;
-	ptm.cfg.nr_cntr =		BMVAL(ptm.cfg.config_code, 13, 15);
-	ptm.cfg.nr_ext_input =		BMVAL(ptm.cfg.config_code, 17, 19);
-	ptm.cfg.nr_ext_output =		BMVAL(ptm.cfg.config_code, 20, 22);
-	ptm.cfg.nr_context_id_comp =	BMVAL(ptm.cfg.config_code, 24, 25);
-
-	ptm.cfg.config_code_extn =	ptm_readl(ptm, cpu, ETMCCER);
-	ptm.cfg.nr_extnd_ext_input_sel =
-					BMVAL(ptm.cfg.config_code_extn, 0, 2);
-	ptm.cfg.nr_instr_resources =	BMVAL(ptm.cfg.config_code_extn, 13, 15);
-
-	ptm.cfg.system_config =		ptm_readl(ptm, cpu, ETMSCR);
-	ptm.cfg.fifofull_supported =	BVAL(ptm.cfg.system_config, 8);
-	ptm.cfg.nr_procs_supported =	BMVAL(ptm.cfg.system_config, 12, 14);
-
-	/* Vote for ETM power/clock disable */
-	ptm_set_powerdown(cpu);
-	PTM_LOCK(cpu);
-}
-
-static int __devinit ptm_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct resource *res;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -EINVAL;
-		goto err_res;
-	}
-
-	ptm.base = ioremap_nocache(res->start, resource_size(res));
-	if (!ptm.base) {
-		ret = -EINVAL;
-		goto err_ioremap;
-	}
-
-	ptm.dev = &pdev->dev;
-
-	ret = misc_register(&ptm_misc);
-	if (ret)
-		goto err_misc;
-
-	ret = qdss_clk_enable();
-	if (ret)
-		goto err_clk;
-
-	ptm_cfg_ro_init();
-	ptm_cfg_rw_init();
-
-	ptm.trace_enabled = false;
-
-	wake_lock_init(&ptm.wake_lock, WAKE_LOCK_SUSPEND, "msm_ptm");
-	pm_qos_add_request(&ptm.qos_req, PM_QOS_CPU_DMA_LATENCY,
-						PM_QOS_DEFAULT_VALUE);
-	atomic_set(&ptm.in_use, 0);
-
-	qdss_clk_disable();
-
-	dev_info(ptm.dev, "PTM intialized.\n");
-
-	if (trace_on_boot) {
-		if (!ptm_trace_enable())
-			dev_info(ptm.dev, "tracing enabled\n");
-		else
-			dev_err(ptm.dev, "error enabling trace\n");
-	}
-
-	return 0;
-
-err_clk:
-	misc_deregister(&ptm_misc);
-err_misc:
-	iounmap(ptm.base);
-err_ioremap:
-err_res:
-	return ret;
-}
-
-static int ptm_remove(struct platform_device *pdev)
-{
-	if (ptm.trace_enabled)
-		ptm_trace_disable();
-	pm_qos_remove_request(&ptm.qos_req);
-	wake_lock_destroy(&ptm.wake_lock);
-	misc_deregister(&ptm_misc);
-	iounmap(ptm.base);
-
-	return 0;
-}
-
-static struct platform_driver ptm_driver = {
-	.probe          = ptm_probe,
-	.remove         = ptm_remove,
-	.driver         = {
-		.name   = "msm_ptm",
-	},
-};
-
-int __init ptm_init(void)
-{
-	return platform_driver_register(&ptm_driver);
-}
-
-void ptm_exit(void)
-{
-	platform_driver_unregister(&ptm_driver);
-}
diff --git a/arch/arm/mach-msm/qdss-tpiu.c b/arch/arm/mach-msm/qdss-tpiu.c
index e4a61de..fa15635 100644
--- a/arch/arm/mach-msm/qdss-tpiu.c
+++ b/arch/arm/mach-msm/qdss-tpiu.c
@@ -18,24 +18,24 @@
 #include <linux/io.h>
 #include <linux/err.h>
 
-#include "qdss.h"
+#include "qdss-priv.h"
 
 #define tpiu_writel(tpiu, val, off)	__raw_writel((val), tpiu.base + off)
 #define tpiu_readl(tpiu, off)		__raw_readl(tpiu.base + off)
 
-#define TPIU_SUPPORTED_PORT_SIZE			(0x000)
-#define TPIU_CURRENT_PORT_SIZE				(0x004)
-#define TPIU_SUPPORTED_TRIGGER_MODES			(0x100)
-#define TPIU_TRIGGER_COUNTER_VALUE			(0x104)
-#define TPIU_TRIGGER_MULTIPLIER				(0x108)
-#define TPIU_SUPPORTED_TEST_PATTERNM			(0x200)
-#define TPIU_CURRENT_TEST_PATTERNM			(0x204)
-#define TPIU_TEST_PATTERN_REPEAT_COUNTER		(0x208)
-#define TPIU_FORMATTER_AND_FLUSH_STATUS			(0x300)
-#define TPIU_FORMATTER_AND_FLUSH_CONTROL		(0x304)
-#define TPIU_FORMATTER_SYNCHRONIZATION_COUNTER		(0x308)
-#define TPIU_EXTCTL_IN_PORT				(0x400)
-#define TPIU_EXTCTL_OUT_PORT				(0x404)
+#define TPIU_SUPP_PORTSZ				(0x000)
+#define TPIU_CURR_PORTSZ				(0x004)
+#define TPIU_SUPP_TRIGMODES				(0x100)
+#define TPIU_TRIG_CNTRVAL				(0x104)
+#define TPIU_TRIG_MULT					(0x108)
+#define TPIU_SUPP_TESTPATM				(0x200)
+#define TPIU_CURR_TESTPATM				(0x204)
+#define TPIU_TEST_PATREPCNTR				(0x208)
+#define TPIU_FFSR					(0x300)
+#define TPIU_FFCR					(0x304)
+#define TPIU_FSYNC_CNTR					(0x308)
+#define TPIU_EXTCTL_INPORT				(0x400)
+#define TPIU_EXTCTL_OUTPORT				(0x404)
 #define TPIU_ITTRFLINACK				(0xEE4)
 #define TPIU_ITTRFLIN					(0xEE8)
 #define TPIU_ITATBDATA0					(0xEEC)
@@ -67,8 +67,8 @@
 {
 	TPIU_UNLOCK();
 
-	tpiu_writel(tpiu, 0x3000, TPIU_FORMATTER_AND_FLUSH_CONTROL);
-	tpiu_writel(tpiu, 0x3040, TPIU_FORMATTER_AND_FLUSH_CONTROL);
+	tpiu_writel(tpiu, 0x3000, TPIU_FFCR);
+	tpiu_writel(tpiu, 0x3040, TPIU_FFCR);
 
 	TPIU_LOCK();
 }
@@ -77,7 +77,7 @@
 {
 	__tpiu_disable();
 	tpiu.enabled = false;
-	dev_info(tpiu.dev, "tpiu disabled\n");
+	dev_info(tpiu.dev, "TPIU disabled\n");
 }
 
 static int __devinit tpiu_probe(struct platform_device *pdev)
@@ -99,14 +99,16 @@
 
 	tpiu.dev = &pdev->dev;
 
+	dev_info(tpiu.dev, "TPIU initialized\n");
 	return 0;
 
 err_ioremap:
 err_res:
+	dev_err(tpiu.dev, "TPIU init failed\n");
 	return ret;
 }
 
-static int tpiu_remove(struct platform_device *pdev)
+static int __devexit tpiu_remove(struct platform_device *pdev)
 {
 	if (tpiu.enabled)
 		tpiu_disable();
@@ -117,18 +119,23 @@
 
 static struct platform_driver tpiu_driver = {
 	.probe          = tpiu_probe,
-	.remove         = tpiu_remove,
+	.remove         = __devexit_p(tpiu_remove),
 	.driver         = {
 		.name   = "msm_tpiu",
 	},
 };
 
-int __init tpiu_init(void)
+static int __init tpiu_init(void)
 {
 	return platform_driver_register(&tpiu_driver);
 }
+module_init(tpiu_init);
 
-void tpiu_exit(void)
+static void __exit tpiu_exit(void)
 {
 	platform_driver_unregister(&tpiu_driver);
 }
+module_exit(tpiu_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
diff --git a/arch/arm/mach-msm/qdss.c b/arch/arm/mach-msm/qdss.c
index 55d14cd..cfe65ad 100644
--- a/arch/arm/mach-msm/qdss.c
+++ b/arch/arm/mach-msm/qdss.c
@@ -18,10 +18,13 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/export.h>
 #include <mach/rpm.h>
 
 #include "rpm_resources.h"
-#include "qdss.h"
+#include "qdss-priv.h"
+
+#define MAX_STR_LEN	(65535)
 
 enum {
 	QDSS_CLK_OFF,
@@ -29,71 +32,355 @@
 	QDSS_CLK_ON_HSDBG,
 };
 
+/*
+ * Exclusion rules for structure fields.
+ *
+ * S: qdss.sources_mutex protected.
+ * I: qdss.sink_mutex protected.
+ * C: qdss.clk_mutex protected.
+ */
+struct qdss_ctx {
+	struct kobject			*modulekobj;
+	struct msm_qdss_platform_data	*pdata;
+	struct list_head		sources;	/* S: sources list */
+	struct mutex			sources_mutex;
+	uint8_t				sink_count;	/* I: sink count */
+	struct mutex			sink_mutex;
+	uint8_t				max_clk;
+	uint8_t				clk_count;	/* C: clk count */
+	struct mutex			clk_mutex;
+};
 
-int qdss_clk_enable(void)
+static struct qdss_ctx qdss;
+
+/**
+ * qdss_get - get the qdss source handle
+ * @name: name of the qdss source
+ *
+ * Searches the sources list to get the qdss source handle for this source.
+ *
+ * CONTEXT:
+ * Typically called from init or probe functions
+ *
+ * RETURNS:
+ * pointer to struct qdss_source on success, %NULL on failure
+ */
+struct qdss_source *qdss_get(const char *name)
+{
+	struct qdss_source *src, *source = NULL;
+
+	mutex_lock(&qdss.sources_mutex);
+	list_for_each_entry(src, &qdss.sources, link) {
+		if (src->name) {
+			if (strncmp(src->name, name, MAX_STR_LEN))
+				continue;
+			source = src;
+			break;
+		}
+	}
+	mutex_unlock(&qdss.sources_mutex);
+
+	return source ? source : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(qdss_get);
+
+/**
+ * qdss_put - release the qdss source handle
+ * @name: name of the qdss source
+ *
+ * CONTEXT:
+ * Typically called from driver remove or exit functions
+ */
+void qdss_put(struct qdss_source *src)
+{
+}
+EXPORT_SYMBOL(qdss_put);
+
+/**
+ * qdss_enable - enable qdss for the source
+ * @src: handle for the source making the call
+ *
+ * Enables qdss block (relevant funnel ports and sink) if not already
+ * enabled, otherwise increments the reference count
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ *
+ * RETURNS:
+ * 0 on success, non-zero on failure
+ */
+int qdss_enable(struct qdss_source *src)
 {
 	int ret;
 
-	struct msm_rpm_iv_pair iv;
-	iv.id = MSM_RPM_ID_QDSS_CLK;
-	iv.value = QDSS_CLK_ON_DBG;
-	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
-	if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
-		goto err_clk;
+	if (!src)
+		return -EINVAL;
 
+	ret = qdss_clk_enable();
+	if (ret)
+		goto err;
+
+	if ((qdss.pdata)->afamily) {
+		mutex_lock(&qdss.sink_mutex);
+		if (qdss.sink_count == 0) {
+			etb_disable();
+			tpiu_disable();
+			/* enable ETB first to avoid losing any trace data */
+			etb_enable();
+		}
+		qdss.sink_count++;
+		mutex_unlock(&qdss.sink_mutex);
+	}
+
+	funnel_enable(0x0, src->fport_mask);
 	return 0;
-
-err_clk:
+err:
 	return ret;
 }
+EXPORT_SYMBOL(qdss_enable);
 
+/**
+ * qdss_disable - disable qdss for the source
+ * @src: handle for the source making the call
+ *
+ * Disables qdss block (relevant funnel ports and sink) if the reference count
+ * is one, otherwise decrements the reference count
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ */
+void qdss_disable(struct qdss_source *src)
+{
+	if (!src)
+		return;
+
+	if ((qdss.pdata)->afamily) {
+		mutex_lock(&qdss.sink_mutex);
+		if (WARN(qdss.sink_count == 0, "qdss is unbalanced\n"))
+			goto out;
+		if (qdss.sink_count == 1) {
+			etb_dump();
+			etb_disable();
+		}
+		qdss.sink_count--;
+		mutex_unlock(&qdss.sink_mutex);
+	}
+
+	funnel_disable(0x0, src->fport_mask);
+	qdss_clk_disable();
+	return;
+out:
+	mutex_unlock(&qdss.sink_mutex);
+}
+EXPORT_SYMBOL(qdss_disable);
+
+/**
+ * qdss_clk_enable - enable qdss clocks
+ *
+ * Enables qdss clocks via RPM if they aren't already enabled, otherwise
+ * increments the reference count.
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ *
+ * RETURNS:
+ * 0 on success, non-zero on failure
+ */
+int qdss_clk_enable(void)
+{
+	int ret;
+	struct msm_rpm_iv_pair iv;
+
+	mutex_lock(&qdss.clk_mutex);
+	if (qdss.clk_count == 0) {
+		iv.id = MSM_RPM_ID_QDSS_CLK;
+		if (qdss.max_clk)
+			iv.value = QDSS_CLK_ON_HSDBG;
+		else
+			iv.value = QDSS_CLK_ON_DBG;
+		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
+		if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
+			goto err_clk;
+	}
+	qdss.clk_count++;
+	mutex_unlock(&qdss.clk_mutex);
+	return 0;
+err_clk:
+	mutex_unlock(&qdss.clk_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(qdss_clk_enable);
+
+/**
+ * qdss_clk_disable - disable qdss clocks
+ *
+ * Disables qdss clocks via RPM if the reference count is one, otherwise
+ * decrements the reference count.
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ */
 void qdss_clk_disable(void)
 {
 	int ret;
 	struct msm_rpm_iv_pair iv;
 
-	iv.id = MSM_RPM_ID_QDSS_CLK;
-	iv.value = QDSS_CLK_OFF;
-	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
-	WARN(ret, "qdss clks not disabled (%d)\n", ret);
+	mutex_lock(&qdss.clk_mutex);
+	if (WARN(qdss.clk_count == 0, "qdss clks are unbalanced\n"))
+		goto out;
+	if (qdss.clk_count == 1) {
+		iv.id = MSM_RPM_ID_QDSS_CLK;
+		iv.value = QDSS_CLK_OFF;
+		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
+		WARN(ret, "qdss clks not disabled (%d)\n", ret);
+	}
+	qdss.clk_count--;
+out:
+	mutex_unlock(&qdss.clk_mutex);
+}
+EXPORT_SYMBOL(qdss_clk_disable);
+
+struct kobject *qdss_get_modulekobj(void)
+{
+	return qdss.modulekobj;
 }
 
-static int __init qdss_init(void)
+#define QDSS_ATTR(name)						\
+static struct kobj_attribute name##_attr =				\
+		__ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
+
+static ssize_t max_clk_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	qdss.max_clk = val;
+	return n;
+}
+static ssize_t max_clk_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = qdss.max_clk;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+QDSS_ATTR(max_clk);
+
+static void __init qdss_add_sources(struct qdss_source *srcs, size_t num)
+{
+	mutex_lock(&qdss.sources_mutex);
+	while (num--) {
+		list_add_tail(&srcs->link, &qdss.sources);
+		srcs++;
+	}
+	mutex_unlock(&qdss.sources_mutex);
+}
+
+static int __init qdss_sysfs_init(void)
 {
 	int ret;
 
-	ret = etb_init();
-	if (ret)
-		goto err_etb;
-	ret = tpiu_init();
-	if (ret)
-		goto err_tpiu;
-	ret = funnel_init();
-	if (ret)
-		goto err_funnel;
-	ret = ptm_init();
-	if (ret)
-		goto err_ptm;
+	qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!qdss.modulekobj) {
+		pr_err("failed to find QDSS sysfs module kobject\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
+	if (ret) {
+		pr_err("failed to create QDSS sysfs max_clk attribute\n");
+		goto err;
+	}
 
 	return 0;
-
-err_ptm:
-	funnel_exit();
-err_funnel:
-	tpiu_exit();
-err_tpiu:
-	etb_exit();
-err_etb:
+err:
 	return ret;
 }
-module_init(qdss_init);
+
+static void __exit qdss_sysfs_exit(void)
+{
+	sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
+}
+
+static int __devinit qdss_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct qdss_source *src_table;
+	size_t num_srcs;
+
+	mutex_init(&qdss.sources_mutex);
+	mutex_init(&qdss.clk_mutex);
+	mutex_init(&qdss.sink_mutex);
+
+	if (pdev->dev.platform_data == NULL) {
+		pr_err("%s: platform data is NULL\n", __func__);
+		ret = -ENODEV;
+		goto err_pdata;
+	}
+	qdss.pdata = pdev->dev.platform_data;
+
+	INIT_LIST_HEAD(&qdss.sources);
+	src_table = (qdss.pdata)->src_table;
+	num_srcs = (qdss.pdata)->size;
+	qdss_add_sources(src_table, num_srcs);
+
+	pr_info("QDSS arch initialized\n");
+	return 0;
+err_pdata:
+	mutex_destroy(&qdss.sink_mutex);
+	mutex_destroy(&qdss.clk_mutex);
+	mutex_destroy(&qdss.sources_mutex);
+	pr_err("QDSS init failed\n");
+	return ret;
+}
+
+static int __devexit qdss_remove(struct platform_device *pdev)
+{
+	qdss_sysfs_exit();
+	mutex_destroy(&qdss.sink_mutex);
+	mutex_destroy(&qdss.clk_mutex);
+	mutex_destroy(&qdss.sources_mutex);
+
+	return 0;
+}
+
+static struct platform_driver qdss_driver = {
+	.probe          = qdss_probe,
+	.remove         = __devexit_p(qdss_remove),
+	.driver         = {
+		.name   = "msm_qdss",
+	},
+};
+
+static int __init qdss_init(void)
+{
+	return platform_driver_register(&qdss_driver);
+}
+arch_initcall(qdss_init);
+
+static int __init qdss_module_init(void)
+{
+	int ret;
+
+	ret = qdss_sysfs_init();
+	if (ret)
+		goto err_sysfs;
+
+	pr_info("QDSS module initialized\n");
+	return 0;
+err_sysfs:
+	return ret;
+}
+module_init(qdss_module_init);
 
 static void __exit qdss_exit(void)
 {
-	ptm_exit();
-	funnel_exit();
-	tpiu_exit();
-	etb_exit();
+	platform_driver_unregister(&qdss_driver);
 }
 module_exit(qdss_exit);
 
diff --git a/arch/arm/mach-msm/rpc_hsusb.c b/arch/arm/mach-msm/rpc_hsusb.c
index 635ef31..52a1001 100644
--- a/arch/arm/mach-msm/rpc_hsusb.c
+++ b/arch/arm/mach-msm/rpc_hsusb.c
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-msm/rpc_hsusb.c
  *
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -621,7 +621,7 @@
 }
 
 
-#ifdef CONFIG_USB_GADGET_MSM_72K
+#ifdef CONFIG_USB_MSM_72K
 /* charger api wrappers */
 int hsusb_chg_init(int connect)
 {
diff --git a/arch/arm/mach-msm/rpm-regulator-8930.c b/arch/arm/mach-msm/rpm-regulator-8930.c
index 22595ec..f396fed 100644
--- a/arch/arm/mach-msm/rpm-regulator-8930.c
+++ b/arch/arm/mach-msm/rpm-regulator-8930.c
@@ -50,6 +50,11 @@
 	.hpm		= REQUEST_MEMBER(0, 0x00000C00, 10),
 };
 
+static struct rpm_vreg_parts corner_parts = {
+	.request_len	= 1,
+	.uV		= REQUEST_MEMBER(0, 0x00000003,  0),
+};
+
 /* Physically available PMIC regulator voltage setpoint ranges */
 static struct vreg_range pldo_ranges[] = {
 	VOLTAGE_RANGE( 750000, 1487500, 12500),
@@ -78,11 +83,16 @@
 	VOLTAGE_RANGE(1500000, 3300000, 50000),
 };
 
+static struct vreg_range corner_ranges[] = {
+	VOLTAGE_RANGE(RPM_VREG_CORNER_NONE, RPM_VREG_CORNER_HIGH, 1),
+};
+
 static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
 static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
 static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
 static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
 static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
+static struct vreg_set_points corner_set_points = SET_POINTS(corner_ranges);
 
 static struct vreg_set_points *all_set_points[] = {
 	&pldo_set_points,
@@ -90,6 +100,7 @@
 	&nldo1200_set_points,
 	&smps_set_points,
 	&ftsmps_set_points,
+	&corner_set_points,
 };
 
 #define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
@@ -135,6 +146,19 @@
 		.rdesc_pc.name	 = _name_pc, \
 	}
 
+#define CORNER(_id, _rpm_id, _name, _ranges) \
+	[RPM_VREG_ID_PM8038_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_CORNER, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &corner_parts, \
+		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.rdesc.name	 = _name, \
+	}
+
 static struct vreg vregs[] = {
 	LDO(L1,   "8038_l1",   NULL,          nldo1200, LDO_1200),
 	LDO(L2,   "8038_l2",   "8038_l2_pc",  nldo,     LDO_150),
@@ -171,6 +195,8 @@
 
 	LVS(LVS1, "8038_lvs1", "8038_lvs1_pc"),
 	LVS(LVS2, "8038_lvs2", "8038_lvs2_pc"),
+
+	CORNER(VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
 };
 
 static const char *pin_func_label[] = {
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index 88b52ea..d4f9a8a 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -24,7 +24,8 @@
 	RPM_REGULATOR_TYPE_SMPS,
 	RPM_REGULATOR_TYPE_VS,
 	RPM_REGULATOR_TYPE_NCP,
-	RPM_REGULATOR_TYPE_MAX = RPM_REGULATOR_TYPE_NCP,
+	RPM_REGULATOR_TYPE_CORNER,
+	RPM_REGULATOR_TYPE_MAX = RPM_REGULATOR_TYPE_CORNER,
 };
 
 struct request_member {
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index ed366ae..c708df5 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -90,6 +90,14 @@
 	[RPM_VREG_FREQ_1p28]		= "1.28",
 	[RPM_VREG_FREQ_1p20]		= "1.20",
 };
+
+static const char *label_corner[] = {
+	[RPM_VREG_CORNER_NONE]		= "NONE",
+	[RPM_VREG_CORNER_LOW]		= "LOW",
+	[RPM_VREG_CORNER_NOMINAL]	= "NOM",
+	[RPM_VREG_CORNER_HIGH]		= "HIGH",
+};
+
 /*
  * This is used when voting for LPM or HPM by subtracting or adding to the
  * hpm_min_load of a regulator.  It has units of uA.
@@ -117,7 +125,7 @@
 	int uV, mV, fm, pm, pc, pf, pd, freq, state, i;
 	const char *pf_label = "", *fm_label = "", *pc_total = "";
 	const char *pc_en[4] = {"", "", "", ""};
-	const char *pm_label = "", *freq_label = "";
+	const char *pm_label = "", *freq_label = "", *corner_label = "";
 	char buf[DEBUG_PRINT_BUFFER_SIZE];
 	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
 	int pos = 0;
@@ -169,7 +177,7 @@
 			vreg->rdesc.name,
 			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'));
 
-	if (USES_PART(vreg, uV))
+	if (USES_PART(vreg, uV) && vreg->type != RPM_REGULATOR_TYPE_CORNER)
 		pos += scnprintf(buf + pos, buflen - pos, ", v=%7d uV", uV);
 	if (USES_PART(vreg, mV))
 		pos += scnprintf(buf + pos, buflen - pos, ", v=%4d mV", mV);
@@ -215,6 +223,12 @@
 	if (USES_PART(vreg, hpm))
 		pos += scnprintf(buf + pos, buflen - pos,
 				 ", hpm=%d", GET_PART(vreg, hpm));
+	if (USES_PART(vreg, uV) && vreg->type == RPM_REGULATOR_TYPE_CORNER) {
+		if (uV >= 0 && uV < (ARRAY_SIZE(label_corner) - 1))
+			corner_label = label_corner[uV+1];
+		pos += scnprintf(buf + pos, buflen - pos, ", corner=%s (%d)",
+			corner_label, uV);
+	}
 
 	pos += scnprintf(buf + pos, buflen - pos, "; req[0]={%d, 0x%08X}",
 			 vreg->req[0].id, vreg->req[0].value);
@@ -313,6 +327,12 @@
 	vreg->req[1].value &= ~mask1;
 	vreg->req[1].value |= val1 & mask1;
 
+	/* Set the force mode field based on which set is being requested. */
+	if (set == MSM_RPM_CTX_SET_0)
+		SET_PART(vreg, fm, vreg->pdata.force_mode);
+	else
+		SET_PART(vreg, fm, vreg->pdata.sleep_set_force_mode);
+
 	if (update_voltage)
 		min_uV_vote[voter] = voltage_from_req(vreg);
 
@@ -507,6 +527,16 @@
 		}
 	}
 
+	if (vreg->type == RPM_REGULATOR_TYPE_CORNER) {
+		/*
+		 * Translate from enum values which work as inputs in the
+		 * rpm_vreg_set_voltage function to the actual corner values
+		 * sent to the RPM.
+		 */
+		if (uV > 0)
+			uV -= RPM_VREG_CORNER_NONE;
+	}
+
 	if (vreg->part->uV.mask) {
 		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
 		mask[vreg->part->uV.word] = vreg->part->uV.mask;
@@ -695,6 +725,7 @@
 	switch (vreg->type) {
 	case RPM_REGULATOR_TYPE_LDO:
 	case RPM_REGULATOR_TYPE_SMPS:
+	case RPM_REGULATOR_TYPE_CORNER:
 		/* Enable by setting a voltage. */
 		if (vreg->part->uV.mask) {
 			val[vreg->part->uV.word]
@@ -717,7 +748,7 @@
 	}
 }
 
-static int vreg_enable(struct regulator_dev *rdev)
+static int rpm_vreg_enable(struct regulator_dev *rdev)
 {
 	struct vreg *vreg = rdev_get_drvdata(rdev);
 	unsigned int mask[2] = {0}, val[2] = {0};
@@ -746,6 +777,7 @@
 	switch (vreg->type) {
 	case RPM_REGULATOR_TYPE_LDO:
 	case RPM_REGULATOR_TYPE_SMPS:
+	case RPM_REGULATOR_TYPE_CORNER:
 		/* Disable by setting a voltage of 0 uV. */
 		if (vreg->part->uV.mask) {
 			val[vreg->part->uV.word] |= 0 << vreg->part->uV.shift;
@@ -765,7 +797,7 @@
 	}
 }
 
-static int vreg_disable(struct regulator_dev *rdev)
+static int rpm_vreg_disable(struct regulator_dev *rdev)
 {
 	struct vreg *vreg = rdev_get_drvdata(rdev);
 	unsigned int mask[2] = {0}, val[2] = {0};
@@ -838,6 +870,15 @@
 		return -EINVAL;
 	}
 
+	if (vreg->type == RPM_REGULATOR_TYPE_CORNER) {
+		/*
+		 * Translate from enum values which work as inputs in the
+		 * regulator_set_voltage function to the actual corner values
+		 * sent to the RPM.
+		 */
+		uV -= RPM_VREG_CORNER_NONE;
+	}
+
 	if (vreg->part->uV.mask) {
 		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
 		mask[vreg->part->uV.word] = vreg->part->uV.mask;
@@ -1111,8 +1152,8 @@
 
 /* Real regulator operations. */
 static struct regulator_ops ldo_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
 	.is_enabled		= vreg_is_enabled,
 	.set_voltage		= vreg_set_voltage,
 	.get_voltage		= vreg_get_voltage,
@@ -1124,8 +1165,8 @@
 };
 
 static struct regulator_ops smps_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
 	.is_enabled		= vreg_is_enabled,
 	.set_voltage		= vreg_set_voltage,
 	.get_voltage		= vreg_get_voltage,
@@ -1137,15 +1178,25 @@
 };
 
 static struct regulator_ops switch_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
 	.is_enabled		= vreg_is_enabled,
 	.enable_time		= vreg_enable_time,
 };
 
 static struct regulator_ops ncp_ops = {
-	.enable			= vreg_enable,
-	.disable		= vreg_disable,
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.enable_time		= vreg_enable_time,
+};
+
+static struct regulator_ops corner_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
 	.is_enabled		= vreg_is_enabled,
 	.set_voltage		= vreg_set_voltage,
 	.get_voltage		= vreg_get_voltage,
@@ -1165,6 +1216,7 @@
 	[RPM_REGULATOR_TYPE_SMPS]	= &smps_ops,
 	[RPM_REGULATOR_TYPE_VS]		= &switch_ops,
 	[RPM_REGULATOR_TYPE_NCP]	= &ncp_ops,
+	[RPM_REGULATOR_TYPE_CORNER]	= &corner_ops,
 };
 
 static int __devinit
@@ -1278,7 +1330,7 @@
 	if (rc)
 		goto bail;
 
-	rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg);
+	rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg, NULL);
 	if (IS_ERR(rdev)) {
 		rc = PTR_ERR(rdev);
 		pr_err("regulator_register failed: %s, rc=%d\n",
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
index 05b2953..b0fa3d2 100644
--- a/arch/arm/mach-msm/rpm.c
+++ b/arch/arm/mach-msm/rpm.c
@@ -239,6 +239,19 @@
 	return 2;
 }
 
+static void msm_rpm_err_fatal(void)
+{
+	/* Tell RPM that we're handling the interrupt */
+	__raw_writel(0x1, msm_rpm_data.ipc_rpm_reg);
+	panic("RPM error fataled");
+}
+
+static irqreturn_t msm_rpm_err_interrupt(int irq, void *dev_id)
+{
+	msm_rpm_err_fatal();
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t msm_rpm_ack_interrupt(int irq, void *dev_id)
 {
 	unsigned long flags;
@@ -267,6 +280,9 @@
 				msm_rpm_request) {
 			if (allow_async_completion)
 				spin_unlock(&msm_rpm_irq_lock);
+			if (gic_is_spi_pending(msm_rpm_data.irq_err))
+				msm_rpm_err_fatal();
+			gic_clear_spi_pending(msm_rpm_data.irq_err);
 			udelay(1);
 			if (allow_async_completion)
 				spin_lock(&msm_rpm_irq_lock);
@@ -355,7 +371,7 @@
 	uint32_t ctx_mask = msm_rpm_get_ctx_mask(ctx);
 	uint32_t ctx_mask_ack = 0;
 	uint32_t sel_masks_ack[SEL_MASK_SIZE];
-	struct irq_chip *irq_chip = NULL;
+	struct irq_chip *irq_chip, *err_chip;
 	int i;
 
 	msm_rpm_request_poll_mode.req = req;
@@ -371,6 +387,13 @@
 		return -ENOSPC;
 	}
 	irq_chip->irq_mask(irq_get_irq_data(irq));
+	err_chip = irq_get_chip(msm_rpm_data.irq_err);
+	if (!err_chip) {
+		irq_chip->irq_unmask(irq_get_irq_data(irq));
+		spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+		return -ENOSPC;
+	}
+	err_chip->irq_mask(irq_get_irq_data(msm_rpm_data.irq_err));
 
 	if (msm_rpm_request) {
 		msm_rpm_busy_wait_for_request_completion(true);
@@ -398,6 +421,7 @@
 	msm_rpm_busy_wait_for_request_completion(false);
 	BUG_ON(msm_rpm_request);
 
+	err_chip->irq_unmask(irq_get_irq_data(msm_rpm_data.irq_err));
 	irq_chip->irq_unmask(irq_get_irq_data(irq));
 	spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
 
@@ -413,7 +437,6 @@
  *
  * Return value:
  *   0: success
- *   -EINTR: interrupted
  *   -EINVAL: invalid <ctx> or invalid id in <req> array
  *   -ENOSPC: request rejected
  *   -ENODEV: RPM driver not initialized
@@ -440,10 +463,7 @@
 		rc = msm_rpm_set_exclusive_noirq(ctx, sel_masks, req, count);
 		spin_unlock_irqrestore(&msm_rpm_lock, flags);
 	} else {
-		rc = mutex_lock_interruptible(&msm_rpm_mutex);
-		if (rc)
-			goto set_common_exit;
-
+		mutex_lock(&msm_rpm_mutex);
 		rc = msm_rpm_set_exclusive(ctx, sel_masks, req, count);
 		mutex_unlock(&msm_rpm_mutex);
 	}
@@ -455,7 +475,6 @@
 /*
  * Return value:
  *   0: success
- *   -EINTR: interrupted
  *   -EINVAL: invalid <ctx> or invalid id in <req> array
  *   -ENODEV: RPM driver not initialized.
  */
@@ -494,10 +513,7 @@
 		spin_unlock_irqrestore(&msm_rpm_lock, flags);
 		BUG_ON(rc);
 	} else {
-		rc = mutex_lock_interruptible(&msm_rpm_mutex);
-		if (rc)
-			goto clear_common_exit;
-
+		mutex_lock(&msm_rpm_mutex);
 		rc = msm_rpm_set_exclusive(ctx, sel_masks, r, ARRAY_SIZE(r));
 		mutex_unlock(&msm_rpm_mutex);
 		BUG_ON(rc);
@@ -659,7 +675,6 @@
  *
  * Return value:
  *   0: success
- *   -EINTR: interrupted
  *   -EINVAL: invalid <ctx> or invalid id in <req> array
  *   -ENOSPC: request rejected
  *   -ENODEV: RPM driver not initialized
@@ -700,7 +715,6 @@
  *
  * Return value:
  *   0: success
- *   -EINTR: interrupted
  *   -EINVAL: invalid <ctx> or invalid id in <req> array
  */
 int msm_rpm_clear(int ctx, struct msm_rpm_iv_pair *req, int count)
@@ -745,7 +759,6 @@
  *
  * Return value:
  *   0: success
- *   -EINTR: interrupted
  *   -EINVAL: invalid id in <req> array
  *   -ENODEV: RPM driver not initialized
  */
@@ -763,9 +776,7 @@
 	if (rc)
 		goto register_notification_exit;
 
-	rc = mutex_lock_interruptible(&msm_rpm_mutex);
-	if (rc)
-		goto register_notification_exit;
+	mutex_lock(&msm_rpm_mutex);
 
 	if (!msm_rpm_init_notif_done) {
 		msm_rpm_initialize_notification();
@@ -799,7 +810,6 @@
  *
  * Return value:
  *   0: success
- *   -EINTR: interrupted
  *   -ENODEV: RPM driver not initialized
  */
 int msm_rpm_unregister_notification(struct msm_rpm_notification *n)
@@ -807,13 +817,10 @@
 	unsigned long flags;
 	unsigned int ctx;
 	struct msm_rpm_notif_config cfg;
-	int rc;
+	int rc = 0;
 	int i;
 
-	rc = mutex_lock_interruptible(&msm_rpm_mutex);
-	if (rc)
-		goto unregister_notification_exit;
-
+	mutex_lock(&msm_rpm_mutex);
 	ctx = MSM_RPM_CTX_SET_0;
 	cfg = msm_rpm_notif_cfgs[ctx];
 
@@ -830,7 +837,6 @@
 	msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg);
 	mutex_unlock(&msm_rpm_mutex);
 
-unregister_notification_exit:
 	return rc;
 }
 EXPORT_SYMBOL(msm_rpm_unregister_notification);
@@ -983,6 +989,14 @@
 		return rc;
 	}
 
+	rc = request_irq(data->irq_err, msm_rpm_err_interrupt,
+			IRQF_TRIGGER_RISING, "rpm_err", NULL);
+	if (rc) {
+		pr_err("%s: failed to request error interrupt: %d\n",
+			__func__, rc);
+		return rc;
+	}
+
 	msm_rpm_populate_map(data);
 
 	return platform_driver_register(&msm_rpm_platform_driver);
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 546a917..6282eca 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -895,6 +895,9 @@
 		if (latency_us < level->latency_us)
 			continue;
 
+		if (sleep_us <= level->time_overhead_us)
+			continue;
+
 		if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
 					irqs_detectable, gpio_detectable))
 			continue;
diff --git a/arch/arm/mach-msm/saw-regulator.c b/arch/arm/mach-msm/saw-regulator.c
index b11b1fa..c747e5b 100644
--- a/arch/arm/mach-msm/saw-regulator.c
+++ b/arch/arm/mach-msm/saw-regulator.c
@@ -174,8 +174,8 @@
 	vreg->desc.owner = THIS_MODULE;
 	vreg->uV	 = MIN_CORE_VOLTAGE;
 
-	vreg->rdev = regulator_register(&vreg->desc, &pdev->dev, init_data,
-					vreg);
+	vreg->rdev = regulator_register(&vreg->desc, &pdev->dev,
+							init_data, vreg, NULL);
 	if (IS_ERR(vreg->rdev)) {
 		rc = PTR_ERR(vreg->rdev);
 		pr_err("regulator_register failed, rc=%d.\n", rc);
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 747b585..4096d9c 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -103,7 +103,7 @@
 		if (ret) {
 			pr_err("bandwidth request failed (%d)\n", ret);
 		} else {
-			ret = clk_enable(scm_bus_clk);
+			ret = clk_prepare_enable(scm_bus_clk);
 			if (ret)
 				pr_err("clock enable failed\n");
 		}
@@ -121,7 +121,7 @@
 	mutex_lock(&scm_pas_bw_mutex);
 	if (scm_pas_bw_count-- == 1) {
 		msm_bus_scale_client_update_request(scm_perf_client, 0);
-		clk_disable(scm_bus_clk);
+		clk_disable_unprepare(scm_bus_clk);
 	}
 	mutex_unlock(&scm_pas_bw_mutex);
 }
@@ -190,10 +190,7 @@
 
 static int __init scm_pas_init(void)
 {
-	/* TODO: Remove once bus scaling driver is in place */
-	if (!cpu_is_apq8064())
-		scm_perf_client = msm_bus_scale_register_client(
-				&scm_pas_bus_pdata);
+	scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
 	if (!scm_perf_client)
 		pr_warn("unable to register bus client\n");
 	scm_bus_clk = clk_get_sys("scm", "bus_clk");
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index 6794a88..e664414 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;
@@ -382,6 +414,19 @@
 }
 EXPORT_SYMBOL(scm_is_call_available);
 
+#define GET_FEAT_VERSION_CMD	3
+int scm_get_feat_version(u32 feat)
+{
+	if (scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD)) {
+		u32 version;
+		if (!scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &feat,
+				sizeof(feat), &version, sizeof(version)))
+			return version;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(scm_get_feat_version);
+
 static int scm_init(void)
 {
 	u32 ctr;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index bca1e0c..d00dd1a 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -32,11 +32,14 @@
 #include <linux/remote_spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/kfifo.h>
+#include <linux/wakelock.h>
+#include <linux/notifier.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
 #include <mach/subsystem_notif.h>
 #include <mach/socinfo.h>
+#include <asm/cacheflush.h>
 
 #include "smd_private.h"
 #include "proc_comm.h"
@@ -63,6 +66,7 @@
 #define SMEM_VERSION 0x000B
 #define SMD_VERSION 0x00020000
 #define SMSM_SNAPSHOT_CNT 64
+#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
 
 uint32_t SMSM_NUM_ENTRIES = 8;
 uint32_t SMSM_NUM_HOSTS = 3;
@@ -72,6 +76,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 {
@@ -81,7 +86,10 @@
 };
 
 static struct smsm_shared_info smsm_info;
-struct kfifo smsm_snapshot_fifo;
+static struct kfifo smsm_snapshot_fifo;
+static struct wake_lock smsm_snapshot_wakelock;
+static int smsm_snapshot_count;
+static DEFINE_SPINLOCK(smsm_snapshot_count_lock);
 
 struct smsm_size_info_type {
 	uint32_t num_hosts;
@@ -117,29 +125,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 +188,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;
@@ -189,13 +207,13 @@
 
 #if defined(CONFIG_ARCH_MSM7X30)
 #define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 0, MSM_GCC_BASE + 0x8))
+			(smd_write_intr(1 << 0, MSM_APCS_GCC_BASE + 0x8))
 #define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 8, MSM_GCC_BASE + 0x8))
+			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
 #define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 5, MSM_GCC_BASE + 0x8))
+			(smd_write_intr(1 << 5, MSM_APCS_GCC_BASE + 0x8))
 #define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 8, MSM_GCC_BASE + 0x8))
+			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
 #define MSM_TRIG_A2DSPS_SMD_INT
 #define MSM_TRIG_A2DSPS_SMSM_INT
 #define MSM_TRIG_A2WCNSS_SMD_INT
@@ -214,24 +232,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 +258,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
@@ -312,13 +330,16 @@
 
 static LIST_HEAD(smd_ch_list_loopback);
 static void smd_fake_irq_handler(unsigned long arg);
-static void smsm_cb_snapshot(void);
+static void smsm_cb_snapshot(uint32_t use_wakelock);
 
 static void notify_smsm_cb_clients_worker(struct work_struct *work);
 static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
 static DEFINE_MUTEX(smsm_lock);
 static struct smsm_state_info *smsm_states;
 static int spinlocks_initialized;
+static RAW_NOTIFIER_HEAD(smsm_driver_state_notifier_list);
+static DEFINE_MUTEX(smsm_driver_state_notifier_lock);
+static void smsm_driver_state_notify(uint32_t state, void *data);
 
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr)
@@ -349,33 +370,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 +414,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 +472,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)
@@ -473,7 +518,13 @@
 		notify_dsps_smsm();
 	}
 
-	smsm_cb_snapshot();
+	/*
+	 * Notify local SMSM callback clients without wakelock since this
+	 * code is used by power management during power-down/-up sequencing
+	 * on DEM-based targets.  Grabbing a wakelock in this case will
+	 * abort the power-down sequencing.
+	 */
+	smsm_cb_snapshot(0);
 }
 
 void smd_diag(void)
@@ -589,27 +640,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 {
@@ -618,6 +670,7 @@
 	struct notifier_block nb;
 };
 
+static int disable_smsm_reset_handshake;
 static struct platform_device loopback_tty_pdev = {.name = "LOOPBACK_TTY"};
 
 static LIST_HEAD(smd_ch_closed_list);
@@ -721,6 +774,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 +893,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 +1208,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 +1233,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 +1242,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 +1251,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 +1260,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;
@@ -1832,42 +1947,77 @@
 
 int smd_read(smd_channel_t *ch, void *data, int len)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->read(ch, data, len, 0);
 }
 EXPORT_SYMBOL(smd_read);
 
 int smd_read_user_buffer(smd_channel_t *ch, void *data, int len)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->read(ch, data, len, 1);
 }
 EXPORT_SYMBOL(smd_read_user_buffer);
 
 int smd_read_from_cb(smd_channel_t *ch, void *data, int len)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->read_from_cb(ch, data, len, 0);
 }
 EXPORT_SYMBOL(smd_read_from_cb);
 
 int smd_write(smd_channel_t *ch, const void *data, int len)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->pending_pkt_sz ? -EBUSY : ch->write(ch, data, len, 0);
 }
 EXPORT_SYMBOL(smd_write);
 
 int smd_write_user_buffer(smd_channel_t *ch, const void *data, int len)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->pending_pkt_sz ? -EBUSY : ch->write(ch, data, len, 1);
 }
 EXPORT_SYMBOL(smd_write_user_buffer);
 
 int smd_read_avail(smd_channel_t *ch)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->read_avail(ch);
 }
 EXPORT_SYMBOL(smd_read_avail);
 
 int smd_write_avail(smd_channel_t *ch)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->write_avail(ch);
 }
 EXPORT_SYMBOL(smd_write_avail);
@@ -1898,12 +2048,22 @@
 
 int smd_cur_packet_size(smd_channel_t *ch)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->current_packet;
 }
 EXPORT_SYMBOL(smd_cur_packet_size);
 
 int smd_tiocmget(smd_channel_t *ch)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return  (ch->recv->fDSR ? TIOCM_DSR : 0) |
 		(ch->recv->fCTS ? TIOCM_CTS : 0) |
 		(ch->recv->fCD ? TIOCM_CD : 0) |
@@ -1917,6 +2077,11 @@
 int
 smd_tiocmset_from_cb(smd_channel_t *ch, unsigned int set, unsigned int clear)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	if (set & TIOCM_DTR)
 		ch->send->fDSR = 1;
 
@@ -1941,6 +2106,11 @@
 {
 	unsigned long flags;
 
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	spin_lock_irqsave(&smd_lock, flags);
 	smd_tiocmset_from_cb(ch, set, clear);
 	spin_unlock_irqrestore(&smd_lock, flags);
@@ -2110,6 +2280,8 @@
 		pr_err("%s: SMSM state fifo alloc failed %d\n", __func__, i);
 		return i;
 	}
+	wake_lock_init(&smsm_snapshot_wakelock, WAKE_LOCK_SUSPEND,
+			"smsm_snapshot");
 
 	if (!smsm_info.state) {
 		smsm_info.state = smem_alloc2(ID_SHARED_STATE,
@@ -2146,6 +2318,7 @@
 		return i;
 
 	wmb();
+	smsm_driver_state_notify(SMSM_INIT, NULL);
 	return 0;
 }
 
@@ -2180,18 +2353,43 @@
 }
 EXPORT_SYMBOL(smsm_reset_modem_cont);
 
-static void smsm_cb_snapshot(void)
+static void smsm_cb_snapshot(uint32_t use_wakelock)
 {
 	int n;
 	uint32_t new_state;
+	unsigned long flags;
 	int ret;
 
 	ret = kfifo_avail(&smsm_snapshot_fifo);
-	if (ret < (SMSM_NUM_ENTRIES * 4)) {
+	if (ret < SMSM_SNAPSHOT_SIZE) {
 		pr_err("%s: SMSM snapshot full %d\n", __func__, ret);
 		return;
 	}
 
+	/*
+	 * To avoid a race condition with notify_smsm_cb_clients_worker, the
+	 * following sequence must be followed:
+	 *   1) increment snapshot count
+	 *   2) insert data into FIFO
+	 *
+	 *   Potentially in parallel, the worker:
+	 *   a) verifies >= 1 snapshots are in FIFO
+	 *   b) processes snapshot
+	 *   c) decrements reference count
+	 *
+	 *   This order ensures that 1 will always occur before abc.
+	 */
+	if (use_wakelock) {
+		spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
+		if (smsm_snapshot_count == 0) {
+			SMx_POWER_INFO("SMSM snapshot wake lock\n");
+			wake_lock(&smsm_snapshot_wakelock);
+		}
+		++smsm_snapshot_count;
+		spin_unlock_irqrestore(&smsm_snapshot_count_lock, flags);
+	}
+
+	/* queue state entries */
 	for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
 		new_state = __raw_readl(SMSM_STATE_ADDR(n));
 
@@ -2199,10 +2397,35 @@
 				&new_state, sizeof(new_state));
 		if (ret != sizeof(new_state)) {
 			pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
-			return;
+			goto restore_snapshot_count;
 		}
 	}
+
+	/* queue wakelock usage flag */
+	ret = kfifo_in(&smsm_snapshot_fifo,
+			&use_wakelock, sizeof(use_wakelock));
+	if (ret != sizeof(use_wakelock)) {
+		pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+		goto restore_snapshot_count;
+	}
+
 	schedule_work(&smsm_cb_work);
+	return;
+
+restore_snapshot_count:
+	if (use_wakelock) {
+		spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
+		if (smsm_snapshot_count) {
+			--smsm_snapshot_count;
+			if (smsm_snapshot_count == 0) {
+				SMx_POWER_INFO("SMSM snapshot wake unlock\n");
+				wake_unlock(&smsm_snapshot_wakelock);
+			}
+		} else {
+			pr_err("%s: invalid snapshot count\n", __func__);
+		}
+		spin_unlock_irqrestore(&smsm_snapshot_count_lock, flags);
+	}
 }
 
 static irqreturn_t smsm_irq_handler(int irq, void *data)
@@ -2221,7 +2444,7 @@
 		}
 
 		spin_lock_irqsave(&smem_lock, flags);
-		smsm_cb_snapshot();
+		smsm_cb_snapshot(1);
 		spin_unlock_irqrestore(&smem_lock, flags);
 		return IRQ_HANDLED;
 	}
@@ -2240,7 +2463,7 @@
 			/* If we get an interrupt and the apps SMSM_RESET
 			   bit is already set, the modem is acking the
 			   app's reset ack. */
-			if (!cpu_is_msm8960() && !cpu_is_msm8930())
+			if (!disable_smsm_reset_handshake)
 				apps &= ~SMSM_RESET;
 			/* Issue a fake irq to handle any
 			 * smd state changes during reset
@@ -2251,10 +2474,12 @@
 			modem_queue_start_reset_notify();
 
 		} else if (modm & SMSM_RESET) {
-			if (!cpu_is_msm8960() && !cpu_is_msm8930())
-				apps |= SMSM_RESET;
-
 			pr_err("\nSMSM: Modem SMSM state changed to SMSM_RESET.");
+			if (!disable_smsm_reset_handshake) {
+				apps |= SMSM_RESET;
+				flush_cache_all();
+				outer_flush_all();
+			}
 			modem_queue_start_reset_notify();
 
 		} else if (modm & SMSM_INIT) {
@@ -2280,12 +2505,40 @@
 			notify_other_smsm(SMSM_APPS_STATE, (old_apps ^ apps));
 		}
 
-		smsm_cb_snapshot();
+		smsm_cb_snapshot(1);
 	}
 	spin_unlock_irqrestore(&smem_lock, flags);
 	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)
 {
@@ -2395,13 +2648,14 @@
 	int n;
 	uint32_t new_state;
 	uint32_t state_changes;
+	uint32_t use_wakelock;
 	int ret;
-	int snapshot_size = SMSM_NUM_ENTRIES * sizeof(uint32_t);
+	unsigned long flags;
 
 	if (!smd_initialized)
 		return;
 
-	while (kfifo_len(&smsm_snapshot_fifo) >= snapshot_size) {
+	while (kfifo_len(&smsm_snapshot_fifo) >= SMSM_SNAPSHOT_SIZE) {
 		mutex_lock(&smsm_lock);
 		for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
 			state_info = &smsm_states[n];
@@ -2417,6 +2671,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) {
 
@@ -2429,6 +2686,32 @@
 			}
 		}
 		mutex_unlock(&smsm_lock);
+
+		/* read wakelock flag */
+		ret = kfifo_out(&smsm_snapshot_fifo, &use_wakelock,
+				sizeof(use_wakelock));
+		if (ret != sizeof(use_wakelock)) {
+			pr_err("%s: snapshot underflow %d\n",
+				__func__, ret);
+			return;
+		}
+
+		if (use_wakelock) {
+			spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
+			if (smsm_snapshot_count) {
+				--smsm_snapshot_count;
+				if (smsm_snapshot_count == 0) {
+					SMx_POWER_INFO("SMSM snapshot"
+						   " wake unlock\n");
+					wake_unlock(&smsm_snapshot_wakelock);
+				}
+			} else {
+				pr_err("%s: invalid snapshot count\n",
+						__func__);
+			}
+			spin_unlock_irqrestore(&smsm_snapshot_count_lock,
+					flags);
+		}
 	}
 }
 
@@ -2551,6 +2834,38 @@
 }
 EXPORT_SYMBOL(smsm_state_cb_deregister);
 
+int smsm_driver_state_notifier_register(struct notifier_block *nb)
+{
+	int ret;
+	if (!nb)
+		return -EINVAL;
+	mutex_lock(&smsm_driver_state_notifier_lock);
+	ret = raw_notifier_chain_register(&smsm_driver_state_notifier_list, nb);
+	mutex_unlock(&smsm_driver_state_notifier_lock);
+	return ret;
+}
+EXPORT_SYMBOL(smsm_driver_state_notifier_register);
+
+int smsm_driver_state_notifier_unregister(struct notifier_block *nb)
+{
+	int ret;
+	if (!nb)
+		return -EINVAL;
+	mutex_lock(&smsm_driver_state_notifier_lock);
+	ret = raw_notifier_chain_unregister(&smsm_driver_state_notifier_list,
+					    nb);
+	mutex_unlock(&smsm_driver_state_notifier_lock);
+	return ret;
+}
+EXPORT_SYMBOL(smsm_driver_state_notifier_unregister);
+
+static void smsm_driver_state_notify(uint32_t state, void *data)
+{
+	mutex_lock(&smsm_driver_state_notifier_lock);
+	raw_notifier_call_chain(&smsm_driver_state_notifier_list,
+				state, data);
+	mutex_unlock(&smsm_driver_state_notifier_lock);
+}
 
 int smd_core_init(void)
 {
@@ -2567,7 +2882,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 +2905,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 +2935,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 +2952,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 +2962,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 +2981,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;
 	}
 
@@ -2742,6 +3057,10 @@
 	num_ss = smd_platform_data->num_ss_configs;
 	smd_ss_config_list = smd_platform_data->smd_ss_configs;
 
+	if (smd_platform_data->smd_ssr_config)
+		disable_smsm_reset_handshake = smd_platform_data->
+			   smd_ssr_config->disable_smsm_reset_handshake;
+
 	for (i = 0; i < num_ss; i++) {
 		cfg = &smd_ss_config_list[i];
 
@@ -2770,6 +3089,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 63c5fef..5f835a2 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -40,7 +40,7 @@
 #ifdef CONFIG_ARCH_FSM9XXX
 #define NUM_SMD_PKT_PORTS 4
 #else
-#define NUM_SMD_PKT_PORTS 12
+#define NUM_SMD_PKT_PORTS 13
 #endif
 
 #define LOOPBACK_INX (NUM_SMD_PKT_PORTS - 1)
@@ -66,6 +66,7 @@
 
 	int blocking_write;
 	int is_open;
+	int poll_mode;
 	unsigned ch_size;
 	uint open_modem_wait;
 
@@ -74,6 +75,7 @@
 	struct completion ch_allocated;
 	struct wake_lock pa_wake_lock;		/* Packet Arrival Wake lock*/
 	struct work_struct packet_arrival_work;
+	struct spinlock pa_spinlock;
 } *smd_pkt_devp[NUM_SMD_PKT_PORTS];
 
 struct class *smd_pkt_classp;
@@ -86,24 +88,65 @@
 static int msm_smd_pkt_debug_mask;
 module_param_named(debug_mask, msm_smd_pkt_debug_mask,
 		int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+enum {
+	SMD_PKT_STATUS = 1U << 0,
+	SMD_PKT_READ = 1U << 1,
+	SMD_PKT_WRITE = 1U << 2,
+	SMD_PKT_READ_DUMP_BUFFER = 1U << 3,
+	SMD_PKT_WRITE_DUMP_BUFFER = 1U << 4,
+	SMD_PKT_POLL = 1U << 5,
+};
+
 #define DEBUG
 
 #ifdef DEBUG
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
+#define D_STATUS(x...) \
 do { \
-	if (msm_smd_pkt_debug_mask) \
-		print_hex_dump(KERN_DEBUG, prestr, \
-				DUMP_PREFIX_NONE, 16, 1, \
-				buf, cnt, 1); \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
+		pr_info("Status: "x); \
+} while (0)
+
+#define D_READ(x...) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_READ) \
+		pr_info("Read: "x); \
+} while (0)
+
+#define D_WRITE(x...) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE) \
+		pr_info("Write: "x); \
+} while (0)
+
+#define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_READ_DUMP_BUFFER) \
+		print_hex_dump(KERN_INFO, prestr, \
+			       DUMP_PREFIX_NONE, 16, 1, \
+			       buf, cnt, 1); \
+} while (0)
+
+#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE_DUMP_BUFFER) \
+		print_hex_dump(KERN_INFO, prestr, \
+			       DUMP_PREFIX_NONE, 16, 1, \
+			       buf, cnt, 1); \
+} while (0)
+
+#define D_POLL(x...) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
+		pr_info("Poll: "x); \
 } while (0)
 #else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#endif
-
-#ifdef DEBUG
-#define D(x...) if (msm_smd_pkt_debug_mask) printk(x)
-#else
-#define D(x...) do {} while (0)
+#define D_STATUS(x...) do {} while (0)
+#define D_READ(x...) do {} while (0)
+#define D_WRITE(x...) do {} while (0)
+#define D_READ_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D_POLL(x...) do {} while (0)
 #endif
 
 static ssize_t open_timeout_store(struct device *d,
@@ -169,6 +212,7 @@
 	wake_up(&smd_pkt_devp->ch_read_wait_queue);
 	wake_up(&smd_pkt_devp->ch_write_wait_queue);
 	wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
+	D_STATUS("%s smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
 }
 
 static void loopback_probe_worker(struct work_struct *work)
@@ -193,9 +237,12 @@
 	smd_pkt_devp = container_of(work, struct smd_pkt_dev,
 				    packet_arrival_work);
 	mutex_lock(&smd_pkt_devp->ch_lock);
-	if (smd_pkt_devp->ch)
+	if (smd_pkt_devp->ch) {
+		D_READ("%s locking smd_pkt_dev id:%d wakelock\n",
+			__func__, smd_pkt_devp->i);
 		wake_lock_timeout(&smd_pkt_devp->pa_wake_lock,
 				  WAKELOCK_TIMEOUT);
+	}
 	mutex_unlock(&smd_pkt_devp->ch_lock);
 }
 
@@ -211,15 +258,20 @@
 
 	switch (cmd) {
 	case TIOCMGET:
+		D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n",
+			 __func__, smd_pkt_devp->i);
 		ret = smd_tiocmget(smd_pkt_devp->ch);
 		break;
 	case TIOCMSET:
+		D_STATUS("%s TIOCSET command on smd_pkt_dev id:%d\n",
+			 __func__, smd_pkt_devp->i);
 		ret = smd_tiocmset(smd_pkt_devp->ch, arg, ~arg);
 		break;
 	case SMD_PKT_IOCTL_BLOCKING_WRITE:
 		ret = get_user(smd_pkt_devp->blocking_write, (int *)arg);
 		break;
 	default:
+		pr_err("%s: Unrecognized ioctl command %d\n", __func__, cmd);
 		ret = -1;
 	}
 
@@ -236,19 +288,29 @@
 	int pkt_size;
 	struct smd_pkt_dev *smd_pkt_devp;
 	struct smd_channel *chl;
-
-	D(KERN_ERR "%s: read %i bytes\n",
-	  __func__, count);
+	unsigned long flags;
 
 	smd_pkt_devp = file->private_data;
 
-	if (!smd_pkt_devp || !smd_pkt_devp->ch)
+	if (!smd_pkt_devp) {
+		pr_err("%s on NULL smd_pkt_dev\n", __func__);
 		return -EINVAL;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return -EINVAL;
+	}
 
 	if (smd_pkt_devp->do_reset_notification) {
 		/* notify client that a reset occurred */
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
 		return notify_reset(smd_pkt_devp);
 	}
+	D_READ("Begin %s on smd_pkt_dev id:%d buffer_size %d\n",
+		__func__, smd_pkt_devp->i, count);
 
 	chl = smd_pkt_devp->ch;
 wait_for_packet:
@@ -257,20 +319,19 @@
 				      smd_read_avail(chl)) ||
 				     smd_pkt_devp->has_reset);
 
-	if (smd_pkt_devp->has_reset)
+	if (smd_pkt_devp->has_reset) {
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
 		return notify_reset(smd_pkt_devp);
+	}
 
 	if (r < 0) {
 		/* qualify error message */
 		if (r != -ERESTARTSYS) {
 			/* we get this anytime a signal comes in */
-			printk(KERN_ERR "ERROR:%s:%i:%s: "
-			       "wait_event_interruptible ret %i\n",
-			       __FILE__,
-			       __LINE__,
-			       __func__,
-			       r
-				);
+			pr_err("%s: wait_event_interruptible on smd_pkt_dev"
+			       " id:%d ret %i\n",
+				__func__, smd_pkt_devp->i, r);
 		}
 		return r;
 	}
@@ -281,13 +342,16 @@
 	pkt_size = smd_cur_packet_size(smd_pkt_devp->ch);
 
 	if (!pkt_size) {
-		D(KERN_ERR "%s: Nothing to read\n", __func__);
+		pr_err("%s: No data on smd_pkt_dev id:%d, False wakeup\n",
+			__func__, smd_pkt_devp->i);
 		mutex_unlock(&smd_pkt_devp->rx_lock);
 		goto wait_for_packet;
 	}
 
 	if (pkt_size > count) {
-		pr_err("packet size %i > buffer size %i,", pkt_size, count);
+		pr_err("%s: failure on smd_pkt_dev id: %d - packet size %d"
+		       " > buffer size %d,", __func__, smd_pkt_devp->i,
+			pkt_size, count);
 		mutex_unlock(&smd_pkt_devp->rx_lock);
 		return -ETOOSMALL;
 	}
@@ -299,8 +363,12 @@
 					 (pkt_size - bytes_read));
 		if (r < 0) {
 			mutex_unlock(&smd_pkt_devp->rx_lock);
-			if (smd_pkt_devp->has_reset)
+			if (smd_pkt_devp->has_reset) {
+				pr_err("%s notifying reset for smd_pkt_dev"
+				       " id:%d\n", __func__, smd_pkt_devp->i);
 				return notify_reset(smd_pkt_devp);
+			}
+			pr_err("%s Error while reading %d\n", __func__, r);
 			return r;
 		}
 		bytes_read += r;
@@ -310,14 +378,28 @@
 				   smd_pkt_devp->has_reset);
 		if (smd_pkt_devp->has_reset) {
 			mutex_unlock(&smd_pkt_devp->rx_lock);
+			pr_err("%s notifying reset for smd_pkt_dev  id:%d\n",
+				__func__, smd_pkt_devp->i);
 			return notify_reset(smd_pkt_devp);
 		}
 	} while (pkt_size != bytes_read);
-	D_DUMP_BUFFER("read: ", bytes_read, buf);
+	D_READ_DUMP_BUFFER("Read: ", (bytes_read > 16 ? 16 : bytes_read), buf);
 	mutex_unlock(&smd_pkt_devp->rx_lock);
 
-	D(KERN_ERR "%s: just read %i bytes\n",
-	  __func__, bytes_read);
+	mutex_lock(&smd_pkt_devp->ch_lock);
+	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+	if (smd_pkt_devp->poll_mode &&
+	    !smd_cur_packet_size(smd_pkt_devp->ch)) {
+		wake_unlock(&smd_pkt_devp->pa_wake_lock);
+		smd_pkt_devp->poll_mode = 0;
+		D_READ("%s unlocked smd_pkt_dev id:%d wakelock\n",
+			__func__, smd_pkt_devp->i);
+	}
+	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
+	mutex_unlock(&smd_pkt_devp->ch_lock);
+
+	D_READ("Finished %s on smd_pkt_dev id:%d  %d bytes\n",
+		__func__, smd_pkt_devp->i, bytes_read);
 
 	/* check and wakeup read threads waiting on this device */
 	check_and_wakeup_reader(smd_pkt_devp);
@@ -334,24 +416,33 @@
 	struct smd_pkt_dev *smd_pkt_devp;
 	DEFINE_WAIT(write_wait);
 
-	D(KERN_ERR "%s: writting %i bytes\n",
-	  __func__, count);
-
 	smd_pkt_devp = file->private_data;
 
-	if (!smd_pkt_devp || !smd_pkt_devp->ch)
+	if (!smd_pkt_devp) {
+		pr_err("%s on NULL smd_pkt_dev\n", __func__);
 		return -EINVAL;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return -EINVAL;
+	}
 
 	if (smd_pkt_devp->do_reset_notification) {
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
 		/* notify client that a reset occurred */
 		return notify_reset(smd_pkt_devp);
 	}
+	D_WRITE("Begin %s on smd_pkt_dev id:%d data_size %d\n",
+		__func__, smd_pkt_devp->i, count);
 
 	mutex_lock(&smd_pkt_devp->tx_lock);
 	if (!smd_pkt_devp->blocking_write) {
 		if (smd_write_avail(smd_pkt_devp->ch) < count) {
-			D(KERN_ERR "%s: Not enough space to write\n",
-				   __func__);
+			pr_err("%s: Not enough space in smd_pkt_dev id:%d\n",
+				   __func__, smd_pkt_devp->i);
 			mutex_unlock(&smd_pkt_devp->tx_lock);
 			return -ENOMEM;
 		}
@@ -360,7 +451,8 @@
 	r = smd_write_start(smd_pkt_devp->ch, count);
 	if (r < 0) {
 		mutex_unlock(&smd_pkt_devp->tx_lock);
-		pr_err("%s: Error %d @ smd_write_start\n", __func__, r);
+		pr_err("%s: Error:%d in smd_pkt_dev id:%d @ smd_write_start\n",
+			__func__, r, smd_pkt_devp->i);
 		return r;
 	}
 
@@ -378,6 +470,8 @@
 
 		if (smd_pkt_devp->has_reset) {
 			mutex_unlock(&smd_pkt_devp->tx_lock);
+			pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+				__func__, smd_pkt_devp->i);
 			return notify_reset(smd_pkt_devp);
 		} else {
 			r = smd_write_segment(smd_pkt_devp->ch,
@@ -385,17 +479,22 @@
 					      (count - bytes_written), 1);
 			if (r < 0) {
 				mutex_unlock(&smd_pkt_devp->tx_lock);
-				if (smd_pkt_devp->has_reset)
+				if (smd_pkt_devp->has_reset) {
+					pr_err("%s notifying reset for"
+					       " smd_pkt_dev id:%d\n",
+						__func__, smd_pkt_devp->i);
 					return notify_reset(smd_pkt_devp);
+				}
 			}
 			bytes_written += r;
 		}
 	} while (bytes_written != count);
 	smd_write_end(smd_pkt_devp->ch);
 	mutex_unlock(&smd_pkt_devp->tx_lock);
-
-	D(KERN_ERR "%s: just wrote %i bytes\n",
-	       __func__, count);
+	D_WRITE_DUMP_BUFFER("Write: ",
+			    (bytes_written > 16 ? 16 : bytes_written), buf);
+	D_WRITE("Finished %s on smd_pkt_dev id:%d %d bytes\n",
+		__func__, smd_pkt_devp->i, count);
 
 	return count;
 }
@@ -406,12 +505,18 @@
 	unsigned int mask = 0;
 
 	smd_pkt_devp = file->private_data;
-	if (!smd_pkt_devp)
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
 		return POLLERR;
+	}
 
+	smd_pkt_devp->poll_mode = 1;
 	poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
-	if (smd_read_avail(smd_pkt_devp->ch))
+	if (smd_read_avail(smd_pkt_devp->ch)) {
 		mask |= POLLIN | POLLRDNORM;
+		D_POLL("%s sets POLLIN for smd_pkt_dev id: %d\n",
+			__func__, smd_pkt_devp->i);
+	}
 
 	return mask;
 }
@@ -419,39 +524,60 @@
 static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
 {
 	int sz;
+	unsigned long flags;
 
-	if (!smd_pkt_devp || !smd_pkt_devp->ch)
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
 		return;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return;
+	}
 
 	sz = smd_cur_packet_size(smd_pkt_devp->ch);
 	if (sz == 0) {
-		D(KERN_ERR "%s: packet size is 0\n", __func__);
+		D_READ("%s: No packet in smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
 		return;
 	}
 	if (!smd_read_avail(smd_pkt_devp->ch)) {
-		D(KERN_ERR "%s: packet size is %i - "
-		  "but the data isn't here\n",
-		  __func__, sz);
+		D_READ("%s: packet size is %d in smd_pkt_dev id:%d -"
+			" but the data isn't here\n",
+			__func__, sz, smd_pkt_devp->i);
 		return;
 	}
 
 	/* here we have a packet of size sz ready */
 	wake_up(&smd_pkt_devp->ch_read_wait_queue);
+	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+	wake_lock(&smd_pkt_devp->pa_wake_lock);
+	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
 	schedule_work(&smd_pkt_devp->packet_arrival_work);
-	D(KERN_ERR "%s: after wake_up\n", __func__);
+	D_READ("%s: wake_up smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
 }
 
 static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp)
 {
 	int sz;
 
-	if (!smd_pkt_devp || !smd_pkt_devp->ch)
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
 		return;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return;
+	}
 
 	sz = smd_write_avail(smd_pkt_devp->ch);
 	if (sz) {
-		D(KERN_ERR "%s: %d bytes Write Space available\n",
-			    __func__, sz);
+		D_WRITE("%s: %d bytes write space in smd_pkt_dev id:%d\n",
+			__func__, sz, smd_pkt_devp->i);
 		smd_disable_read_intr(smd_pkt_devp->ch);
 		wake_up(&smd_pkt_devp->ch_write_wait_queue);
 	}
@@ -461,31 +587,32 @@
 {
 	struct smd_pkt_dev *smd_pkt_devp = priv;
 
-	if (smd_pkt_devp->ch == 0)
+	if (smd_pkt_devp->ch == 0) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
 		return;
+	}
 
 	switch (event) {
 	case SMD_EVENT_DATA: {
-		D(KERN_ERR "%s: data\n", __func__);
+		D_STATUS("%s: DATA event in smd_pkt_dev id:%d\n",
+			 __func__, smd_pkt_devp->i);
 		check_and_wakeup_reader(smd_pkt_devp);
 		if (smd_pkt_devp->blocking_write)
 			check_and_wakeup_writer(smd_pkt_devp);
-		D(KERN_ERR "%s: data after check_and_wakeup\n", __func__);
 		break;
 	}
 	case SMD_EVENT_OPEN:
-		D(KERN_ERR "%s: smd opened\n",
-		  __func__);
-
+		D_STATUS("%s: OPEN event in smd_pkt_dev id:%d\n",
+			  __func__, smd_pkt_devp->i);
 		smd_pkt_devp->has_reset = 0;
 		smd_pkt_devp->is_open = 1;
 		wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
 		break;
 	case SMD_EVENT_CLOSE:
+		D_STATUS("%s: CLOSE event in smd_pkt_dev id:%d\n",
+			  __func__, smd_pkt_devp->i);
 		smd_pkt_devp->is_open = 0;
-		printk(KERN_ERR "%s: smd closed\n",
-		       __func__);
-
 		/* put port into reset state */
 		clean_and_signal(smd_pkt_devp);
 		if (smd_pkt_devp->i == LOOPBACK_INX)
@@ -529,6 +656,7 @@
 	"smd22",
 	"smd_sns_dsps",
 	"apr_apps2",
+	"smdcntl8",
 	"smd_pkt_loopback",
 };
 
@@ -544,6 +672,7 @@
 	"DATA22",
 	"SENSOR",
 	"apr_apps2",
+	"DATA40_CNTL",
 	"LOOPBACK",
 };
 
@@ -560,6 +689,7 @@
 	SMD_APPS_DSPS,
 	SMD_APPS_QDSP,
 	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
 };
 #endif
 
@@ -570,6 +700,8 @@
 	for (i = 0; i < NUM_SMD_PKT_PORTS; i++) {
 		if (!strncmp(pdev->name, smd_ch_name[i], SMD_MAX_CH_NAME_LEN)) {
 			complete_all(&smd_pkt_devp[i]->ch_allocated);
+			D_STATUS("%s allocated SMD ch for smd_pkt_dev id:%d\n",
+				 __func__, i);
 			break;
 		}
 	}
@@ -589,12 +721,15 @@
 {
 	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);
 
-	if (!smd_pkt_devp)
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
 		return -EINVAL;
+	}
+	D_STATUS("Begin %s on smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
 
 	wake_lock_init(&smd_pkt_devp->pa_wake_lock, WAKE_LOCK_SUSPEND,
 			smd_pkt_dev_name[smd_pkt_devp->i]);
@@ -604,17 +739,28 @@
 
 	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;
+				pr_err("%s failed on smd_pkt_dev id:%d -"
+				       " pil_get failed for %s\n", __func__,
+					smd_pkt_devp->i, peripheral);
+				goto release_pd;
 			}
 
 			/* Wait for the modem SMSM to be inited for the SMD
@@ -643,8 +789,9 @@
 				if (r == 0)
 					r = -ETIMEDOUT;
 				if (r < 0) {
-					pr_err("%s: wait failed for smd port:"
-					       " %d\n", __func__, r);
+					pr_err("%s: wait on smd_pkt_dev id:%d"
+					       " allocation failed rc:%d\n",
+						__func__, smd_pkt_devp->i, r);
 					goto release_pil;
 				}
 			}
@@ -668,21 +815,28 @@
 			r = -ETIMEDOUT;
 
 		if (r < 0) {
-			pr_err("%s: wait failed for smd open: %d\n",
-			       __func__, r);
+			pr_err("%s: wait on smd_pkt_dev id:%d OPEN event failed"
+			       " rc:%d\n", __func__, smd_pkt_devp->i, r);
 		} else if (!smd_pkt_devp->is_open) {
-			pr_err("%s: Invalid open notification\n", __func__);
+			pr_err("%s: Invalid OPEN event on smd_pkt_dev id:%d\n",
+				__func__, smd_pkt_devp->i);
 			r = -ENODEV;
 		} else {
 			smd_disable_read_intr(smd_pkt_devp->ch);
 			smd_pkt_devp->ch_size =
 				smd_write_avail(smd_pkt_devp->ch);
 			r = 0;
+			D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
+				 __func__, smd_pkt_devp->i);
 		}
 	}
 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);
 
@@ -697,8 +851,12 @@
 	int r = 0;
 	struct smd_pkt_dev *smd_pkt_devp = file->private_data;
 
-	if (!smd_pkt_devp)
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
 		return -EINVAL;
+	}
+	D_STATUS("Begin %s on smd_pkt_dev id:%d\n",
+		 __func__, smd_pkt_devp->i);
 
 	clean_and_signal(smd_pkt_devp);
 
@@ -707,6 +865,8 @@
 		r = smd_close(smd_pkt_devp->ch);
 		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);
 	}
@@ -715,6 +875,8 @@
 	smd_pkt_devp->has_reset = 0;
 	smd_pkt_devp->do_reset_notification = 0;
 	wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
+	D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
+		 __func__, smd_pkt_devp->i);
 
 	return r;
 }
@@ -739,22 +901,14 @@
 			       NUM_SMD_PKT_PORTS,
 			       DEVICE_NAME);
 	if (IS_ERR_VALUE(r)) {
-		printk(KERN_ERR "ERROR:%s:%i:%s: "
-		       "alloc_chrdev_region() ret %i.\n",
-		       __FILE__,
-		       __LINE__,
-		       __func__,
-		       r);
+		pr_err("%s: alloc_chrdev_region() failed ret:%i\n",
+		       __func__, r);
 		goto error0;
 	}
 
 	smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
 	if (IS_ERR(smd_pkt_classp)) {
-		printk(KERN_ERR "ERROR:%s:%i:%s: "
-		       "class_create() ENOMEM\n",
-		       __FILE__,
-		       __LINE__,
-		       __func__);
+		pr_err("%s: class_create() failed ENOMEM\n", __func__);
 		r = -ENOMEM;
 		goto error1;
 	}
@@ -763,10 +917,8 @@
 		smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
 					 GFP_KERNEL);
 		if (IS_ERR(smd_pkt_devp[i])) {
-			printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n",
-			       __FILE__,
-			       __LINE__,
-			       __func__);
+			pr_err("%s: kzalloc() failed for smd_pkt_dev id:%d\n",
+				__func__, i);
 			r = -ENOMEM;
 			goto error2;
 		}
@@ -776,12 +928,13 @@
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_write_wait_queue);
 		smd_pkt_devp[i]->is_open = 0;
+		smd_pkt_devp[i]->poll_mode = 0;
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
 
+		spin_lock_init(&smd_pkt_devp[i]->pa_spinlock);
 		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;
@@ -791,11 +944,8 @@
 			     1);
 
 		if (IS_ERR_VALUE(r)) {
-			printk(KERN_ERR "%s:%i:%s: cdev_add() ret %i\n",
-			       __FILE__,
-			       __LINE__,
-			       __func__,
-			       r);
+			pr_err("%s: cdev_add() failed for smd_pkt_dev id:%d"
+			       " ret:%i\n", __func__, i, r);
 			kfree(smd_pkt_devp[i]);
 			goto error2;
 		}
@@ -808,11 +958,8 @@
 				      smd_pkt_dev_name[i]);
 
 		if (IS_ERR(smd_pkt_devp[i]->devicep)) {
-			printk(KERN_ERR "%s:%i:%s: "
-			       "device_create() ENOMEM\n",
-			       __FILE__,
-			       __LINE__,
-			       __func__);
+			pr_err("%s: device_create() failed for smd_pkt_dev"
+			       " id:%d\n", __func__, i);
 			r = -ENOMEM;
 			cdev_del(&smd_pkt_devp[i]->cdev);
 			kfree(smd_pkt_devp[i]);
@@ -820,26 +967,18 @@
 		}
 		if (device_create_file(smd_pkt_devp[i]->devicep,
 					&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;
+			pr_err("%s: unable to create device attr for"
+			       " smd_pkt_dev id:%d\n", __func__, i);
 	}
 
 	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
 
-	D(KERN_INFO "SMD Packet Port Driver Initialized.\n");
+	D_STATUS("SMD Packet Port Driver Initialized.\n");
 	return 0;
 
  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,
@@ -859,7 +998,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..28850d0 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)) {
@@ -489,7 +487,8 @@
 		if (!smd_configs[n].dev_name)
 			continue;
 
-		if (!strncmp(pdev->name, smd_configs[n].dev_name,
+		if (pdev->id == smd_configs[n].edge &&
+			!strncmp(pdev->name, smd_configs[n].dev_name,
 					SMD_MAX_CH_NAME_LEN)) {
 			complete_all(&smd_tty[idx].ch_allocated);
 			return 0;
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index bf598b7..2e9a97c 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -59,10 +59,20 @@
 #define D(x...) do {} while (0)
 #endif
 
+/*
+ * Legacy targets use the 32KHz hardware timer and new targets will use
+ * the scheduler timer scaled to a 32KHz tick count.
+ *
+ * As testing on legacy targets permits, we will move them to use
+ * sched_clock() and eventually remove the conditiona compilation.
+ */
 #if defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60) \
 	|| defined(CONFIG_ARCH_FSM9XXX)
 #define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x08)
-#else
+#elif defined(CONFIG_ARCH_APQ8064) || defined(CONFIG_ARCH_MSM7X01A) || \
+	defined(CONFIG_ARCH_MSM7x25) || defined(CONFIG_ARCH_MSM7X27) || \
+	defined(CONFIG_ARCH_MSM7X27A) || defined(CONFIG_ARCH_MSM8960) || \
+	defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_QSD8X50)
 #define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x04)
 #endif
 
@@ -623,6 +633,8 @@
 static void init_syms(void) {}
 #endif
 
+#ifdef TIMESTAMP_ADDR
+/* legacy timestamp using 32.768KHz clock */
 static inline unsigned int read_timestamp(void)
 {
 	unsigned int tick = 0;
@@ -637,6 +649,18 @@
 
 	return tick;
 }
+#else
+static inline unsigned int read_timestamp(void)
+{
+	unsigned long long val;
+
+	/* SMEM LOG uses a 32.768KHz timestamp */
+	val = sched_clock() * 32768U;
+	do_div(val, 1000000000U);
+
+	return (unsigned int)val;
+}
+#endif
 
 static void smem_log_event_from_user(struct smem_log_inst *inst,
 				     const char __user *buf, int size, int num)
@@ -649,6 +673,11 @@
 	int first = 1;
 	int ret;
 
+	if (!inst->idx) {
+		pr_err("%s: invalid write index\n", __func__);
+		return;
+	}
+
 	remote_spin_lock_irqsave(inst->remote_spinlock, flags);
 
 	while (num--) {
@@ -821,9 +850,9 @@
 
 	inst[GEN].which_log = GEN;
 	inst[GEN].events =
-		(struct smem_log_item *)smem_alloc(SMEM_SMEM_LOG_EVENTS,
+		(struct smem_log_item *)smem_alloc2(SMEM_SMEM_LOG_EVENTS,
 						  SMEM_LOG_EVENTS_SIZE);
-	inst[GEN].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_IDX,
+	inst[GEN].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_LOG_IDX,
 					     sizeof(uint32_t));
 	if (!inst[GEN].events || !inst[GEN].idx)
 		pr_info("%s: no log or log_idx allocated\n", __func__);
@@ -837,9 +866,9 @@
 	inst[STA].which_log = STA;
 	inst[STA].events =
 		(struct smem_log_item *)
-		smem_alloc(SMEM_SMEM_STATIC_LOG_EVENTS,
+		smem_alloc2(SMEM_SMEM_STATIC_LOG_EVENTS,
 			   SMEM_STATIC_LOG_EVENTS_SIZE);
-	inst[STA].idx = (uint32_t *)smem_alloc(SMEM_SMEM_STATIC_LOG_IDX,
+	inst[STA].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_STATIC_LOG_IDX,
 						     sizeof(uint32_t));
 	if (!inst[STA].events || !inst[STA].idx)
 		pr_info("%s: no static log or log_idx allocated\n", __func__);
@@ -853,9 +882,9 @@
 	inst[POW].which_log = POW;
 	inst[POW].events =
 		(struct smem_log_item *)
-		smem_alloc(SMEM_SMEM_LOG_POWER_EVENTS,
+		smem_alloc2(SMEM_SMEM_LOG_POWER_EVENTS,
 			   SMEM_POWER_LOG_EVENTS_SIZE);
-	inst[POW].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_POWER_IDX,
+	inst[POW].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_LOG_POWER_IDX,
 						     sizeof(uint32_t));
 	if (!inst[POW].events || !inst[POW].idx)
 		pr_info("%s: no power log or log_idx allocated\n", __func__);
@@ -898,6 +927,9 @@
 
 	local_inst = fp->private_data;
 
+	if (!local_inst->idx)
+		return -ENODEV;
+
 	remote_spin_lock_irqsave(local_inst->remote_spinlock, flags);
 
 	orig_idx = *local_inst->idx;
@@ -947,6 +979,8 @@
 	struct smem_log_inst *inst;
 
 	inst = fp->private_data;
+	if (!inst->idx)
+		return -ENODEV;
 
 	remote_spin_lock_irqsave(inst->remote_spinlock, flags);
 
@@ -1185,8 +1219,10 @@
 	int curr_read_avail;
 	unsigned long flags = 0;
 
-	remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+	if (!inst->idx)
+		return 0;
 
+	remote_spin_lock_irqsave(inst->remote_spinlock, flags);
 	curr_read_avail = (*inst->idx - inst->read_idx);
 	if (curr_read_avail < 0)
 		curr_read_avail = inst->num - inst->read_idx + *inst->idx;
@@ -1694,6 +1730,10 @@
 static int debug_dump(char *buf, int max, uint32_t cont)
 {
 	int r;
+
+	if (!inst[GEN].idx || !inst[GEN].events)
+		return -ENODEV;
+
 	while (cont) {
 		update_read_avail(&inst[GEN]);
 		r = wait_event_interruptible_timeout(inst[GEN].read_wait,
@@ -1714,6 +1754,10 @@
 static int debug_dump_sym(char *buf, int max, uint32_t cont)
 {
 	int r;
+
+	if (!inst[GEN].idx || !inst[GEN].events)
+		return -ENODEV;
+
 	while (cont) {
 		update_read_avail(&inst[GEN]);
 		r = wait_event_interruptible_timeout(inst[GEN].read_wait,
@@ -1734,6 +1778,10 @@
 static int debug_dump_static(char *buf, int max, uint32_t cont)
 {
 	int r;
+
+	if (!inst[STA].idx || !inst[STA].events)
+		return -ENODEV;
+
 	while (cont) {
 		update_read_avail(&inst[STA]);
 		r = wait_event_interruptible_timeout(inst[STA].read_wait,
@@ -1754,6 +1802,10 @@
 static int debug_dump_static_sym(char *buf, int max, uint32_t cont)
 {
 	int r;
+
+	if (!inst[STA].idx || !inst[STA].events)
+		return -ENODEV;
+
 	while (cont) {
 		update_read_avail(&inst[STA]);
 		r = wait_event_interruptible_timeout(inst[STA].read_wait,
@@ -1774,6 +1826,10 @@
 static int debug_dump_power(char *buf, int max, uint32_t cont)
 {
 	int r;
+
+	if (!inst[POW].idx || !inst[POW].events)
+		return -ENODEV;
+
 	while (cont) {
 		update_read_avail(&inst[POW]);
 		r = wait_event_interruptible_timeout(inst[POW].read_wait,
@@ -1794,6 +1850,10 @@
 static int debug_dump_power_sym(char *buf, int max, uint32_t cont)
 {
 	int r;
+
+	if (!inst[POW].idx || !inst[POW].events)
+		return -ENODEV;
+
 	while (cont) {
 		update_read_avail(&inst[POW]);
 		r = wait_event_interruptible_timeout(inst[POW].read_wait,
@@ -1822,10 +1882,15 @@
 			  size_t count, loff_t *ppos)
 {
 	int r;
-	static int bsize;
+	int bsize = 0;
 	int (*fill)(char *, int, uint32_t) = file->private_data;
-	if (!(*ppos))
+	if (!(*ppos)) {
 		bsize = fill(debug_buffer, EVENTS_PRINT_SIZE, 0);
+
+		if (bsize < 0)
+			bsize = scnprintf(debug_buffer,
+				EVENTS_PRINT_SIZE, "Log not available\n");
+	}
 	DBG("%s: count %d ppos %d\n", __func__, count, (unsigned int)*ppos);
 	r =  simple_read_from_buffer(buf, count, ppos, debug_buffer,
 				     bsize);
@@ -1840,12 +1905,21 @@
 	int bsize;
 	if (!buffer)
 		return -ENOMEM;
+
 	bsize = fill(buffer, count, 1);
+	if (bsize < 0) {
+		if (*ppos == 0)
+			bsize = scnprintf(buffer, count, "Log not available\n");
+		else
+			bsize = 0;
+	}
+
 	DBG("%s: count %d bsize %d\n", __func__, count, bsize);
 	if (copy_to_user(buf, buffer, bsize)) {
 		kfree(buffer);
 		return -EFAULT;
 	}
+	*ppos += bsize;
 	kfree(buffer);
 	return bsize;
 }
@@ -1934,28 +2008,25 @@
 	return ret;
 }
 
-static int modem_notifier(struct notifier_block *this,
-			  unsigned long code,
-			  void *_cmd)
+static int smsm_driver_state_notifier(struct notifier_block *this,
+				      unsigned long code,
+				      void *_cmd)
 {
-	switch (code) {
-	case MODEM_NOTIFIER_SMSM_INIT:
+	int ret = 0;
+	if (code & SMSM_INIT) {
 		if (!smem_log_initialized)
-			smem_log_initialize();
-		break;
-	default:
-		break;
+			ret = smem_log_initialize();
 	}
-	return NOTIFY_DONE;
+	return ret;
 }
 
 static struct notifier_block nb = {
-	.notifier_call = modem_notifier,
+	.notifier_call = smsm_driver_state_notifier,
 };
 
 static int __init smem_log_init(void)
 {
-	return modem_register_notifier(&nb);
+	return smsm_driver_state_notifier_register(&nb);
 }
 
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index a1bf280..3faeb37 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -257,7 +257,6 @@
 static struct socinfo_v1 dummy_socinfo = {
 	.format = 1,
 	.version = 1,
-	.build_id = "Dummy socinfo placeholder"
 };
 
 uint32_t socinfo_get_id(void)
@@ -604,7 +603,7 @@
 
 arch_initcall(socinfo_init_sysdev);
 
-void *setup_dummy_socinfo(void)
+static void * __init setup_dummy_socinfo(void)
 {
 	if (machine_is_msm8960_rumi3() || machine_is_msm8960_sim() ||
 	    machine_is_msm8960_cdp())
@@ -613,10 +612,14 @@
 		dummy_socinfo.id = 109;
 	else if (machine_is_msm9615_mtp() || machine_is_msm9615_cdp())
 		dummy_socinfo.id = 104;
-	else if (early_machine_is_copper())
+	else if (early_machine_is_copper()) {
 		dummy_socinfo.id = 126;
-	else if (machine_is_msm8625_rumi3())
+		strlcpy(dummy_socinfo.build_id, "copper - ",
+			sizeof(dummy_socinfo.build_id));
+	} else if (machine_is_msm8625_rumi3())
 		dummy_socinfo.id = 127;
+	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
+		sizeof(dummy_socinfo.build_id));
 	return (void *) &dummy_socinfo;
 }
 
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 4a7cf91..2a6294f 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.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
@@ -68,6 +68,9 @@
 
 	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0xFF;
 	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= vlevel;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
 }
 
 static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
@@ -235,6 +238,7 @@
 	msm_spm_drv_set_vctl(dev, vlevel);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
 	mb();
 
 	/* Wait for PMIC state to return to idle or until timeout */
@@ -271,6 +275,17 @@
 	return -EIO;
 }
 
+void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
+{
+	int i;
+
+	for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
+		msm_spm_drv_flush_shadow(dev, i);
+
+	msm_spm_drv_flush_seq_entry(dev);
+	mb();
+}
+
 int __init msm_spm_drv_init(struct msm_spm_driver_data *dev,
 		struct msm_spm_platform_data *data)
 {
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index b155781..21c7dca 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -115,6 +115,7 @@
 #if defined(CONFIG_MSM_L2_SPM)
 int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
 int msm_spm_l2_init(struct msm_spm_platform_data *data);
+void msm_spm_l2_reinit(void);
 #else
 static inline int msm_spm_l2_set_low_power_mode(unsigned int mode,
 		bool notify_rpm)
@@ -125,6 +126,10 @@
 {
 	return -ENOSYS;
 }
+static inline void msm_spm_l2_reinit(void)
+{
+	/* empty */
+}
 #endif /* defined(CONFIG_MSM_L2_SPM) */
 
 #else /* defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2) */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 883dec1..2b17fa3 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -126,6 +126,13 @@
 	return ret;
 }
 
+void msm_spm_reinit(void)
+{
+	unsigned int cpu;
+	for_each_possible_cpu(cpu)
+		msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
+}
+
 int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
 {
 	struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
@@ -169,11 +176,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;
@@ -202,4 +205,9 @@
 {
 	return msm_spm_dev_init(&msm_spm_l2_device, data);
 }
+
+void msm_spm_l2_reinit(void)
+{
+	msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
+}
 #endif
diff --git a/arch/arm/mach-msm/spm_driver.h b/arch/arm/mach-msm/spm_driver.h
index f8d3cfc..712f051 100644
--- a/arch/arm/mach-msm/spm_driver.h
+++ b/arch/arm/mach-msm/spm_driver.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
@@ -23,6 +23,7 @@
 
 int msm_spm_drv_init(struct msm_spm_driver_data *dev,
 		struct msm_spm_platform_data *data);
+void msm_spm_drv_reinit(struct msm_spm_driver_data *dev);
 int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
 		uint32_t addr);
 int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 78a6203..bc4bd21 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.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
@@ -23,6 +23,8 @@
 #include <linux/io.h>
 #include <linux/kthread.h>
 #include <linux/time.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
 
 #include <asm/current.h>
 
@@ -43,9 +45,12 @@
 	struct subsys_data *subsys_ptrs[];
 };
 
-struct restart_thread_data {
+struct restart_wq_data {
 	struct subsys_data *subsys;
+	struct wake_lock ssr_wake_lock;
+	char wakelockname[64];
 	int coupled;
+	struct work_struct work;
 };
 
 struct restart_log {
@@ -56,6 +61,7 @@
 
 static int restart_level;
 static int enable_ramdumps;
+struct workqueue_struct *ssr_wq;
 
 static LIST_HEAD(restart_log_list);
 static LIST_HEAD(subsystem_list);
@@ -297,9 +303,10 @@
 	mutex_unlock(&restart_log_mutex);
 }
 
-static int subsystem_restart_thread(void *data)
+static void subsystem_restart_wq_func(struct work_struct *work)
 {
-	struct restart_thread_data *r_work = data;
+	struct restart_wq_data *r_work = container_of(work,
+						struct restart_wq_data, work);
 	struct subsys_data **restart_list;
 	struct subsys_data *subsys = r_work->subsys;
 	struct subsys_soc_restart_order *soc_restart_order = NULL;
@@ -334,10 +341,8 @@
 	/* Try to acquire shutdown_lock. If this fails, these subsystems are
 	 * already being restarted - return.
 	 */
-	if (!mutex_trylock(shutdown_lock)) {
-		kfree(data);
-		do_exit(0);
-	}
+	if (!mutex_trylock(shutdown_lock))
+		goto out;
 
 	pr_debug("[%p]: Attempting to get powerup lock!\n", current);
 
@@ -430,15 +435,17 @@
 
 	pr_debug("[%p]: Released powerup lock!\n", current);
 
-	kfree(data);
-	do_exit(0);
+out:
+	wake_unlock(&r_work->ssr_wake_lock);
+	wake_lock_destroy(&r_work->ssr_wake_lock);
+	kfree(r_work);
 }
 
 int subsystem_restart(const char *subsys_name)
 {
 	struct subsys_data *subsys;
-	struct task_struct *tsk;
-	struct restart_thread_data *data = NULL;
+	struct restart_wq_data *data = NULL;
+	int rc;
 
 	if (!subsys_name) {
 		pr_err("Invalid subsystem name.\n");
@@ -459,7 +466,7 @@
 	}
 
 	if (restart_level != RESET_SOC) {
-		data = kzalloc(sizeof(struct restart_thread_data), GFP_KERNEL);
+		data = kzalloc(sizeof(struct restart_wq_data), GFP_KERNEL);
 		if (!data) {
 			restart_level = RESET_SOC;
 			pr_warn("Failed to alloc restart data. Resetting.\n");
@@ -482,18 +489,18 @@
 		pr_debug("Restarting %s [level=%d]!\n", subsys_name,
 				restart_level);
 
-		/* Let the kthread handle the actual restarting. Using a
-		 * workqueue will not work since all restart requests are
-		 * serialized and it prevents the short circuiting of
-		 * restart requests for subsystems already in a restart
-		 * sequence.
-		 */
-		tsk = kthread_run(subsystem_restart_thread, data,
-				"subsystem_restart_thread");
-		if (IS_ERR(tsk))
-			panic("%s: Unable to create thread to restart %s",
-				__func__, subsys->name);
+		snprintf(data->wakelockname, sizeof(data->wakelockname),
+				"ssr(%s)", subsys_name);
+		wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND,
+			data->wakelockname);
+		wake_lock(&data->ssr_wake_lock);
 
+		INIT_WORK(&data->work, subsystem_restart_wq_func);
+		rc = schedule_work(&data->work);
+
+		if (rc < 0)
+			panic("%s: Unable to schedule work to restart %s",
+			     __func__, subsys->name);
 		break;
 
 	case RESET_SOC:
@@ -577,7 +584,8 @@
 		n_restart_orders = ARRAY_SIZE(orders_8x60_all);
 	}
 
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
+			cpu_is_apq8064()) {
 		restart_orders = restart_orders_8960;
 		n_restart_orders = ARRAY_SIZE(restart_orders_8960);
 	}
@@ -596,6 +604,11 @@
 
 	restart_level = RESET_SOC;
 
+	ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
+
+	if (!ssr_wq)
+		panic("Couldn't allocate workqueue for subsystem restart.\n");
+
 	ret = ssr_init_soc_restart_orders();
 
 	return ret;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 4128e3a..ea8356c 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -66,6 +66,7 @@
 	DGT_CLK_CTL_DIV_3 = 2,
 	DGT_CLK_CTL_DIV_4 = 3,
 };
+#define TIMER_STATUS            0x0088
 #define TIMER_ENABLE_EN              1
 #define TIMER_ENABLE_CLR_ON_MATCH_EN 2
 
@@ -112,6 +113,7 @@
 	uint32_t                    index;
 	void __iomem                *global_counter;
 	void __iomem                *local_counter;
+	uint32_t		    status_mask;
 	union {
 		struct clock_event_device		*evt;
 		struct clock_event_device __percpu	**percpu_evt;
@@ -1001,15 +1003,21 @@
 		dgt->regbase = MSM_TMR_BASE + 0x10;
 	} else if (cpu_is_fsm9xxx())
 		dgt->freq = 4800000;
-	else if (cpu_is_msm7x30() || cpu_is_msm8x55())
+	else if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		dgt->freq = 6144000;
-	else if (cpu_is_msm8x60()) {
+	} else if (cpu_is_msm8x60()) {
 		global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		dgt->freq = 6750000;
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 	} else if (cpu_is_msm9615()) {
 		dgt->freq = 6750000;
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		gpt->freq = 32765;
 		gpt_hz = 32765;
 		sclk_hz = 32765;
@@ -1019,10 +1027,12 @@
 		global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
 		dgt->freq = 6750000;
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		gpt->freq = 32765;
 		gpt_hz = 32765;
 		sclk_hz = 32765;
-		if (!machine_is_apq8064_rumi3()) {
+		if (!cpu_is_msm8930()) {
 			gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
 			dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
 		}
@@ -1042,8 +1052,7 @@
 		struct clock_event_device *ce = &clock->clockevent;
 		struct clocksource *cs = &clock->clocksource;
 		__raw_writel(0, clock->regbase + TIMER_ENABLE);
-		__raw_writel(1, clock->regbase + TIMER_CLEAR);
-		__raw_writel(0, clock->regbase + TIMER_COUNT_VAL);
+		__raw_writel(0, clock->regbase + TIMER_CLEAR);
 		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
 
 		if ((clock->freq << clock->shift) == gpt_hz) {
@@ -1105,15 +1114,22 @@
 		if (chip && chip->irq_mask)
 			chip->irq_mask(irq_get_irq_data(clock->irq));
 
+		if (clock->status_mask)
+			while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+			       clock->status_mask)
+				;
+
 		clockevents_register_device(ce);
 	}
 	msm_sched_clock_init();
 
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
 	if (is_smp()) {
 		__raw_writel(1,
 			msm_clocks[MSM_CLOCK_DGT].regbase + TIMER_ENABLE);
 		set_delay_fn(read_current_timer_delay_loop);
 	}
+#endif
 }
 
 #ifdef CONFIG_SMP
@@ -1136,6 +1152,10 @@
 		__raw_writel(0, clock->regbase + TIMER_CLEAR);
 		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
 		__get_cpu_var(first_boot) = false;
+		if (clock->status_mask)
+			while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+			       clock->status_mask)
+				;
 	}
 	evt->irq = clock->irq;
 	evt->name = "local_timer";
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index caef19d..7da9e6a 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -17,9 +17,14 @@
 extern struct sys_timer msm_timer;
 
 void __iomem *msm_timer_get_timer0_base(void);
-int64_t msm_timer_enter_idle(void);
-void msm_timer_exit_idle(int low_power);
 int64_t msm_timer_get_sclk_time(int64_t *period);
 uint32_t msm_timer_get_sclk_ticks(void);
 int msm_timer_init_time_sync(void (*timeout)(void));
+#ifndef CONFIG_ARM_ARCH_TIMER
+int64_t msm_timer_enter_idle(void);
+void msm_timer_exit_idle(int low_power);
+#else
+static inline int64_t msm_timer_enter_idle(void) { return 0; }
+static inline void msm_timer_exit_idle(int low_power) { return; }
+#endif
 #endif
diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c
index cffa5c7..bb29279 100644
--- a/arch/arm/mach-msm/vreg.c
+++ b/arch/arm/mach-msm/vreg.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/vreg.c
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -132,6 +132,8 @@
 {
 	kfree(vreg->name);
 	regulator_put(vreg->reg);
+	list_del(&vreg->list);
+	kfree(vreg);
 }
 
 int vreg_enable(struct vreg *vreg)
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 9970c90..90948ea 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)
@@ -82,7 +84,6 @@
 						MODULE_NAME);
 		return IRQ_HANDLED;
 	}
-	disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
 	ss_restart_inprogress = true;
 	ret = schedule_work(&riva_fatal_work);
 	return IRQ_HANDLED;
@@ -97,20 +98,25 @@
 	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);
+	disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
 
-	/* 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/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 5dcc59d..b3a7124 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -404,7 +404,7 @@
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);		\
 	reg &= ~BM_CLKCTRL_##dr##_DIV;					\
 	reg |= div << BP_CLKCTRL_##dr##_DIV;				\
-	if (reg | (1 << clk->enable_shift)) {				\
+	if (reg & (1 << clk->enable_shift)) {				\
 		pr_err("%s: clock is gated\n", __func__);		\
 		return -EINVAL;						\
 	}								\
diff --git a/arch/arm/mach-mxs/include/mach/mxs.h b/arch/arm/mach-mxs/include/mach/mxs.h
index 35a89dd..1332f73 100644
--- a/arch/arm/mach-mxs/include/mach/mxs.h
+++ b/arch/arm/mach-mxs/include/mach/mxs.h
@@ -30,6 +30,7 @@
  */
 #define cpu_is_mx23()		(					\
 		machine_is_mx23evk() ||					\
+		machine_is_stmp378x() ||				\
 		0)
 #define cpu_is_mx28()		(					\
 		machine_is_mx28evk() ||					\
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 19d5891..841ae21 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -326,6 +326,7 @@
 config OMAP3_EMU
 	bool "OMAP3 debugging peripherals"
 	depends on ARCH_OMAP3
+	select ARM_AMBA
 	select OC_ETM
 	help
 	  Say Y here to enable debugging hardware of omap3
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 2fdb70c..18d331e 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -133,7 +133,7 @@
 static void __init rx51_charger_init(void)
 {
 	WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO,
-		GPIOF_OUT_INIT_LOW, "isp1704_reset"));
+		GPIOF_OUT_INIT_HIGH, "isp1704_reset"));
 
 	platform_device_register(&rx51_charger_device);
 }
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 130034b..dfffbbf 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -528,7 +528,13 @@
 
 	case GPMC_CONFIG_DEV_SIZE:
 		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+		/* clear 2 target bits */
+		regval &= ~GPMC_CONFIG1_DEVICESIZE(3);
+
+		/* set the proper value */
 		regval |= GPMC_CONFIG1_DEVICESIZE(wval);
+
 		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
 		break;
 
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index fb7dc52..f5a6bc1 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -137,7 +137,7 @@
 		sr_write_reg(sr_info, ERRCONFIG_V1, status);
 	} else if (sr_info->ip_type == SR_TYPE_V2) {
 		/* Read the status bits */
-		sr_read_reg(sr_info, IRQSTATUS);
+		status = sr_read_reg(sr_info, IRQSTATUS);
 
 		/* Clear them by writing back */
 		sr_write_reg(sr_info, IRQSTATUS, status);
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index 810a982..6ca327d 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -307,7 +307,7 @@
 /******************************************************************************
  * USB Gadget
  ******************************************************************************/
-#if defined(CONFIG_USB_GADGET_PXA27X)||defined(CONFIG_USB_GADGET_PXA27X_MODULE)
+#if defined(CONFIG_USB_PXA27X)||defined(CONFIG_USB_PXA27X_MODULE)
 static void balloon3_udc_command(int cmd)
 {
 	if (cmd == PXA2XX_UDC_CMD_CONNECT)
diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c
index ff9ff5f..fdf611c 100644
--- a/arch/arm/mach-pxa/colibri-pxa320.c
+++ b/arch/arm/mach-pxa/colibri-pxa320.c
@@ -147,7 +147,7 @@
 static inline void __init colibri_pxa320_init_eth(void) {}
 #endif /* CONFIG_AX88796 */
 
-#if defined(CONFIG_USB_GADGET_PXA27X)||defined(CONFIG_USB_GADGET_PXA27X_MODULE)
+#if defined(CONFIG_USB_PXA27X)||defined(CONFIG_USB_PXA27X_MODULE)
 static struct gpio_vbus_mach_info colibri_pxa320_gpio_vbus_info = {
 	.gpio_vbus		= mfp_to_gpio(MFP_PIN_GPIO96),
 	.gpio_pullup		= -1,
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index d65e4bd..b9e8233 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -106,7 +106,7 @@
 }
 #endif
 
-#ifdef CONFIG_USB_GADGET_PXA25X
+#ifdef CONFIG_USB_PXA25X
 static struct gpio_vbus_mach_info gumstix_udc_info = {
 	.gpio_vbus		= GPIO_GUMSTIX_USB_GPIOn,
 	.gpio_pullup		= GPIO_GUMSTIX_USB_GPIOx,
diff --git a/arch/arm/mach-pxa/include/mach/palm27x.h b/arch/arm/mach-pxa/include/mach/palm27x.h
index 0a5e5ea..8d56043 100644
--- a/arch/arm/mach-pxa/include/mach/palm27x.h
+++ b/arch/arm/mach-pxa/include/mach/palm27x.h
@@ -37,8 +37,8 @@
 static inline void palm27x_lcd_init(int power, struct pxafb_mode_info *mode) {}
 #endif
 
-#if	defined(CONFIG_USB_GADGET_PXA27X) || \
-	defined(CONFIG_USB_GADGET_PXA27X_MODULE)
+#if	defined(CONFIG_USB_PXA27X) || \
+	defined(CONFIG_USB_PXA27X_MODULE)
 extern void __init palm27x_udc_init(int vbus, int pullup,
 					int vbus_inverted);
 #else
diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c
index 325c245..fbc10d7 100644
--- a/arch/arm/mach-pxa/palm27x.c
+++ b/arch/arm/mach-pxa/palm27x.c
@@ -164,8 +164,8 @@
 /******************************************************************************
  * USB Gadget
  ******************************************************************************/
-#if	defined(CONFIG_USB_GADGET_PXA27X) || \
-	defined(CONFIG_USB_GADGET_PXA27X_MODULE)
+#if	defined(CONFIG_USB_PXA27X) || \
+	defined(CONFIG_USB_PXA27X_MODULE)
 static struct gpio_vbus_mach_info palm27x_udc_info = {
 	.gpio_vbus_inverted	= 1,
 };
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
index fb06bd0..5193ce2 100644
--- a/arch/arm/mach-pxa/palmtc.c
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -339,7 +339,7 @@
 /******************************************************************************
  * UDC
  ******************************************************************************/
-#if defined(CONFIG_USB_GADGET_PXA25X)||defined(CONFIG_USB_GADGET_PXA25X_MODULE)
+#if defined(CONFIG_USB_PXA25X)||defined(CONFIG_USB_PXA25X_MODULE)
 static struct gpio_vbus_mach_info palmtc_udc_info = {
 	.gpio_vbus		= GPIO_NR_PALMTC_USB_DETECT_N,
 	.gpio_vbus_inverted	= 1,
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index 67bd414..10b80d4 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -343,7 +343,7 @@
 /******************************************************************************
  * USB Gadget
  ******************************************************************************/
-#if defined(CONFIG_USB_GADGET_PXA27X)||defined(CONFIG_USB_GADGET_PXA27X_MODULE)
+#if defined(CONFIG_USB_PXA27X)||defined(CONFIG_USB_PXA27X_MODULE)
 static struct gpio_vbus_mach_info vpac270_gpio_vbus_info = {
 	.gpio_vbus		= GPIO41_VPAC270_UDC_DETECT,
 	.gpio_pullup		= -1,
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 9a9706c..6ebdb0d 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -7,6 +7,7 @@
 	select HAS_MTU
 	select ARM_ERRATA_753970
 	select ARM_ERRATA_754322
+	select ARM_ERRATA_764369
 
 menu "Ux500 SoC"
 
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index 1da23bb..8aa104a 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -99,7 +99,27 @@
 	ux500_cache_sync();
 }
 
-static int ux500_l2x0_init(void)
+static int __init ux500_l2x0_unlock(void)
+{
+	int i;
+
+	/*
+	 * Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions
+	 * apparently locks both caches before jumping to the kernel. The
+	 * l2x0 core will not touch the unlock registers if the l2x0 is
+	 * already enabled, so we do it right here instead. The PL310 has
+	 * 8 sets of registers, one per possible CPU.
+	 */
+	for (i = 0; i < 8; i++) {
+		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
+			       i * L2X0_LOCKDOWN_STRIDE);
+		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
+			       i * L2X0_LOCKDOWN_STRIDE);
+	}
+	return 0;
+}
+
+static int __init ux500_l2x0_init(void)
 {
 	if (cpu_is_u5500())
 		l2x0_base = __io_address(U5500_L2CC_BASE);
@@ -108,6 +128,9 @@
 	else
 		ux500_unknown_soc();
 
+	/* Unlock before init */
+	ux500_l2x0_unlock();
+
 	/* 64KB way size, 8 way associativity, force WA */
 	l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
 
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index bc5ffce..8b2566a 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -17,9 +17,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -48,7 +51,7 @@
 {
 	/* wait for cache operation by line or way to complete */
 	while (readl_relaxed(reg) & mask)
-		;
+		cpu_relax();
 }
 
 #ifdef CONFIG_CACHE_PL310
@@ -484,6 +487,16 @@
 
 		/* Invalidate the cache */
 		l2x0_inv_all();
+		/*
+		 * TBD: make sure that l2xo_inv_all finished
+		 * before actually enabling the cache. Logically this
+		 * is not required as cache sync is atomic operation.
+		 * but on 8x25, observed the random crashes and they go
+		 * away if we add dmb or disable the L2.
+		 * keeping this as temporary workaround until root
+		 * cause is find out.
+		 */
+		dmb();
 	}
 
 	/* Enable the cache */
@@ -491,3 +504,103 @@
 
 	mb();
 }
+
+#ifdef CONFIG_OF
+static void __init l2x0_of_setup(const struct device_node *np,
+				 __u32 *aux_val, __u32 *aux_mask)
+{
+	u32 data[2] = { 0, 0 };
+	u32 tag = 0;
+	u32 dirty = 0;
+	u32 val = 0, mask = 0;
+
+	of_property_read_u32(np, "arm,tag-latency", &tag);
+	if (tag) {
+		mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
+		val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
+	}
+
+	of_property_read_u32_array(np, "arm,data-latency",
+				   data, ARRAY_SIZE(data));
+	if (data[0] && data[1]) {
+		mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
+			L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
+		val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
+		       ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
+	}
+
+	of_property_read_u32(np, "arm,dirty-latency", &dirty);
+	if (dirty) {
+		mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
+		val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
+	}
+
+	*aux_val &= ~mask;
+	*aux_val |= val;
+	*aux_mask &= ~mask;
+}
+
+static void __init pl310_of_setup(const struct device_node *np,
+				  __u32 *aux_val, __u32 *aux_mask)
+{
+	u32 data[3] = { 0, 0, 0 };
+	u32 tag[3] = { 0, 0, 0 };
+	u32 filter[2] = { 0, 0 };
+
+	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
+	if (tag[0] && tag[1] && tag[2])
+		writel_relaxed(
+			((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+			((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+			((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+			l2x0_base + L2X0_TAG_LATENCY_CTRL);
+
+	of_property_read_u32_array(np, "arm,data-latency",
+				   data, ARRAY_SIZE(data));
+	if (data[0] && data[1] && data[2])
+		writel_relaxed(
+			((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+			((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+			((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+			l2x0_base + L2X0_DATA_LATENCY_CTRL);
+
+	of_property_read_u32_array(np, "arm,filter-ranges",
+				   filter, ARRAY_SIZE(filter));
+	if (filter[1]) {
+		writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
+			       l2x0_base + L2X0_ADDR_FILTER_END);
+		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
+			       l2x0_base + L2X0_ADDR_FILTER_START);
+	}
+}
+
+static const struct of_device_id l2x0_ids[] __initconst = {
+	{ .compatible = "arm,pl310-cache", .data = pl310_of_setup },
+	{ .compatible = "arm,l220-cache", .data = l2x0_of_setup },
+	{ .compatible = "arm,l210-cache", .data = l2x0_of_setup },
+	{}
+};
+
+int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask)
+{
+	struct device_node *np;
+	void (*l2_setup)(const struct device_node *np,
+		__u32 *aux_val, __u32 *aux_mask);
+
+	np = of_find_matching_node(NULL, l2x0_ids);
+	if (!np)
+		return -ENODEV;
+	l2x0_base = of_iomap(np, 0);
+	if (!l2x0_base)
+		return -ENOMEM;
+
+	/* L2 configuration can only be changed if the cache is disabled */
+	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+		l2_setup = of_match_node(l2x0_ids, np)->data;
+		if (l2_setup)
+			l2_setup(np, &aux_val, &aux_mask);
+	}
+	l2x0_init(l2x0_base, aux_val, aux_mask);
+	return 0;
+}
+#endif
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/mm/context.c b/arch/arm/mm/context.c
index 14536f6..946899d 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -17,6 +17,8 @@
 #include <asm/thread_notify.h>
 #include <asm/tlbflush.h>
 
+#include <mach/msm_rtb.h>
+
 static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
 unsigned int cpu_last_asid = ASID_FIRST_VERSION;
 #ifdef CONFIG_SMP
@@ -25,6 +27,7 @@
 
 static void write_contextidr(u32 contextidr)
 {
+	uncached_logk(LOGK_CTXID, (void *)contextidr);
 	asm("mcr	p15, 0, %0, c13, c0, 1" : : "r" (contextidr));
 	isb();
 }
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index de65c4b..b514d48 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -293,10 +293,6 @@
  *	Initialise TLB, Caches, and MMU state ready to switch the MMU
  *	on.  Return in r0 the new CP15 C1 control register setting.
  *
- *	We automatically detect if we have a Harvard cache, and use the
- *	Harvard cache control instructions insead of the unified cache
- *	control instructions.
- *
  *	This should be able to cover all ARMv7 cores.
  *
  *	It is assumed that:
@@ -393,9 +389,7 @@
 #endif
 
 3:	mov	r10, #0
-#ifdef HARVARD_CACHE
 	mcr	p15, 0, r10, c7, c5, 0		@ I+BTB cache invalidate
-#endif
 	dsb
 #ifdef CONFIG_MMU
 	mcr	p15, 0, r10, c8, c7, 0		@ invalidate I + D TLBs
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index afd7afb..338e8c2 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -36,6 +36,8 @@
 		return "arm/armv6";
 	case ARM_PERF_PMU_ID_V6MP:
 		return "arm/mpcore";
+	case ARM_PERF_PMU_ID_CA5:
+		return "arm/armv7";
 	case ARM_PERF_PMU_ID_CA8:
 		return "arm/armv7";
 	case ARM_PERF_PMU_ID_CA9:
@@ -122,7 +124,7 @@
 	return oprofile_perf_init(ops);
 }
 
-void __exit oprofile_arch_exit(void)
+void oprofile_arch_exit(void)
 {
 	oprofile_perf_exit();
 }
diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h
index ebbce33..4509956 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-v3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h
@@ -89,11 +89,11 @@
 #define PAD_CTL_HYS			(1 << 8)
 
 #define PAD_CTL_PKE			(1 << 7)
-#define PAD_CTL_PUE			(1 << 6)
-#define PAD_CTL_PUS_100K_DOWN		(0 << 4)
-#define PAD_CTL_PUS_47K_UP		(1 << 4)
-#define PAD_CTL_PUS_100K_UP		(2 << 4)
-#define PAD_CTL_PUS_22K_UP		(3 << 4)
+#define PAD_CTL_PUE			(1 << 6 | PAD_CTL_PKE)
+#define PAD_CTL_PUS_100K_DOWN		(0 << 4 | PAD_CTL_PUE)
+#define PAD_CTL_PUS_47K_UP		(1 << 4 | PAD_CTL_PUE)
+#define PAD_CTL_PUS_100K_UP		(2 << 4 | PAD_CTL_PUE)
+#define PAD_CTL_PUS_22K_UP		(3 << 4 | PAD_CTL_PUE)
 
 #define PAD_CTL_ODE			(1 << 3)
 
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index 7a61ef8..f4b68be 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -32,6 +32,9 @@
 #define MX3_PWMSAR                0x0C    /* PWM Sample Register */
 #define MX3_PWMPR                 0x10    /* PWM Period Register */
 #define MX3_PWMCR_PRESCALER(x)    (((x - 1) & 0xFFF) << 4)
+#define MX3_PWMCR_DOZEEN                (1 << 24)
+#define MX3_PWMCR_WAITEN                (1 << 23)
+#define MX3_PWMCR_DBGEN			(1 << 22)
 #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
 #define MX3_PWMCR_CLKSRC_IPG      (1 << 16)
 #define MX3_PWMCR_EN              (1 << 0)
@@ -74,10 +77,21 @@
 		do_div(c, period_ns);
 		duty_cycles = c;
 
+		/*
+		 * according to imx pwm RM, the real period value should be
+		 * PERIOD value in PWMPR plus 2.
+		 */
+		if (period_cycles > 2)
+			period_cycles -= 2;
+		else
+			period_cycles = 0;
+
 		writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
 		writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
 
-		cr = MX3_PWMCR_PRESCALER(prescale) | MX3_PWMCR_EN;
+		cr = MX3_PWMCR_PRESCALER(prescale) |
+			MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
+			MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
 
 		if (cpu_is_mx25())
 			cr |= MX3_PWMCR_CLKSRC_IPG;
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
old mode 100755
new mode 100644
index 8dcce03..0ff30c3
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1136,6 +1136,10 @@
 apq8064_cdp		MACH_APQ8064_CDP	APQ8064_CDP		3948
 apq8064_mtp		MACH_APQ8064_MTP	APQ8064_MTP		3949
 apq8064_liquid		MACH_APQ8064_LIQUID	APQ8064_LIQUID		3951
+mpq8064_cdp		MACH_MPQ8064_CDP	MPQ8064_CDP		3993
 mpq8064_hrd		MACH_MPQ8064_HRD	MPQ8064_HRD		3994
 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
+msm8625_qrd7		MACH_MSM8625_QRD7	MSM8625_QRD7		4095
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 3be485a..f19de9f 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -429,22 +429,24 @@
 static struct acpi_table_slit __initdata *slit_table;
 cpumask_t early_cpu_possible_map = CPU_MASK_NONE;
 
-static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
+static int __init
+get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
 {
 	int pxm;
 
 	pxm = pa->proximity_domain_lo;
-	if (ia64_platform_is("sn2"))
+	if (ia64_platform_is("sn2") || acpi_srat_revision >= 2)
 		pxm += pa->proximity_domain_hi[0] << 8;
 	return pxm;
 }
 
-static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
+static int __init
+get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
 {
 	int pxm;
 
 	pxm = ma->proximity_domain;
-	if (!ia64_platform_is("sn2"))
+	if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1)
 		pxm &= 0xff;
 
 	return pxm;
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 6fbce72..a0f358d 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -8,7 +8,7 @@
 
 #ifdef __powerpc64__
 
-extern char _end[];
+extern char __end_interrupts[];
 
 static inline int in_kernel_text(unsigned long addr)
 {
diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h
index 54a47ea..0c5fa31 100644
--- a/arch/powerpc/include/asm/sparsemem.h
+++ b/arch/powerpc/include/asm/sparsemem.h
@@ -16,7 +16,7 @@
 #endif /* CONFIG_SPARSEMEM */
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-extern void create_section_mapping(unsigned long start, unsigned long end);
+extern int create_section_mapping(unsigned long start, unsigned long end);
 extern int remove_section_mapping(unsigned long start, unsigned long end);
 #ifdef CONFIG_NUMA
 extern int hot_add_scn_to_nid(unsigned long scn_addr);
diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h
index d7cab44..87878c6 100644
--- a/arch/powerpc/include/asm/synch.h
+++ b/arch/powerpc/include/asm/synch.h
@@ -13,6 +13,7 @@
 extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
 extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
 			     void *fixup_end);
+extern void do_final_fixups(void);
 
 static inline void eieio(void)
 {
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index fe6f7c2..bc3c745 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -219,5 +219,7 @@
 extern void secondary_cpu_time_init(void);
 extern void iSeries_time_init_early(void);
 
+extern void decrementer_check_overflow(void);
+
 #endif /* __KERNEL__ */
 #endif /* __POWERPC_TIME_H */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 5b428e3..ca2987d 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -170,16 +170,13 @@
 	 */
 	local_paca->hard_enabled = en;
 
-#ifndef CONFIG_BOOKE
-	/* On server, re-trigger the decrementer if it went negative since
-	 * some processors only trigger on edge transitions of the sign bit.
-	 *
-	 * BookE has a level sensitive decrementer (latches in TSR) so we
-	 * don't need that
+	/*
+	 * Trigger the decrementer if we have a pending event. Some processors
+	 * only trigger on edge transitions of the sign bit. We might also
+	 * have disabled interrupts long enough that the decrementer wrapped
+	 * to positive.
 	 */
-	if ((int)mfspr(SPRN_DEC) < 0)
-		mtspr(SPRN_DEC, 1);
-#endif /* CONFIG_BOOKE */
+	decrementer_check_overflow();
 
 	/*
 	 * Force the delivery of pending soft-disabled interrupts on PS3.
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index b06bdae..ad892f7 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -131,7 +131,6 @@
 	/* On relocatable kernels interrupts handlers and our code
 	   can be in different regions, so we don't patch them */
 
-	extern u32 __end_interrupts;
 	if ((ulong)inst < (ulong)&__end_interrupts)
 		return;
 #endif
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 620d792..c7e7b8c 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -107,6 +107,8 @@
 			 PTRRELOC(&__start___lwsync_fixup),
 			 PTRRELOC(&__stop___lwsync_fixup));
 
+	do_final_fixups();
+
 	return KERNELBASE + offset;
 }
 
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index a88bf27..7867fd1 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -352,6 +352,7 @@
 			  &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
 	do_lwsync_fixups(cur_cpu_spec->cpu_features,
 			 &__start___lwsync_fixup, &__stop___lwsync_fixup);
+	do_final_fixups();
 
 	/*
 	 * Unflatten the device-tree passed by prom_init or kexec
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 03b29a6..2de304a 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -889,6 +889,15 @@
 	       clock->name, clock->mult, clock->shift);
 }
 
+void decrementer_check_overflow(void)
+{
+	u64 now = get_tb_or_rtc();
+	struct decrementer_clock *decrementer = &__get_cpu_var(decrementers);
+
+	if (now >= decrementer->next_tb)
+		set_dec(1);
+}
+
 static int decrementer_set_next_event(unsigned long evt,
 				      struct clock_event_device *dev)
 {
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 0d08d01..7a8a748 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -18,6 +18,8 @@
 #include <linux/init.h>
 #include <asm/cputable.h>
 #include <asm/code-patching.h>
+#include <asm/page.h>
+#include <asm/sections.h>
 
 
 struct fixup_entry {
@@ -128,6 +130,27 @@
 	}
 }
 
+void do_final_fixups(void)
+{
+#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
+	int *src, *dest;
+	unsigned long length;
+
+	if (PHYSICAL_START == 0)
+		return;
+
+	src = (int *)(KERNELBASE + PHYSICAL_START);
+	dest = (int *)KERNELBASE;
+	length = (__end_interrupts - _stext) / sizeof(int);
+
+	while (length--) {
+		patch_instruction(dest, *src);
+		src++;
+		dest++;
+	}
+#endif
+}
+
 #ifdef CONFIG_FTR_FIXUP_SELFTEST
 
 #define check(x)	\
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
index fec1320..d7efdbf 100644
--- a/arch/powerpc/mm/gup.c
+++ b/arch/powerpc/mm/gup.c
@@ -16,16 +16,6 @@
 
 #ifdef __HAVE_ARCH_PTE_SPECIAL
 
-static inline void get_huge_page_tail(struct page *page)
-{
-	/*
-	 * __split_huge_page_refcount() cannot run
-	 * from under us.
-	 */
-	VM_BUG_ON(atomic_read(&page->_count) < 0);
-	atomic_inc(&page->_count);
-}
-
 /*
  * The performance critical leaf functions are made noinline otherwise gcc
  * inlines everything into a single function which results in too much
@@ -57,8 +47,6 @@
 			put_page(page);
 			return 0;
 		}
-		if (PageTail(page))
-			get_huge_page_tail(page);
 		pages[*nr] = page;
 		(*nr)++;
 
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 26b2872..07f9e9f 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -534,11 +534,11 @@
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-void create_section_mapping(unsigned long start, unsigned long end)
+int create_section_mapping(unsigned long start, unsigned long end)
 {
-	BUG_ON(htab_bolt_mapping(start, end, __pa(start),
+	return htab_bolt_mapping(start, end, __pa(start),
 				 pgprot_val(PAGE_KERNEL), mmu_linear_psize,
-				 mmu_kernel_ssize));
+				 mmu_kernel_ssize);
 }
 
 int remove_section_mapping(unsigned long start, unsigned long end)
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 0b9a5c1..da5eb38 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -390,7 +390,7 @@
 {
 	unsigned long mask;
 	unsigned long pte_end;
-	struct page *head, *page;
+	struct page *head, *page, *tail;
 	pte_t pte;
 	int refs;
 
@@ -413,6 +413,7 @@
 	head = pte_page(pte);
 
 	page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
+	tail = page;
 	do {
 		VM_BUG_ON(compound_head(page) != head);
 		pages[*nr] = page;
@@ -428,10 +429,20 @@
 
 	if (unlikely(pte_val(pte) != pte_val(*ptep))) {
 		/* Could be optimized better */
-		while (*nr) {
-			put_page(page);
-			(*nr)--;
-		}
+		*nr -= refs;
+		while (refs--)
+			put_page(head);
+		return 0;
+	}
+
+	/*
+	 * Any tail page need their mapcount reference taken before we
+	 * return.
+	 */
+	while (refs--) {
+		if (PageTail(tail))
+			get_huge_page_tail(tail);
+		tail++;
 	}
 
 	return 1;
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 29d4dde..278ec8e 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -123,7 +123,8 @@
 	pgdata = NODE_DATA(nid);
 
 	start = (unsigned long)__va(start);
-	create_section_mapping(start, start + size);
+	if (create_section_mapping(start, start + size))
+		return -EINVAL;
 
 	/* this should work for most non-highmem platforms */
 	zone = pgdata->node_zones;
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 3bafc3d..4ff587e 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -136,8 +136,8 @@
 	if (!mm || !acop)
 		return -EINVAL;
 
-	/* We need to make sure mm_users doesn't change */
-	down_read(&mm->mmap_sem);
+	/* The page_table_lock ensures mm_users won't change under us */
+	spin_lock(&mm->page_table_lock);
 	spin_lock(mm->context.cop_lockp);
 
 	if (mm->context.cop_pid == COP_PID_NONE) {
@@ -164,7 +164,7 @@
 
 out:
 	spin_unlock(mm->context.cop_lockp);
-	up_read(&mm->mmap_sem);
+	spin_unlock(&mm->page_table_lock);
 
 	return ret;
 }
@@ -185,8 +185,8 @@
 	if (WARN_ON_ONCE(!mm))
 		return;
 
-	/* We need to make sure mm_users doesn't change */
-	down_read(&mm->mmap_sem);
+	/* The page_table_lock ensures mm_users won't change under us */
+	spin_lock(&mm->page_table_lock);
 	spin_lock(mm->context.cop_lockp);
 
 	mm->context.acop &= ~acop;
@@ -213,7 +213,7 @@
 	}
 
 	spin_unlock(mm->context.cop_lockp);
-	up_read(&mm->mmap_sem);
+	spin_unlock(&mm->page_table_lock);
 }
 EXPORT_SYMBOL_GPL(drop_cop);
 
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 2164006..2c1ae7a 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1214,11 +1214,12 @@
 			break;
 		}
 
-		of_node_put(memory);
 		if (nid >= 0)
 			break;
 	}
 
+	of_node_put(memory);
+
 	return nid;
 }
 
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 600ed2c..1aa478b 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -88,6 +88,7 @@
 	struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
 	u64 ppe_id;
 	u64 thread_id;
+	unsigned long ipi_mask;
 };
 
 static DEFINE_PER_CPU(struct ps3_private, ps3_private);
@@ -144,7 +145,11 @@
 static void ps3_chip_eoi(struct irq_data *d)
 {
 	const struct ps3_private *pd = irq_data_get_irq_chip_data(d);
-	lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
+
+	/* non-IPIs are EOIed here. */
+
+	if (!test_bit(63 - d->irq, &pd->ipi_mask))
+		lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
 }
 
 /**
@@ -691,6 +696,16 @@
 		cpu, virq, pd->bmp.ipi_debug_brk_mask);
 }
 
+void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq)
+{
+	struct ps3_private *pd = &per_cpu(ps3_private, cpu);
+
+	set_bit(63 - virq, &pd->ipi_mask);
+
+	DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__,
+		cpu, virq, pd->ipi_mask);
+}
+
 static unsigned int ps3_get_irq(void)
 {
 	struct ps3_private *pd = &__get_cpu_var(ps3_private);
@@ -720,6 +735,12 @@
 		BUG();
 	}
 #endif
+
+	/* IPIs are EOIed here. */
+
+	if (test_bit(63 - plug, &pd->ipi_mask))
+		lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug);
+
 	return plug;
 }
 
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 9a196a8..1a633ed 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -43,6 +43,7 @@
 void ps3_init_IRQ(void);
 void ps3_shutdown_IRQ(int cpu);
 void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq);
+void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq);
 
 /* smp */
 
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 4c44794..f609345 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -94,6 +94,8 @@
 
 		if (result)
 			virqs[i] = NO_IRQ;
+		else
+			ps3_register_ipi_irq(cpu, virqs[i]);
 	}
 
 	ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]);
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 57ceb92..82766e5 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -112,6 +112,7 @@
 	dlpar_free_one_cc_node(dn);
 }
 
+#define COMPLETE	0
 #define NEXT_SIBLING    1
 #define NEXT_CHILD      2
 #define NEXT_PROPERTY   3
@@ -158,6 +159,9 @@
 		spin_unlock(&rtas_data_buf_lock);
 
 		switch (rc) {
+		case COMPLETE:
+			break;
+
 		case NEXT_SIBLING:
 			dn = dlpar_parse_cc_node(ccwa);
 			if (!dn)
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 46b55cf..3608704 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1338,7 +1338,7 @@
 static int __init eeh_init_proc(void)
 {
 	if (machine_is(pseries))
-		proc_create("ppc64/eeh", 0, NULL, &proc_eeh_operations);
+		proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations);
 	return 0;
 }
 __initcall(eeh_init_proc);
diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c
index f106662..c9311cf 100644
--- a/arch/powerpc/platforms/pseries/hvCall_inst.c
+++ b/arch/powerpc/platforms/pseries/hvCall_inst.c
@@ -109,7 +109,7 @@
 	if (opcode > MAX_HCALL_OPCODE)
 		return;
 
-	h = &get_cpu_var(hcall_stats)[opcode / 4];
+	h = &__get_cpu_var(hcall_stats)[opcode / 4];
 	h->tb_start = mftb();
 	h->purr_start = mfspr(SPRN_PURR);
 }
@@ -126,8 +126,6 @@
 	h->num_calls++;
 	h->tb_total += mftb() - h->tb_start;
 	h->purr_total += mfspr(SPRN_PURR) - h->purr_start;
-
-	put_cpu_var(hcall_stats);
 }
 
 static int __init hcall_inst_init(void)
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index ed96b37..81e30d9 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -745,6 +745,7 @@
 		goto out;
 
 	(*depth)++;
+	preempt_disable();
 	trace_hcall_entry(opcode, args);
 	(*depth)--;
 
@@ -767,6 +768,7 @@
 
 	(*depth)++;
 	trace_hcall_exit(opcode, retval, retbuf);
+	preempt_enable();
 	(*depth)--;
 
 out:
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index ef86ad2..5804cfa 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -47,29 +47,31 @@
 
 void update_per_regs(struct task_struct *task)
 {
-	static const struct per_regs per_single_step = {
-		.control = PER_EVENT_IFETCH,
-		.start = 0,
-		.end = PSW_ADDR_INSN,
-	};
 	struct pt_regs *regs = task_pt_regs(task);
 	struct thread_struct *thread = &task->thread;
-	const struct per_regs *new;
-	struct per_regs old;
+	struct per_regs old, new;
 
-	/* TIF_SINGLE_STEP overrides the user specified PER registers. */
-	new = test_tsk_thread_flag(task, TIF_SINGLE_STEP) ?
-		&per_single_step : &thread->per_user;
+	/* Copy user specified PER registers */
+	new.control = thread->per_user.control;
+	new.start = thread->per_user.start;
+	new.end = thread->per_user.end;
+
+	/* merge TIF_SINGLE_STEP into user specified PER registers. */
+	if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
+		new.control |= PER_EVENT_IFETCH;
+		new.start = 0;
+		new.end = PSW_ADDR_INSN;
+	}
 
 	/* Take care of the PER enablement bit in the PSW. */
-	if (!(new->control & PER_EVENT_MASK)) {
+	if (!(new.control & PER_EVENT_MASK)) {
 		regs->psw.mask &= ~PSW_MASK_PER;
 		return;
 	}
 	regs->psw.mask |= PSW_MASK_PER;
 	__ctl_store(old, 9, 11);
-	if (memcmp(new, &old, sizeof(struct per_regs)) != 0)
-		__ctl_load(*new, 9, 11);
+	if (memcmp(&new, &old, sizeof(struct per_regs)) != 0)
+		__ctl_load(new, 9, 11);
 }
 
 void user_enable_single_step(struct task_struct *task)
@@ -895,6 +897,14 @@
 	return 0;
 }
 
+static int s390_last_break_set(struct task_struct *target,
+			       const struct user_regset *regset,
+			       unsigned int pos, unsigned int count,
+			       const void *kbuf, const void __user *ubuf)
+{
+	return 0;
+}
+
 #endif
 
 static const struct user_regset s390_regsets[] = {
@@ -921,6 +931,7 @@
 		.size = sizeof(long),
 		.align = sizeof(long),
 		.get = s390_last_break_get,
+		.set = s390_last_break_set,
 	},
 #endif
 };
@@ -1078,6 +1089,14 @@
 	return 0;
 }
 
+static int s390_compat_last_break_set(struct task_struct *target,
+				      const struct user_regset *regset,
+				      unsigned int pos, unsigned int count,
+				      const void *kbuf, const void __user *ubuf)
+{
+	return 0;
+}
+
 static const struct user_regset s390_compat_regsets[] = {
 	[REGSET_GENERAL] = {
 		.core_note_type = NT_PRSTATUS,
@@ -1101,6 +1120,7 @@
 		.size = sizeof(long),
 		.align = sizeof(long),
 		.get = s390_compat_last_break_get,
+		.set = s390_compat_last_break_set,
 	},
 	[REGSET_GENERAL_EXTENDED] = {
 		.core_note_type = NT_S390_HIGH_GPRS,
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 67345ae..2ada634 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -301,11 +301,17 @@
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 				      unsigned int id)
 {
-	struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
-	int rc = -ENOMEM;
+	struct kvm_vcpu *vcpu;
+	int rc = -EINVAL;
 
+	if (id >= KVM_MAX_VCPUS)
+		goto out;
+
+	rc = -ENOMEM;
+
+	vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
 	if (!vcpu)
-		goto out_nomem;
+		goto out;
 
 	vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
 					get_zeroed_page(GFP_KERNEL);
@@ -341,7 +347,7 @@
 	free_page((unsigned long)(vcpu->arch.sie_block));
 out_free_cpu:
 	kfree(vcpu);
-out_nomem:
+out:
 	return ERR_PTR(rc);
 }
 
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 45b405c..65cb06e 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -52,7 +52,7 @@
 		unsigned long end, int write, struct page **pages, int *nr)
 {
 	unsigned long mask, result;
-	struct page *head, *page;
+	struct page *head, *page, *tail;
 	int refs;
 
 	result = write ? 0 : _SEGMENT_ENTRY_RO;
@@ -64,6 +64,7 @@
 	refs = 0;
 	head = pmd_page(pmd);
 	page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+	tail = page;
 	do {
 		VM_BUG_ON(compound_head(page) != head);
 		pages[*nr] = page;
@@ -81,6 +82,17 @@
 		*nr -= refs;
 		while (refs--)
 			put_page(head);
+		return 0;
+	}
+
+	/*
+	 * Any tail page need their mapcount reference taken before we
+	 * return.
+	 */
+	while (refs--) {
+		if (PageTail(tail))
+			get_huge_page_tail(tail);
+		tail++;
 	}
 
 	return 1;
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 37a23c22..458893f 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -291,8 +291,9 @@
 
 void __tlb_remove_table(void *_table)
 {
-	void *table = (void *)((unsigned long) _table & PAGE_MASK);
-	unsigned type = (unsigned long) _table & ~PAGE_MASK;
+	const unsigned long mask = (FRAG_MASK << 4) | FRAG_MASK;
+	void *table = (void *)((unsigned long) _table & ~mask);
+	unsigned type = (unsigned long) _table & mask;
 
 	if (type)
 		__page_table_free_rcu(table, type);
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c
index 0e358c2..422110a 100644
--- a/arch/s390/oprofile/init.c
+++ b/arch/s390/oprofile/init.c
@@ -90,7 +90,7 @@
 		return -EINVAL;
 
 	retval = oprofilefs_ulong_from_user(&val, buf, count);
-	if (retval)
+	if (retval <= 0)
 		return retval;
 
 	if (oprofile_started)
diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S
index 577abba..83bb960 100644
--- a/arch/score/kernel/entry.S
+++ b/arch/score/kernel/entry.S
@@ -408,7 +408,7 @@
 	sw	r9, [r0, PT_EPC]
 
 	cmpi.c	r27, __NR_syscalls 	# check syscall number
-	bgtu	illegal_syscall
+	bgeu	illegal_syscall
 
 	slli	r8, r27, 2		# get syscall routine
 	la	r11, sys_call_table
diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
index 822d608..abcc4dc 100644
--- a/arch/sh/include/asm/page.h
+++ b/arch/sh/include/asm/page.h
@@ -141,8 +141,13 @@
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_UNCACHED_MAPPING
+#if defined(CONFIG_29BIT)
+#define UNCAC_ADDR(addr)	P2SEGADDR(addr)
+#define CAC_ADDR(addr)		P1SEGADDR(addr)
+#else
 #define UNCAC_ADDR(addr)	((addr) - PAGE_OFFSET + uncached_start)
 #define CAC_ADDR(addr)		((addr) - uncached_start + PAGE_OFFSET)
+#endif
 #else
 #define UNCAC_ADDR(addr)	((addr))
 #define CAC_ADDR(addr)		((addr))
diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c
index b4c2d2b..e4dd5d5 100644
--- a/arch/sh/oprofile/common.c
+++ b/arch/sh/oprofile/common.c
@@ -49,7 +49,7 @@
 	return oprofile_perf_init(ops);
 }
 
-void __exit oprofile_arch_exit(void)
+void oprofile_arch_exit(void)
 {
 	oprofile_perf_exit();
 	kfree(sh_pmu_op_name);
@@ -60,5 +60,5 @@
 	ops->backtrace = sh_backtrace;
 	return -ENODEV;
 }
-void __exit oprofile_arch_exit(void) {}
+void oprofile_arch_exit(void) {}
 #endif /* CONFIG_HW_PERF_EVENTS */
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 5b31a8e..a790cc6 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -431,10 +431,6 @@
 #define kern_addr_valid(addr) \
 	(test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
 
-extern int io_remap_pfn_range(struct vm_area_struct *vma,
-			      unsigned long from, unsigned long pfn,
-			      unsigned long size, pgprot_t prot);
-
 /*
  * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
  * its high 4 bits.  These macros/functions put it there or get it from there.
@@ -443,6 +439,22 @@
 #define GET_IOSPACE(pfn)		(pfn >> (BITS_PER_LONG - 4))
 #define GET_PFN(pfn)			(pfn & 0x0fffffffUL)
 
+extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
+			   unsigned long, pgprot_t);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+				     unsigned long from, unsigned long pfn,
+				     unsigned long size, pgprot_t prot)
+{
+	unsigned long long offset, space, phys_base;
+
+	offset = ((unsigned long long) GET_PFN(pfn)) << PAGE_SHIFT;
+	space = GET_IOSPACE(pfn);
+	phys_base = offset | (space << 32ULL);
+
+	return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
+}
+
 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
 ({									  \
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 1e03c5a..9822628 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -750,10 +750,6 @@
 
 extern int page_in_phys_avail(unsigned long paddr);
 
-extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-			       unsigned long pfn,
-			       unsigned long size, pgprot_t prot);
-
 /*
  * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
  * its high 4 bits.  These macros/functions put it there or get it from there.
@@ -762,6 +758,22 @@
 #define GET_IOSPACE(pfn)		(pfn >> (BITS_PER_LONG - 4))
 #define GET_PFN(pfn)			(pfn & 0x0fffffffffffffffUL)
 
+extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
+			   unsigned long, pgprot_t);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+				     unsigned long from, unsigned long pfn,
+				     unsigned long size, pgprot_t prot)
+{
+	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+	int space = GET_IOSPACE(pfn);
+	unsigned long phys_base;
+
+	phys_base = offset | (((unsigned long) space) << 32UL);
+
+	return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
+}
+
 #include <asm-generic/pgtable.h>
 
 /* We provide our own get_unmapped_area to cope with VA holes and
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
index e27f8ea..0c218e4 100644
--- a/arch/sparc/kernel/entry.h
+++ b/arch/sparc/kernel/entry.h
@@ -42,6 +42,9 @@
 extern void fpload(unsigned long *fpregs, unsigned long *fsr);
 
 #else /* CONFIG_SPARC32 */
+
+#include <asm/trap_block.h>
+
 struct popc_3insn_patch_entry {
 	unsigned int	addr;
 	unsigned int	insns[3];
@@ -57,6 +60,10 @@
 	__popc_6insn_patch_end;
 
 extern void __init per_cpu_patch(void);
+extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
+				    struct sun4v_1insn_patch_entry *);
+extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *,
+				    struct sun4v_2insn_patch_entry *);
 extern void __init sun4v_patch(void);
 extern void __init boot_cpu_id_too_large(int cpu);
 extern unsigned int dcache_parity_tl1_occurred;
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index 99ba5ba..8172c18 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -17,6 +17,8 @@
 #include <asm/processor.h>
 #include <asm/spitfire.h>
 
+#include "entry.h"
+
 #ifdef CONFIG_SPARC64
 
 #include <linux/jump_label.h>
@@ -220,6 +222,29 @@
 }
 
 #ifdef CONFIG_SPARC64
+static void do_patch_sections(const Elf_Ehdr *hdr,
+			      const Elf_Shdr *sechdrs)
+{
+	const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL;
+	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+		if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name))
+			sun4v_1insn = s;
+		if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name))
+			sun4v_2insn = s;
+	}
+
+	if (sun4v_1insn && tlb_type == hypervisor) {
+		void *p = (void *) sun4v_1insn->sh_addr;
+		sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size);
+	}
+	if (sun4v_2insn && tlb_type == hypervisor) {
+		void *p = (void *) sun4v_2insn->sh_addr;
+		sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size);
+	}
+}
+
 int module_finalize(const Elf_Ehdr *hdr,
 		    const Elf_Shdr *sechdrs,
 		    struct module *me)
@@ -227,6 +252,8 @@
 	/* make jump label nops */
 	jump_label_apply_nops(me);
 
+	do_patch_sections(hdr, sechdrs);
+
 	/* Cheetah's I-cache is fully coherent.  */
 	if (tlb_type == spitfire) {
 		unsigned long va;
diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c
index b01a06e..9e73c4a 100644
--- a/arch/sparc/kernel/pci_sun4v.c
+++ b/arch/sparc/kernel/pci_sun4v.c
@@ -848,10 +848,10 @@
 	if (!irq)
 		return -ENOMEM;
 
-	if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
-		return -EINVAL;
 	if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
 		return -EINVAL;
+	if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
+		return -EINVAL;
 
 	return irq;
 }
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 3c5bb78..4e7d3ff 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -234,40 +234,50 @@
 	}
 }
 
+void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start,
+			     struct sun4v_1insn_patch_entry *end)
+{
+	while (start < end) {
+		unsigned long addr = start->addr;
+
+		*(unsigned int *) (addr +  0) = start->insn;
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
+
+		start++;
+	}
+}
+
+void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
+			     struct sun4v_2insn_patch_entry *end)
+{
+	while (start < end) {
+		unsigned long addr = start->addr;
+
+		*(unsigned int *) (addr +  0) = start->insns[0];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
+
+		*(unsigned int *) (addr +  4) = start->insns[1];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  4));
+
+		start++;
+	}
+}
+
 void __init sun4v_patch(void)
 {
 	extern void sun4v_hvapi_init(void);
-	struct sun4v_1insn_patch_entry *p1;
-	struct sun4v_2insn_patch_entry *p2;
 
 	if (tlb_type != hypervisor)
 		return;
 
-	p1 = &__sun4v_1insn_patch;
-	while (p1 < &__sun4v_1insn_patch_end) {
-		unsigned long addr = p1->addr;
+	sun4v_patch_1insn_range(&__sun4v_1insn_patch,
+				&__sun4v_1insn_patch_end);
 
-		*(unsigned int *) (addr +  0) = p1->insn;
-		wmb();
-		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
-
-		p1++;
-	}
-
-	p2 = &__sun4v_2insn_patch;
-	while (p2 < &__sun4v_2insn_patch_end) {
-		unsigned long addr = p2->addr;
-
-		*(unsigned int *) (addr +  0) = p2->insns[0];
-		wmb();
-		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
-
-		*(unsigned int *) (addr +  4) = p2->insns[1];
-		wmb();
-		__asm__ __volatile__("flush	%0" : : "r" (addr +  4));
-
-		p2++;
-	}
+	sun4v_patch_2insn_range(&__sun4v_2insn_patch,
+				&__sun4v_2insn_patch_end);
 
 	sun4v_hvapi_init();
 }
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 5d92488..2e58328 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -829,21 +829,23 @@
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-void do_signal32(sigset_t *oldset, struct pt_regs * regs,
-		 int restart_syscall, unsigned long orig_i0)
+void do_signal32(sigset_t *oldset, struct pt_regs * regs)
 {
 	struct k_sigaction ka;
+	unsigned long orig_i0;
+	int restart_syscall;
 	siginfo_t info;
 	int signr;
 	
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
-	/* If the debugger messes with the program counter, it clears
-	 * the "in syscall" bit, directing us to not perform a syscall
-	 * restart.
-	 */
-	if (restart_syscall && !pt_regs_is_syscall(regs))
-		restart_syscall = 0;
+	restart_syscall = 0;
+	orig_i0 = 0;
+	if (pt_regs_is_syscall(regs) &&
+	    (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
+		restart_syscall = 1;
+		orig_i0 = regs->u_regs[UREG_G6];
+	}
 
 	if (signr > 0) {
 		if (restart_syscall)
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 04ede8f..2302567 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -525,10 +525,26 @@
 	siginfo_t info;
 	int signr;
 
+	/* It's a lot of work and synchronization to add a new ptrace
+	 * register for GDB to save and restore in order to get
+	 * orig_i0 correct for syscall restarts when debugging.
+	 *
+	 * Although it should be the case that most of the global
+	 * registers are volatile across a system call, glibc already
+	 * depends upon that fact that we preserve them.  So we can't
+	 * just use any global register to save away the orig_i0 value.
+	 *
+	 * In particular %g2, %g3, %g4, and %g5 are all assumed to be
+	 * preserved across a system call trap by various pieces of
+	 * code in glibc.
+	 *
+	 * %g7 is used as the "thread register".   %g6 is not used in
+	 * any fixed manner.  %g6 is used as a scratch register and
+	 * a compiler temporary, but it's value is never used across
+	 * a system call.  Therefore %g6 is usable for orig_i0 storage.
+	 */
 	if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
-		restart_syscall = 1;
-	else
-		restart_syscall = 0;
+		regs->u_regs[UREG_G6] = orig_i0;
 
 	if (test_thread_flag(TIF_RESTORE_SIGMASK))
 		oldset = &current->saved_sigmask;
@@ -541,8 +557,12 @@
 	 * the software "in syscall" bit, directing us to not perform
 	 * a syscall restart.
 	 */
-	if (restart_syscall && !pt_regs_is_syscall(regs))
-		restart_syscall = 0;
+	restart_syscall = 0;
+	if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) {
+		restart_syscall = 1;
+		orig_i0 = regs->u_regs[UREG_G6];
+	}
+
 
 	if (signr > 0) {
 		if (restart_syscall)
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 47509df..d58260b 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -535,11 +535,27 @@
 	siginfo_t info;
 	int signr;
 	
+	/* It's a lot of work and synchronization to add a new ptrace
+	 * register for GDB to save and restore in order to get
+	 * orig_i0 correct for syscall restarts when debugging.
+	 *
+	 * Although it should be the case that most of the global
+	 * registers are volatile across a system call, glibc already
+	 * depends upon that fact that we preserve them.  So we can't
+	 * just use any global register to save away the orig_i0 value.
+	 *
+	 * In particular %g2, %g3, %g4, and %g5 are all assumed to be
+	 * preserved across a system call trap by various pieces of
+	 * code in glibc.
+	 *
+	 * %g7 is used as the "thread register".   %g6 is not used in
+	 * any fixed manner.  %g6 is used as a scratch register and
+	 * a compiler temporary, but it's value is never used across
+	 * a system call.  Therefore %g6 is usable for orig_i0 storage.
+	 */
 	if (pt_regs_is_syscall(regs) &&
-	    (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
-		restart_syscall = 1;
-	} else
-		restart_syscall = 0;
+	    (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+		regs->u_regs[UREG_G6] = orig_i0;
 
 	if (current_thread_info()->status & TS_RESTORE_SIGMASK)
 		oldset = &current->saved_sigmask;
@@ -548,22 +564,20 @@
 
 #ifdef CONFIG_COMPAT
 	if (test_thread_flag(TIF_32BIT)) {
-		extern void do_signal32(sigset_t *, struct pt_regs *,
-					int restart_syscall,
-					unsigned long orig_i0);
-		do_signal32(oldset, regs, restart_syscall, orig_i0);
+		extern void do_signal32(sigset_t *, struct pt_regs *);
+		do_signal32(oldset, regs);
 		return;
 	}
 #endif	
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
-	/* If the debugger messes with the program counter, it clears
-	 * the software "in syscall" bit, directing us to not perform
-	 * a syscall restart.
-	 */
-	if (restart_syscall && !pt_regs_is_syscall(regs))
-		restart_syscall = 0;
+	restart_syscall = 0;
+	if (pt_regs_is_syscall(regs) &&
+	    (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
+		restart_syscall = 1;
+		orig_i0 = regs->u_regs[UREG_G6];
+	}
 
 	if (signr > 0) {
 		if (restart_syscall)
diff --git a/arch/sparc/kernel/visemul.c b/arch/sparc/kernel/visemul.c
index 3635771..9384a0c 100644
--- a/arch/sparc/kernel/visemul.c
+++ b/arch/sparc/kernel/visemul.c
@@ -713,17 +713,17 @@
 			s16 b = (rs2 >> (i * 16)) & 0xffff;
 
 			if (a > b)
-				rd_val |= 1 << i;
+				rd_val |= 8 >> i;
 		}
 		break;
 
 	case FCMPGT32_OPF:
 		for (i = 0; i < 2; i++) {
-			s32 a = (rs1 >> (i * 32)) & 0xffff;
-			s32 b = (rs2 >> (i * 32)) & 0xffff;
+			s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+			s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
 			if (a > b)
-				rd_val |= 1 << i;
+				rd_val |= 2 >> i;
 		}
 		break;
 
@@ -733,17 +733,17 @@
 			s16 b = (rs2 >> (i * 16)) & 0xffff;
 
 			if (a <= b)
-				rd_val |= 1 << i;
+				rd_val |= 8 >> i;
 		}
 		break;
 
 	case FCMPLE32_OPF:
 		for (i = 0; i < 2; i++) {
-			s32 a = (rs1 >> (i * 32)) & 0xffff;
-			s32 b = (rs2 >> (i * 32)) & 0xffff;
+			s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+			s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
 			if (a <= b)
-				rd_val |= 1 << i;
+				rd_val |= 2 >> i;
 		}
 		break;
 
@@ -753,17 +753,17 @@
 			s16 b = (rs2 >> (i * 16)) & 0xffff;
 
 			if (a != b)
-				rd_val |= 1 << i;
+				rd_val |= 8 >> i;
 		}
 		break;
 
 	case FCMPNE32_OPF:
 		for (i = 0; i < 2; i++) {
-			s32 a = (rs1 >> (i * 32)) & 0xffff;
-			s32 b = (rs2 >> (i * 32)) & 0xffff;
+			s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+			s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
 			if (a != b)
-				rd_val |= 1 << i;
+				rd_val |= 2 >> i;
 		}
 		break;
 
@@ -773,17 +773,17 @@
 			s16 b = (rs2 >> (i * 16)) & 0xffff;
 
 			if (a == b)
-				rd_val |= 1 << i;
+				rd_val |= 8 >> i;
 		}
 		break;
 
 	case FCMPEQ32_OPF:
 		for (i = 0; i < 2; i++) {
-			s32 a = (rs1 >> (i * 32)) & 0xffff;
-			s32 b = (rs2 >> (i * 32)) & 0xffff;
+			s32 a = (rs1 >> (i * 32)) & 0xffffffff;
+			s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 
 			if (a == b)
-				rd_val |= 1 << i;
+				rd_val |= 2 >> i;
 		}
 		break;
 	}
diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S
index 34fe657..4d8c497 100644
--- a/arch/sparc/lib/memcpy.S
+++ b/arch/sparc/lib/memcpy.S
@@ -7,40 +7,12 @@
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
-#ifdef __KERNEL__
-
-#define FUNC(x) 											\
+#define FUNC(x) 		\
 	.globl	x;		\
 	.type	x,@function;	\
-	.align	4;											\
+	.align	4;		\
 x:
 
-#undef FASTER_REVERSE
-#undef FASTER_NONALIGNED
-#define FASTER_ALIGNED
-
-/* In kernel these functions don't return a value.
- * One should use macros in asm/string.h for that purpose.
- * We return 0, so that bugs are more apparent.
- */
-#define SETUP_RETL
-#define RETL_INSN	clr	%o0
-
-#else
-
-/* libc */
-
-#include "DEFS.h"
-
-#define FASTER_REVERSE
-#define FASTER_NONALIGNED
-#define FASTER_ALIGNED
-
-#define SETUP_RETL	mov	%o0, %g6
-#define RETL_INSN	mov	%g6, %o0
-
-#endif
-
 /* Both these macros have to start with exactly the same insn */
 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
 	ldd	[%src + (offset) + 0x00], %t0; \
@@ -164,30 +136,6 @@
 	.text
 	.align	4
 
-#ifdef FASTER_REVERSE
-
-70:	/* rdword_align */
-
-	andcc		%o1, 1, %g0
-	be		4f
-	 andcc		%o1, 2, %g0
-
-	ldub		[%o1 - 1], %g2
-	sub		%o1, 1, %o1
-	stb		%g2, [%o0 - 1]
-	sub		%o2, 1, %o2
-	be		3f
-	 sub		%o0, 1, %o0
-4:
-	lduh		[%o1 - 2], %g2
-	sub		%o1, 2, %o1
-	sth		%g2, [%o0 - 2]
-	sub		%o2, 2, %o2
-	b		3f
-	 sub		%o0, 2, %o0
-
-#endif /* FASTER_REVERSE */
-
 0:
 	retl
 	 nop		! Only bcopy returns here and it retuns void...
@@ -198,7 +146,7 @@
 #endif
 FUNC(memmove)
 	cmp		%o0, %o1
-	SETUP_RETL
+	mov		%o0, %g7
 	bleu		9f
 	 sub		%o0, %o1, %o4
 
@@ -207,8 +155,6 @@
 	bleu		0f
 	 andcc		%o4, 3, %o5
 
-#ifndef FASTER_REVERSE
-
 	add		%o1, %o2, %o1
 	add		%o0, %o2, %o0
 	sub		%o1, 1, %o1
@@ -224,295 +170,7 @@
 	 sub		%o0, 1, %o0
 
 	retl
-	 RETL_INSN
-
-#else /* FASTER_REVERSE */
-
-	add		%o1, %o2, %o1
-	add		%o0, %o2, %o0
-	bne		77f
-	 cmp		%o2, 15
-	bleu		91f
-	 andcc		%o1, 3, %g0
-	bne		70b
-3:
-	 andcc		%o1, 4, %g0
-
-	be		2f
-	 mov		%o2, %g1
-
-	ld		[%o1 - 4], %o4
-	sub		%g1, 4, %g1
-	st		%o4, [%o0 - 4]
-	sub		%o1, 4, %o1
-	sub		%o0, 4, %o0
-2:
-	andcc		%g1, 0xffffff80, %g7
-	be		3f
-	 andcc		%o0, 4, %g0
-
-	be		74f + 4
-5:
-	RMOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-	RMOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-	RMOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-	RMOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-	subcc		%g7, 128, %g7
-	sub		%o1, 128, %o1
-	bne		5b
-	 sub		%o0, 128, %o0
-3:
-	andcc		%g1, 0x70, %g7
-	be		72f
-	 andcc		%g1, 8, %g0
-
-	sethi		%hi(72f), %o5
-	srl		%g7, 1, %o4
-	add		%g7, %o4, %o4
-	sub		%o1, %g7, %o1
-	sub		%o5, %o4, %o5
-	jmpl		%o5 + %lo(72f), %g0
-	 sub		%o0, %g7, %o0
-
-71:	/* rmemcpy_table */
-	RMOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
-	RMOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
-	RMOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
-	RMOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
-	RMOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
-	RMOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
-	RMOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-
-72:	/* rmemcpy_table_end */
-
-	be		73f
-	 andcc		%g1, 4, %g0
-
-	ldd		[%o1 - 0x08], %g2
-	sub		%o0, 8, %o0
-	sub		%o1, 8, %o1
-	st		%g2, [%o0]
-	st		%g3, [%o0 + 0x04]
-
-73:	/* rmemcpy_last7 */
-
-	be		1f
-	 andcc		%g1, 2, %g0
-
-	ld		[%o1 - 4], %g2
-	sub		%o1, 4, %o1
-	st		%g2, [%o0 - 4]
-	sub		%o0, 4, %o0
-1:
-	be		1f
-	 andcc		%g1, 1, %g0
-
-	lduh		[%o1 - 2], %g2
-	sub		%o1, 2, %o1
-	sth		%g2, [%o0 - 2]
-	sub		%o0, 2, %o0
-1:
-	be		1f
-	 nop
-
-	ldub		[%o1 - 1], %g2
-	stb		%g2, [%o0 - 1]
-1:
-	retl
- 	 RETL_INSN
-
-74:	/* rldd_std */
-	RMOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-	RMOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-	RMOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-	RMOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-	subcc		%g7, 128, %g7
-	sub		%o1, 128, %o1
-	bne		74b
-	 sub		%o0, 128, %o0
-
-	andcc		%g1, 0x70, %g7
-	be		72b
-	 andcc		%g1, 8, %g0
-
-	sethi		%hi(72b), %o5
-	srl		%g7, 1, %o4
-	add		%g7, %o4, %o4
-	sub		%o1, %g7, %o1
-	sub		%o5, %o4, %o5
-	jmpl		%o5 + %lo(72b), %g0
-	 sub		%o0, %g7, %o0
-
-75:	/* rshort_end */
-
-	and		%o2, 0xe, %o3
-2:
-	sethi		%hi(76f), %o5
-	sll		%o3, 3, %o4
-	sub		%o0, %o3, %o0
-	sub		%o5, %o4, %o5
-	sub		%o1, %o3, %o1
-	jmpl		%o5 + %lo(76f), %g0
-	 andcc		%o2, 1, %g0
-
-	RMOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
-	RMOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
-	RMOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
-	RMOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
-	RMOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
-	RMOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
-	RMOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
-
-76:	/* rshort_table_end */
-
-	be		1f
-	 nop
-	ldub		[%o1 - 1], %g2
-	stb		%g2, [%o0 - 1]
-1:
-	retl
- 	 RETL_INSN
-
-91:	/* rshort_aligned_end */
-
-	bne		75b
-	 andcc		%o2, 8, %g0
-
-	be		1f
-	 andcc		%o2, 4, %g0
-
-	ld		[%o1 - 0x08], %g2
-	ld		[%o1 - 0x04], %g3
-	sub		%o1, 8, %o1
-	st		%g2, [%o0 - 0x08]
-	st		%g3, [%o0 - 0x04]
-	sub		%o0, 8, %o0
-1:
-	b		73b
-	 mov		%o2, %g1
-
-77:	/* rnon_aligned */
-	cmp		%o2, 15
-	bleu		75b
-	 andcc		%o0, 3, %g0
-	be		64f
-	 andcc		%o0, 1, %g0
-	be		63f
-	 andcc		%o0, 2, %g0
-	ldub		[%o1 - 1], %g5
-	sub		%o1, 1, %o1
-	stb		%g5, [%o0 - 1]
-	sub		%o0, 1, %o0
-	be		64f
-	 sub		%o2, 1, %o2
-63:
-	ldub		[%o1 - 1], %g5
-	sub		%o1, 2, %o1
-	stb		%g5, [%o0 - 1]
-	sub		%o0, 2, %o0
-	ldub		[%o1], %g5
-	sub		%o2, 2, %o2
-	stb		%g5, [%o0]
-64:	
-	and		%o1, 3, %g2
-	and		%o1, -4, %o1
-	and		%o2, 0xc, %g3
-	add		%o1, 4, %o1
-	cmp		%g3, 4
-	sll		%g2, 3, %g4
-	mov		32, %g2
-	be		4f
-	 sub		%g2, %g4, %g7
-
-	blu		3f
-	 cmp		%g3, 8
-
-	be		2f
-	 srl		%o2, 2, %g3
-
-	ld		[%o1 - 4], %o3
-	add		%o0, -8, %o0
-	ld		[%o1 - 8], %o4
-	add		%o1, -16, %o1
-	b		7f
-	 add		%g3, 1, %g3
-2:
-	ld		[%o1 - 4], %o4
-	add		%o0, -4, %o0
-	ld		[%o1 - 8], %g1
-	add		%o1, -12, %o1
-	b		8f
-	 add		%g3, 2, %g3
-3:
-	ld		[%o1 - 4], %o5
-	add		%o0, -12, %o0
-	ld		[%o1 - 8], %o3
-	add		%o1, -20, %o1
-	b		6f
-	 srl		%o2, 2, %g3
-4:
-	ld		[%o1 - 4], %g1
-	srl		%o2, 2, %g3
-	ld		[%o1 - 8], %o5
-	add		%o1, -24, %o1
-	add		%o0, -16, %o0
-	add		%g3, -1, %g3
-
-	ld		[%o1 + 12], %o3
-5:
-	sll		%o5, %g4, %g2
-	srl		%g1, %g7, %g5
-	or		%g2, %g5, %g2
-	st		%g2, [%o0 + 12]
-6:
-	ld		[%o1 + 8], %o4
-	sll		%o3, %g4, %g2
-	srl		%o5, %g7, %g5
-	or		%g2, %g5, %g2
-	st		%g2, [%o0 + 8]
-7:
-	ld		[%o1 + 4], %g1
-	sll		%o4, %g4, %g2
-	srl		%o3, %g7, %g5
-	or		%g2, %g5, %g2
-	st		%g2, [%o0 + 4]
-8:
-	ld		[%o1], %o5
-	sll		%g1, %g4, %g2
-	srl		%o4, %g7, %g5
-	addcc		%g3, -4, %g3
-	or		%g2, %g5, %g2
-	add		%o1, -16, %o1
-	st		%g2, [%o0]
-	add		%o0, -16, %o0
-	bne,a		5b	
-	 ld		[%o1 + 12], %o3
-	sll		%o5, %g4, %g2
-	srl		%g1, %g7, %g5
-	srl		%g4, 3, %g3
-	or		%g2, %g5, %g2
-	add		%o1, %g3, %o1
-	andcc		%o2, 2, %g0
-	st		%g2, [%o0 + 12]
-	be		1f
-	 andcc		%o2, 1, %g0
-	
-	ldub		[%o1 + 15], %g5
-	add		%o1, -2, %o1
-	stb		%g5, [%o0 + 11]
-	add		%o0, -2, %o0
-	ldub		[%o1 + 16], %g5
-	stb		%g5, [%o0 + 12]
-1:
-	be		1f
-	 nop
-	ldub		[%o1 + 15], %g5
-	stb		%g5, [%o0 + 11]
-1:
-	retl
-	 RETL_INSN
-
-#endif /* FASTER_REVERSE */
+	 mov		%g7, %o0
 
 /* NOTE: This code is executed just for the cases,
          where %src (=%o1) & 3 is != 0.
@@ -546,7 +204,7 @@
 FUNC(memcpy)	/* %o0=dst %o1=src %o2=len */
 
 	sub		%o0, %o1, %o4
-	SETUP_RETL
+	mov		%o0, %g7
 9:
 	andcc		%o4, 3, %o5
 0:
@@ -569,7 +227,7 @@
 	add		%o1, 4, %o1
 	add		%o0, 4, %o0
 2:
-	andcc		%g1, 0xffffff80, %g7
+	andcc		%g1, 0xffffff80, %g0
 	be		3f
 	 andcc		%o0, 4, %g0
 
@@ -579,22 +237,23 @@
 	MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-	subcc		%g7, 128, %g7
+	sub		%g1, 128, %g1
 	add		%o1, 128, %o1
-	bne		5b
+	cmp		%g1, 128
+	bge		5b
 	 add		%o0, 128, %o0
 3:
-	andcc		%g1, 0x70, %g7
+	andcc		%g1, 0x70, %g4
 	be		80f
 	 andcc		%g1, 8, %g0
 
 	sethi		%hi(80f), %o5
-	srl		%g7, 1, %o4
-	add		%g7, %o4, %o4
-	add		%o1, %g7, %o1
+	srl		%g4, 1, %o4
+	add		%g4, %o4, %o4
+	add		%o1, %g4, %o1
 	sub		%o5, %o4, %o5
 	jmpl		%o5 + %lo(80f), %g0
-	 add		%o0, %g7, %o0
+	 add		%o0, %g4, %o0
 
 79:	/* memcpy_table */
 
@@ -641,43 +300,28 @@
 	stb		%g2, [%o0]
 1:
 	retl
- 	 RETL_INSN
+	 mov		%g7, %o0
 
 82:	/* ldd_std */
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-	subcc		%g7, 128, %g7
+	subcc		%g1, 128, %g1
 	add		%o1, 128, %o1
-	bne		82b
+	cmp		%g1, 128
+	bge		82b
 	 add		%o0, 128, %o0
 
-#ifndef FASTER_ALIGNED
-
-	andcc		%g1, 0x70, %g7
-	be		80b
-	 andcc		%g1, 8, %g0
-
-	sethi		%hi(80b), %o5
-	srl		%g7, 1, %o4
-	add		%g7, %o4, %o4
-	add		%o1, %g7, %o1
-	sub		%o5, %o4, %o5
-	jmpl		%o5 + %lo(80b), %g0
-	 add		%o0, %g7, %o0
-
-#else /* FASTER_ALIGNED */
-
-	andcc		%g1, 0x70, %g7
+	andcc		%g1, 0x70, %g4
 	be		84f
 	 andcc		%g1, 8, %g0
 
 	sethi		%hi(84f), %o5
-	add		%o1, %g7, %o1
-	sub		%o5, %g7, %o5
+	add		%o1, %g4, %o1
+	sub		%o5, %g4, %o5
 	jmpl		%o5 + %lo(84f), %g0
-	 add		%o0, %g7, %o0
+	 add		%o0, %g4, %o0
 
 83:	/* amemcpy_table */
 
@@ -721,382 +365,132 @@
 	stb		%g2, [%o0]
 1:
 	retl
- 	 RETL_INSN
-
-#endif /* FASTER_ALIGNED */
+	 mov		%g7, %o0
 
 86:	/* non_aligned */
 	cmp		%o2, 6
 	bleu		88f
+	 nop
 
-#ifdef FASTER_NONALIGNED
-
-	 cmp		%o2, 256
-	bcc		87f
-
-#endif /* FASTER_NONALIGNED */
-
-	 andcc		%o0, 3, %g0
+	save		%sp, -96, %sp
+	andcc		%i0, 3, %g0
 	be		61f
-	 andcc		%o0, 1, %g0
+	 andcc		%i0, 1, %g0
 	be		60f
-	 andcc		%o0, 2, %g0
+	 andcc		%i0, 2, %g0
 
-	ldub		[%o1], %g5
-	add		%o1, 1, %o1
-	stb		%g5, [%o0]
-	sub		%o2, 1, %o2
+	ldub		[%i1], %g5
+	add		%i1, 1, %i1
+	stb		%g5, [%i0]
+	sub		%i2, 1, %i2
 	bne		61f
-	 add		%o0, 1, %o0
+	 add		%i0, 1, %i0
 60:
-	ldub		[%o1], %g3
-	add		%o1, 2, %o1
-	stb		%g3, [%o0]
-	sub		%o2, 2, %o2
-	ldub		[%o1 - 1], %g3
-	add		%o0, 2, %o0
-	stb		%g3, [%o0 - 1]
+	ldub		[%i1], %g3
+	add		%i1, 2, %i1
+	stb		%g3, [%i0]
+	sub		%i2, 2, %i2
+	ldub		[%i1 - 1], %g3
+	add		%i0, 2, %i0
+	stb		%g3, [%i0 - 1]
 61:
-	and		%o1, 3, %g2
-	and		%o2, 0xc, %g3
-	and		%o1, -4, %o1
+	and		%i1, 3, %g2
+	and		%i2, 0xc, %g3
+	and		%i1, -4, %i1
 	cmp		%g3, 4
 	sll		%g2, 3, %g4
 	mov		32, %g2
 	be		4f
-	 sub		%g2, %g4, %g7
+	 sub		%g2, %g4, %l0
 	
 	blu		3f
 	 cmp		%g3, 0x8
 
 	be		2f
-	 srl		%o2, 2, %g3
+	 srl		%i2, 2, %g3
 
-	ld		[%o1], %o3
-	add		%o0, -8, %o0
-	ld		[%o1 + 4], %o4
+	ld		[%i1], %i3
+	add		%i0, -8, %i0
+	ld		[%i1 + 4], %i4
 	b		8f
 	 add		%g3, 1, %g3
 2:
-	ld		[%o1], %o4
-	add		%o0, -12, %o0
-	ld		[%o1 + 4], %o5
+	ld		[%i1], %i4
+	add		%i0, -12, %i0
+	ld		[%i1 + 4], %i5
 	add		%g3, 2, %g3
 	b		9f
-	 add		%o1, -4, %o1
+	 add		%i1, -4, %i1
 3:
-	ld		[%o1], %g1
-	add		%o0, -4, %o0
-	ld		[%o1 + 4], %o3
-	srl		%o2, 2, %g3
+	ld		[%i1], %g1
+	add		%i0, -4, %i0
+	ld		[%i1 + 4], %i3
+	srl		%i2, 2, %g3
 	b		7f
-	 add		%o1, 4, %o1
+	 add		%i1, 4, %i1
 4:
-	ld		[%o1], %o5
-	cmp		%o2, 7
-	ld		[%o1 + 4], %g1
-	srl		%o2, 2, %g3
+	ld		[%i1], %i5
+	cmp		%i2, 7
+	ld		[%i1 + 4], %g1
+	srl		%i2, 2, %g3
 	bleu		10f
-	 add		%o1, 8, %o1
+	 add		%i1, 8, %i1
 
-	ld		[%o1], %o3
+	ld		[%i1], %i3
 	add		%g3, -1, %g3
 5:
-	sll		%o5, %g4, %g2
-	srl		%g1, %g7, %g5
+	sll		%i5, %g4, %g2
+	srl		%g1, %l0, %g5
 	or		%g2, %g5, %g2
-	st		%g2, [%o0]
+	st		%g2, [%i0]
 7:
-	ld		[%o1 + 4], %o4
+	ld		[%i1 + 4], %i4
 	sll		%g1, %g4, %g2
-	srl		%o3, %g7, %g5
+	srl		%i3, %l0, %g5
 	or		%g2, %g5, %g2
-	st		%g2, [%o0 + 4]
+	st		%g2, [%i0 + 4]
 8:
-	ld		[%o1 + 8], %o5
-	sll		%o3, %g4, %g2
-	srl		%o4, %g7, %g5
+	ld		[%i1 + 8], %i5
+	sll		%i3, %g4, %g2
+	srl		%i4, %l0, %g5
 	or		%g2, %g5, %g2
-	st		%g2, [%o0 + 8]
+	st		%g2, [%i0 + 8]
 9:
-	ld		[%o1 + 12], %g1
-	sll		%o4, %g4, %g2
-	srl		%o5, %g7, %g5
+	ld		[%i1 + 12], %g1
+	sll		%i4, %g4, %g2
+	srl		%i5, %l0, %g5
 	addcc		%g3, -4, %g3
 	or		%g2, %g5, %g2
-	add		%o1, 16, %o1
-	st		%g2, [%o0 + 12]
-	add		%o0, 16, %o0
+	add		%i1, 16, %i1
+	st		%g2, [%i0 + 12]
+	add		%i0, 16, %i0
 	bne,a		5b
-	 ld		[%o1], %o3
+	 ld		[%i1], %i3
 10:
-	sll		%o5, %g4, %g2
-	srl		%g1, %g7, %g5
-	srl		%g7, 3, %g3
+	sll		%i5, %g4, %g2
+	srl		%g1, %l0, %g5
+	srl		%l0, 3, %g3
 	or		%g2, %g5, %g2
-	sub		%o1, %g3, %o1
-	andcc		%o2, 2, %g0
-	st		%g2, [%o0]
+	sub		%i1, %g3, %i1
+	andcc		%i2, 2, %g0
+	st		%g2, [%i0]
 	be		1f
-	 andcc		%o2, 1, %g0
+	 andcc		%i2, 1, %g0
 
-	ldub		[%o1], %g2
-	add		%o1, 2, %o1
-	stb		%g2, [%o0 + 4]
-	add		%o0, 2, %o0
-	ldub		[%o1 - 1], %g2
-	stb		%g2, [%o0 + 3]
+	ldub		[%i1], %g2
+	add		%i1, 2, %i1
+	stb		%g2, [%i0 + 4]
+	add		%i0, 2, %i0
+	ldub		[%i1 - 1], %g2
+	stb		%g2, [%i0 + 3]
 1:
 	be		1f
 	 nop
-	ldub		[%o1], %g2
-	stb		%g2, [%o0 + 4]
+	ldub		[%i1], %g2
+	stb		%g2, [%i0 + 4]
 1:
-	retl
-	 RETL_INSN
-
-#ifdef FASTER_NONALIGNED
-
-87:	/* faster_nonaligned */
-
-	andcc		%o1, 3, %g0
-	be		3f
-	 andcc		%o1, 1, %g0
-
-	be		4f
-	 andcc		%o1, 2, %g0
-
-	ldub		[%o1], %g2
-	add		%o1, 1, %o1
-	stb		%g2, [%o0]
-	sub		%o2, 1, %o2
-	bne		3f
-	 add		%o0, 1, %o0
-4:
-	lduh		[%o1], %g2
-	add		%o1, 2, %o1
-	srl		%g2, 8, %g3
-	sub		%o2, 2, %o2
-	stb		%g3, [%o0]
-	add		%o0, 2, %o0
-	stb		%g2, [%o0 - 1]
-3:
-	 andcc		%o1, 4, %g0
-
-	bne		2f
-	 cmp		%o5, 1
-
-	ld		[%o1], %o4
-	srl		%o4, 24, %g2
-	stb		%g2, [%o0]
-	srl		%o4, 16, %g3
-	stb		%g3, [%o0 + 1]
-	srl		%o4, 8, %g2
-	stb		%g2, [%o0 + 2]
-	sub		%o2, 4, %o2
-	stb		%o4, [%o0 + 3]
-	add		%o1, 4, %o1
-	add		%o0, 4, %o0
-2:
-	be		33f
-	 cmp		%o5, 2
-	be		32f
-	 sub		%o2, 4, %o2
-31:
-	ld		[%o1], %g2
-	add		%o1, 4, %o1
-	srl		%g2, 24, %g3
-	and		%o0, 7, %g5
-	stb		%g3, [%o0]
-	cmp		%g5, 7
-	sll		%g2, 8, %g1
-	add		%o0, 4, %o0
-	be		41f
-	 and		%o2, 0xffffffc0, %o3
-	ld		[%o0 - 7], %o4
-4:
-	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	subcc		%o3, 64, %o3
-	add		%o1, 64, %o1
-	bne		4b
-	 add		%o0, 64, %o0
-
-	andcc		%o2, 0x30, %o3
-	be,a		1f
-	 srl		%g1, 16, %g2
-4:
-	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	subcc		%o3, 16, %o3
-	add		%o1, 16, %o1
-	bne		4b
-	 add		%o0, 16, %o0
-
-	srl		%g1, 16, %g2
-1:
-	st		%o4, [%o0 - 7]
-	sth		%g2, [%o0 - 3]
-	srl		%g1, 8, %g4
-	b		88f
-	 stb		%g4, [%o0 - 1]
-32:
-	ld		[%o1], %g2
-	add		%o1, 4, %o1
-	srl		%g2, 16, %g3
-	and		%o0, 7, %g5
-	sth		%g3, [%o0]
-	cmp		%g5, 6
-	sll		%g2, 16, %g1
-	add		%o0, 4, %o0
-	be		42f
-	 and		%o2, 0xffffffc0, %o3
-	ld		[%o0 - 6], %o4
-4:
-	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	subcc		%o3, 64, %o3
-	add		%o1, 64, %o1
-	bne		4b
-	 add		%o0, 64, %o0
-
-	andcc		%o2, 0x30, %o3
-	be,a		1f
-	 srl		%g1, 16, %g2
-4:
-	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	subcc		%o3, 16, %o3
-	add		%o1, 16, %o1
-	bne		4b
-	 add		%o0, 16, %o0
-
-	srl		%g1, 16, %g2
-1:
-	st		%o4, [%o0 - 6]
-	b		88f
-	 sth		%g2, [%o0 - 2]
-33:
-	ld		[%o1], %g2
-	sub		%o2, 4, %o2
-	srl		%g2, 24, %g3
-	and		%o0, 7, %g5
-	stb		%g3, [%o0]
-	cmp		%g5, 5
-	srl		%g2, 8, %g4
-	sll		%g2, 24, %g1
-	sth		%g4, [%o0 + 1]
-	add		%o1, 4, %o1
-	be		43f
-	 and		%o2, 0xffffffc0, %o3
-
-	ld		[%o0 - 1], %o4
-	add		%o0, 4, %o0
-4:
-	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-	SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-	SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-	SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-	subcc		%o3, 64, %o3
-	add		%o1, 64, %o1
-	bne		4b
-	 add		%o0, 64, %o0
-
-	andcc		%o2, 0x30, %o3
-	be,a		1f
-	 srl		%g1, 24, %g2
-4:
-	SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
-	subcc		%o3, 16, %o3
-	add		%o1, 16, %o1
-	bne		4b
-	 add		%o0, 16, %o0
-
-	srl		%g1, 24, %g2
-1:
-	st		%o4, [%o0 - 5]
-	b		88f
-	 stb		%g2, [%o0 - 1]
-41:
-	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	subcc		%o3, 64, %o3
-	add		%o1, 64, %o1
-	bne		41b
-	 add		%o0, 64, %o0
-	 
-	andcc		%o2, 0x30, %o3
-	be,a		1f
-	 srl		%g1, 16, %g2
-4:
-	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
-	subcc		%o3, 16, %o3
-	add		%o1, 16, %o1
-	bne		4b
-	 add		%o0, 16, %o0
-
-	srl		%g1, 16, %g2
-1:
-	sth		%g2, [%o0 - 3]
-	srl		%g1, 8, %g4
-	b		88f
-	 stb		%g4, [%o0 - 1]
-43:
-	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-	subcc		%o3, 64, %o3
-	add		%o1, 64, %o1
-	bne		43b
-	 add		%o0, 64, %o0
-
-	andcc		%o2, 0x30, %o3
-	be,a		1f
-	 srl		%g1, 24, %g2
-4:
-	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
-	subcc		%o3, 16, %o3
-	add		%o1, 16, %o1
-	bne		4b
-	 add		%o0, 16, %o0
-
-	srl		%g1, 24, %g2
-1:
-	stb		%g2, [%o0 + 3]
-	b		88f
-	 add		%o0, 4, %o0
-42:
-	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	subcc		%o3, 64, %o3
-	add		%o1, 64, %o1
-	bne		42b
-	 add		%o0, 64, %o0
-	 
-	andcc		%o2, 0x30, %o3
-	be,a		1f
-	 srl		%g1, 16, %g2
-4:
-	SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
-	subcc		%o3, 16, %o3
-	add		%o1, 16, %o1
-	bne		4b
-	 add		%o0, 16, %o0
-
-	srl		%g1, 16, %g2
-1:
-	sth		%g2, [%o0 - 2]
-
-	/* Fall through */
-	 
-#endif /* FASTER_NONALIGNED */
+	ret
+	 restore	%g7, %g0, %o0
 
 88:	/* short_end */
 
@@ -1127,7 +521,7 @@
 	stb		%g2, [%o0]
 1:
 	retl
- 	 RETL_INSN
+	 mov		%g7, %o0
 
 90:	/* short_aligned_end */
 	bne		88b
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 79836a7..3b6e248 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -8,7 +8,6 @@
 obj-y                   += fault_$(BITS).o
 obj-y                   += init_$(BITS).o
 obj-$(CONFIG_SPARC32)   += loadmmu.o
-obj-y                   += generic_$(BITS).o
 obj-$(CONFIG_SPARC32)   += extable.o btfixup.o srmmu.o iommu.o io-unit.o
 obj-$(CONFIG_SPARC32)   += hypersparc.o viking.o tsunami.o swift.o
 obj-$(CONFIG_SPARC_LEON)+= leon_mm.o
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
index 5175ac2..8a7f817 100644
--- a/arch/sparc/mm/btfixup.c
+++ b/arch/sparc/mm/btfixup.c
@@ -302,8 +302,7 @@
 				case 'i':	/* INT */
 					if ((insn & 0xc1c00000) == 0x01000000) /* %HI */
 						set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10));
-					else if ((insn & 0x80002000) == 0x80002000 &&
-					         (insn & 0x01800000) != 0x01800000) /* %LO */
+					else if ((insn & 0x80002000) == 0x80002000) /* %LO */
 						set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff));
 					else {
 						prom_printf(insn_i, p, addr, insn);
diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c
deleted file mode 100644
index e6067b7..0000000
--- a/arch/sparc/mm/generic_32.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * generic.c: Generic Sparc mm routines that are not dependent upon
- *            MMU type but are Sparc specific.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/pagemap.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
-/* Remap IO memory, the same way as remap_pfn_range(), but use
- * the obio memory space.
- *
- * They use a pgprot that sets PAGE_IO and does not check the
- * mem_map table as this is independent of normal memory.
- */
-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	do {
-		set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space));
-		address += PAGE_SIZE;
-		offset += PAGE_SIZE;
-		pte++;
-	} while (address < end);
-}
-
-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	offset -= address;
-	do {
-		pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
-		if (!pte)
-			return -ENOMEM;
-		io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-	return 0;
-}
-
-int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-		       unsigned long pfn, unsigned long size, pgprot_t prot)
-{
-	int error = 0;
-	pgd_t * dir;
-	unsigned long beg = from;
-	unsigned long end = from + size;
-	struct mm_struct *mm = vma->vm_mm;
-	int space = GET_IOSPACE(pfn);
-	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
-
-	/* See comment in mm/memory.c remap_pfn_range */
-	vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-	vma->vm_pgoff = (offset >> PAGE_SHIFT) |
-		((unsigned long)space << 28UL);
-
-	offset -= from;
-	dir = pgd_offset(mm, from);
-	flush_cache_range(vma, beg, end);
-
-	while (from < end) {
-		pmd_t *pmd = pmd_alloc(mm, dir, from);
-		error = -ENOMEM;
-		if (!pmd)
-			break;
-		error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
-		if (error)
-			break;
-		from = (from + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	}
-
-	flush_tlb_range(vma, beg, end);
-	return error;
-}
-EXPORT_SYMBOL(io_remap_pfn_range);
diff --git a/arch/sparc/mm/generic_64.c b/arch/sparc/mm/generic_64.c
deleted file mode 100644
index 3cb00df..0000000
--- a/arch/sparc/mm/generic_64.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * generic.c: Generic Sparc mm routines that are not dependent upon
- *            MMU type but are Sparc specific.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/pagemap.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/tlbflush.h>
-
-/* Remap IO memory, the same way as remap_pfn_range(), but use
- * the obio memory space.
- *
- * They use a pgprot that sets PAGE_IO and does not check the
- * mem_map table as this is independent of normal memory.
- */
-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
-				      unsigned long address,
-				      unsigned long size,
-				      unsigned long offset, pgprot_t prot,
-				      int space)
-{
-	unsigned long end;
-
-	/* clear hack bit that was used as a write_combine side-effect flag */
-	offset &= ~0x1UL;
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	do {
-		pte_t entry;
-		unsigned long curend = address + PAGE_SIZE;
-		
-		entry = mk_pte_io(offset, prot, space, PAGE_SIZE);
-		if (!(address & 0xffff)) {
-			if (PAGE_SIZE < (4 * 1024 * 1024) &&
-			    !(address & 0x3fffff) &&
-			    !(offset & 0x3ffffe) &&
-			    end >= address + 0x400000) {
-				entry = mk_pte_io(offset, prot, space,
-						  4 * 1024 * 1024);
-				curend = address + 0x400000;
-				offset += 0x400000;
-			} else if (PAGE_SIZE < (512 * 1024) &&
-				   !(address & 0x7ffff) &&
-				   !(offset & 0x7fffe) &&
-				   end >= address + 0x80000) {
-				entry = mk_pte_io(offset, prot, space,
-						  512 * 1024 * 1024);
-				curend = address + 0x80000;
-				offset += 0x80000;
-			} else if (PAGE_SIZE < (64 * 1024) &&
-				   !(offset & 0xfffe) &&
-				   end >= address + 0x10000) {
-				entry = mk_pte_io(offset, prot, space,
-						  64 * 1024);
-				curend = address + 0x10000;
-				offset += 0x10000;
-			} else
-				offset += PAGE_SIZE;
-		} else
-			offset += PAGE_SIZE;
-
-		if (pte_write(entry))
-			entry = pte_mkdirty(entry);
-		do {
-			BUG_ON(!pte_none(*pte));
-			set_pte_at(mm, address, pte, entry);
-			address += PAGE_SIZE;
-			pte_val(entry) += PAGE_SIZE;
-			pte++;
-		} while (address < curend);
-	} while (address < end);
-}
-
-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	offset -= address;
-	do {
-		pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
-		if (!pte)
-			return -ENOMEM;
-		io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
-		pte_unmap(pte);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-	return 0;
-}
-
-static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PUD_MASK;
-	end = address + size;
-	if (end > PUD_SIZE)
-		end = PUD_SIZE;
-	offset -= address;
-	do {
-		pmd_t *pmd = pmd_alloc(mm, pud, address);
-		if (!pud)
-			return -ENOMEM;
-		io_remap_pmd_range(mm, pmd, address, end - address, address + offset, prot, space);
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address < end);
-	return 0;
-}
-
-int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-		unsigned long pfn, unsigned long size, pgprot_t prot)
-{
-	int error = 0;
-	pgd_t * dir;
-	unsigned long beg = from;
-	unsigned long end = from + size;
-	struct mm_struct *mm = vma->vm_mm;
-	int space = GET_IOSPACE(pfn);
-	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
-	unsigned long phys_base;
-
-	phys_base = offset | (((unsigned long) space) << 32UL);
-
-	/* See comment in mm/memory.c remap_pfn_range */
-	vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-	vma->vm_pgoff = phys_base >> PAGE_SHIFT;
-
-	offset -= from;
-	dir = pgd_offset(mm, from);
-	flush_cache_range(vma, beg, end);
-
-	while (from < end) {
-		pud_t *pud = pud_alloc(mm, dir, from);
-		error = -ENOMEM;
-		if (!pud)
-			break;
-		error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
-		if (error)
-			break;
-		from = (from + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	}
-
-	flush_tlb_range(vma, beg, end);
-	return error;
-}
-EXPORT_SYMBOL(io_remap_pfn_range);
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 620f5b7..0491e40 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -513,8 +513,37 @@
 static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
 {
 	char *file;
+	int fd;
+	int err;
 
-	file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
+	__u32 version;
+	__u32 align;
+	char *backing_file;
+	time_t mtime;
+	unsigned long long size;
+	int sector_size;
+	int bitmap_offset;
+
+	if (ubd_dev->file && ubd_dev->cow.file) {
+		file = ubd_dev->cow.file;
+
+		goto out;
+	}
+
+	fd = os_open_file(ubd_dev->file, global_openflags, 0);
+	if (fd < 0)
+		return fd;
+
+	err = read_cow_header(file_reader, &fd, &version, &backing_file, \
+		&mtime, &size, &sector_size, &align, &bitmap_offset);
+	os_close_file(fd);
+
+	if(err == -EINVAL)
+		file = ubd_dev->file;
+	else
+		file = backing_file;
+
+out:
 	return os_file_size(file, size_out);
 }
 
diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h
index 67f87f2..78a1eff 100644
--- a/arch/x86/include/asm/amd_nb.h
+++ b/arch/x86/include/asm/amd_nb.h
@@ -1,6 +1,7 @@
 #ifndef _ASM_X86_AMD_NB_H
 #define _ASM_X86_AMD_NB_H
 
+#include <linux/ioport.h>
 #include <linux/pci.h>
 
 struct amd_nb_bus_dev_range {
@@ -13,6 +14,7 @@
 extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[];
 
 extern bool early_is_amd_nb(u32 value);
+extern struct resource *amd_get_mmconfig_range(struct resource *res);
 extern int amd_cache_northbridges(void);
 extern void amd_flush_garts(void);
 extern int amd_numa_init(void);
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 4a0b7c7..244ac77 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -495,7 +495,7 @@
 	return;
 }
 
-extern struct apic *generic_bigsmp_probe(void);
+extern void generic_bigsmp_probe(void);
 
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h
index fa7b917..431793e 100644
--- a/arch/x86/include/asm/timer.h
+++ b/arch/x86/include/asm/timer.h
@@ -32,6 +32,22 @@
  *  (mathieu.desnoyers@polymtl.ca)
  *
  *			-johnstul@us.ibm.com "math is hard, lets go shopping!"
+ *
+ * In:
+ *
+ * ns = cycles * cyc2ns_scale / SC
+ *
+ * Although we may still have enough bits to store the value of ns,
+ * in some cases, we may not have enough bits to store cycles * cyc2ns_scale,
+ * leading to an incorrect result.
+ *
+ * To avoid this, we can decompose 'cycles' into quotient and remainder
+ * of division by SC.  Then,
+ *
+ * ns = (quot * SC + rem) * cyc2ns_scale / SC
+ *    = quot * cyc2ns_scale + (rem * cyc2ns_scale) / SC
+ *
+ *			- sqazi@google.com
  */
 
 DECLARE_PER_CPU(unsigned long, cyc2ns);
@@ -41,9 +57,14 @@
 
 static inline unsigned long long __cycles_2_ns(unsigned long long cyc)
 {
+	unsigned long long quot;
+	unsigned long long rem;
 	int cpu = smp_processor_id();
 	unsigned long long ns = per_cpu(cyc2ns_offset, cpu);
-	ns += cyc * per_cpu(cyc2ns, cpu) >> CYC2NS_SCALE_FACTOR;
+	quot = (cyc >> CYC2NS_SCALE_FACTOR);
+	rem = cyc & ((1ULL << CYC2NS_SCALE_FACTOR) - 1);
+	ns += quot * per_cpu(cyc2ns, cpu) +
+		((rem * per_cpu(cyc2ns, cpu)) >> CYC2NS_SCALE_FACTOR);
 	return ns;
 }
 
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h
index a291c40..5d62d65 100644
--- a/arch/x86/include/asm/uv/uv_bau.h
+++ b/arch/x86/include/asm/uv/uv_bau.h
@@ -55,6 +55,7 @@
 #define UV_BAU_TUNABLES_DIR		"sgi_uv"
 #define UV_BAU_TUNABLES_FILE		"bau_tunables"
 #define WHITESPACE			" \t\n"
+#define uv_mmask			((1UL << uv_hub_info->m_val) - 1)
 #define uv_physnodeaddr(x)		((__pa((unsigned long)(x)) & uv_mmask))
 #define cpubit_isset(cpu, bau_local_cpumask) \
 	test_bit((cpu), (bau_local_cpumask).bits)
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index f26544a..21f7385 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -46,6 +46,13 @@
  *	PNODE   - the low N bits of the GNODE. The PNODE is the most useful variant
  *		  of the nasid for socket usage.
  *
+ *	GPA	- (global physical address) a socket physical address converted
+ *		  so that it can be used by the GRU as a global address. Socket
+ *		  physical addresses 1) need additional NASID (node) bits added
+ *		  to the high end of the address, and 2) unaliased if the
+ *		  partition does not have a physical address 0. In addition, on
+ *		  UV2 rev 1, GPAs need the gnode left shifted to bits 39 or 40.
+ *
  *
  *  NumaLink Global Physical Address Format:
  *  +--------------------------------+---------------------+
@@ -141,6 +148,8 @@
 	unsigned int		gnode_extra;
 	unsigned char		hub_revision;
 	unsigned char		apic_pnode_shift;
+	unsigned char		m_shift;
+	unsigned char		n_lshift;
 	unsigned long		gnode_upper;
 	unsigned long		lowmem_remap_top;
 	unsigned long		lowmem_remap_base;
@@ -177,6 +186,16 @@
 	return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
 }
 
+static inline int is_uv2_1_hub(void)
+{
+	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE;
+}
+
+static inline int is_uv2_2_hub(void)
+{
+	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1;
+}
+
 union uvh_apicid {
     unsigned long       v;
     struct uvh_apicid_s {
@@ -276,7 +295,10 @@
 {
 	if (paddr < uv_hub_info->lowmem_remap_top)
 		paddr |= uv_hub_info->lowmem_remap_base;
-	return paddr | uv_hub_info->gnode_upper;
+	paddr |= uv_hub_info->gnode_upper;
+	paddr = ((paddr << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
+		((paddr >> uv_hub_info->m_val) << uv_hub_info->n_lshift);
+	return paddr;
 }
 
 
@@ -296,20 +318,23 @@
 /* UV global physical address --> socket phys RAM */
 static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa)
 {
-	unsigned long paddr = gpa & uv_hub_info->gpa_mask;
+	unsigned long paddr;
 	unsigned long remap_base = uv_hub_info->lowmem_remap_base;
 	unsigned long remap_top =  uv_hub_info->lowmem_remap_top;
 
+	gpa = ((gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
+		((gpa >> uv_hub_info->n_lshift) << uv_hub_info->m_val);
+	paddr = gpa & uv_hub_info->gpa_mask;
 	if (paddr >= remap_base && paddr < remap_base + remap_top)
 		paddr -= remap_base;
 	return paddr;
 }
 
 
-/* gnode -> pnode */
+/* gpa -> pnode */
 static inline unsigned long uv_gpa_to_gnode(unsigned long gpa)
 {
-	return gpa >> uv_hub_info->m_val;
+	return gpa >> uv_hub_info->n_lshift;
 }
 
 /* gpa -> pnode */
@@ -320,6 +345,12 @@
 	return uv_gpa_to_gnode(gpa) & n_mask;
 }
 
+/* gpa -> node offset*/
+static inline unsigned long uv_gpa_to_offset(unsigned long gpa)
+{
+	return (gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift;
+}
+
 /* pnode, offset --> socket virtual */
 static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
 {
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index d3d9d50..bfd75ff 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1203,7 +1203,7 @@
 		if (!pte || !IOMMU_PTE_PRESENT(*pte))
 			continue;
 
-		dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1);
+		dma_ops_reserve_addresses(dma_dom, i >> PAGE_SHIFT, 1);
 	}
 
 	update_domain(&dma_dom->domain);
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index 4c39baa..bae1efe 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -119,6 +119,37 @@
 	return false;
 }
 
+struct resource *amd_get_mmconfig_range(struct resource *res)
+{
+	u32 address;
+	u64 base, msr;
+	unsigned segn_busn_bits;
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+		return NULL;
+
+	/* assume all cpus from fam10h have mmconfig */
+        if (boot_cpu_data.x86 < 0x10)
+		return NULL;
+
+	address = MSR_FAM10H_MMIO_CONF_BASE;
+	rdmsrl(address, msr);
+
+	/* mmconfig is not enabled */
+	if (!(msr & FAM10H_MMIO_CONF_ENABLE))
+		return NULL;
+
+	base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
+
+	segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
+			 FAM10H_MMIO_CONF_BUSRANGE_MASK;
+
+	res->flags = IORESOURCE_MEM;
+	res->start = base;
+	res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
+	return res;
+}
+
 int amd_get_subcaches(int cpu)
 {
 	struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index efd737e..521bead 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -255,12 +255,24 @@
 	.x86_32_early_logical_apicid	= bigsmp_early_logical_apicid,
 };
 
-struct apic * __init generic_bigsmp_probe(void)
+void __init generic_bigsmp_probe(void)
 {
-	if (probe_bigsmp())
-		return &apic_bigsmp;
+	unsigned int cpu;
 
-	return NULL;
+	if (!probe_bigsmp())
+		return;
+
+	apic = &apic_bigsmp;
+
+	for_each_possible_cpu(cpu) {
+		if (early_per_cpu(x86_cpu_to_logical_apicid,
+				  cpu) == BAD_APICID)
+			continue;
+		early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
+			bigsmp_early_logical_apicid(cpu);
+	}
+
+	pr_info("Overriding APIC driver with %s\n", apic_bigsmp.name);
 }
 
 apic_driver(apic_bigsmp);
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index b5254ad..0787bb3 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -200,14 +200,8 @@
 	 * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
 	 */
 
-	if (!cmdline_apic && apic == &apic_default) {
-		struct apic *bigsmp = generic_bigsmp_probe();
-		if (bigsmp) {
-			apic = bigsmp;
-			printk(KERN_INFO "Overriding APIC driver with %s\n",
-			       apic->name);
-		}
-	}
+	if (!cmdline_apic && apic == &apic_default)
+		generic_bigsmp_probe();
 #endif
 
 	if (apic->setup_apic_routing)
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 34b1859..874c208 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -779,7 +779,12 @@
 	for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++)
 		uv_possible_blades +=
 		  hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8));
-	printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades());
+
+	/* uv_num_possible_blades() is really the hub count */
+	printk(KERN_INFO "UV: Found %d blades, %d hubs\n",
+			is_uv1_hub() ? uv_num_possible_blades() :
+			(uv_num_possible_blades() + 1) / 2,
+			uv_num_possible_blades());
 
 	bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades();
 	uv_blade_info = kzalloc(bytes, GFP_KERNEL);
@@ -832,6 +837,10 @@
 		uv_cpu_hub_info(cpu)->apic_pnode_shift = uvh_apicid.s.pnode_shift;
 		uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;
 
+		uv_cpu_hub_info(cpu)->m_shift = 64 - m_val;
+		uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ?
+				(m_val == 40 ? 40 : 39) : m_val;
+
 		pnode = uv_apicid_to_pnode(apicid);
 		blade = boot_pnode_to_blade(pnode);
 		lcpu = uv_blade_info[blade].nr_possible_cpus;
@@ -862,8 +871,7 @@
 		if (uv_node_to_blade[nid] >= 0)
 			continue;
 		paddr = node_start_pfn(nid) << PAGE_SHIFT;
-		paddr = uv_soc_phys_ram_to_gpa(paddr);
-		pnode = (paddr >> m_val) & pnode_mask;
+		pnode = uv_gpa_to_pnode(uv_soc_phys_ram_to_gpa(paddr));
 		blade = boot_pnode_to_blade(pnode);
 		uv_node_to_blade[nid] = blade;
 	}
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index bab491b..d812fe2 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -508,6 +508,7 @@
 	unsigned long from = cpuc->lbr_entries[0].from;
 	unsigned long old_to, to = cpuc->lbr_entries[0].to;
 	unsigned long ip = regs->ip;
+	int is_64bit = 0;
 
 	/*
 	 * We don't need to fixup if the PEBS assist is fault like
@@ -559,7 +560,10 @@
 		} else
 			kaddr = (void *)to;
 
-		kernel_insn_init(&insn, kaddr);
+#ifdef CONFIG_X86_64
+		is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32);
+#endif
+		insn_init(&insn, kaddr, is_64bit);
 		insn_get_length(&insn);
 		to += insn.length;
 	} while (to < ip);
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 6781765..aa083d3 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -1054,6 +1054,14 @@
 }
 EXPORT_SYMBOL_GPL(hpet_rtc_timer_init);
 
+static void hpet_disable_rtc_channel(void)
+{
+	unsigned long cfg;
+	cfg = hpet_readl(HPET_T1_CFG);
+	cfg &= ~HPET_TN_ENABLE;
+	hpet_writel(cfg, HPET_T1_CFG);
+}
+
 /*
  * The functions below are called from rtc driver.
  * Return 0 if HPET is not being used.
@@ -1065,6 +1073,9 @@
 		return 0;
 
 	hpet_rtc_flags &= ~bit_mask;
+	if (unlikely(!hpet_rtc_flags))
+		hpet_disable_rtc_channel();
+
 	return 1;
 }
 EXPORT_SYMBOL_GPL(hpet_mask_rtc_irq_bit);
@@ -1130,15 +1141,11 @@
 
 static void hpet_rtc_timer_reinit(void)
 {
-	unsigned int cfg, delta;
+	unsigned int delta;
 	int lost_ints = -1;
 
-	if (unlikely(!hpet_rtc_flags)) {
-		cfg = hpet_readl(HPET_T1_CFG);
-		cfg &= ~HPET_TN_ENABLE;
-		hpet_writel(cfg, HPET_T1_CFG);
-		return;
-	}
+	if (unlikely(!hpet_rtc_flags))
+		hpet_disable_rtc_channel();
 
 	if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
 		delta = hpet_default_delta;
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index f1a6244..794bc95 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -75,8 +75,10 @@
 	/*
 	 * Undefined/reserved opcodes, conditional jump, Opcode Extension
 	 * Groups, and some special opcodes can not boost.
+	 * This is non-const to keep gcc from statically optimizing it out, as
+	 * variable_test_bit makes gcc think only *(unsigned long*) is used.
 	 */
-static const u32 twobyte_is_boostable[256 / 32] = {
+static u32 twobyte_is_boostable[256 / 32] = {
 	/*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f          */
 	/*      ----------------------------------------------          */
 	W(0x00, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0) | /* 00 */
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index c561038..b727450 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -298,13 +298,33 @@
 	return state;
 }
 
+/*
+ * AMD microcode firmware naming convention, up to family 15h they are in
+ * the legacy file:
+ *
+ *    amd-ucode/microcode_amd.bin
+ *
+ * This legacy file is always smaller than 2K in size.
+ *
+ * Starting at family 15h they are in family specific firmware files:
+ *
+ *    amd-ucode/microcode_amd_fam15h.bin
+ *    amd-ucode/microcode_amd_fam16h.bin
+ *    ...
+ *
+ * These might be larger than 2K.
+ */
 static enum ucode_state request_microcode_amd(int cpu, struct device *device)
 {
-	const char *fw_name = "amd-ucode/microcode_amd.bin";
+	char fw_name[36] = "amd-ucode/microcode_amd.bin";
 	const struct firmware *fw;
 	enum ucode_state ret = UCODE_NFOUND;
+	struct cpuinfo_x86 *c = &cpu_data(cpu);
 
-	if (request_firmware(&fw, fw_name, device)) {
+	if (c->x86 >= 0x15)
+		snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
+
+	if (request_firmware(&fw, (const char *)fw_name, device)) {
 		pr_err("failed to load file %s\n", fw_name);
 		goto out;
 	}
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 9103b89..0741b062 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -95,8 +95,8 @@
 	}
 #endif
 
+	set_bit(m->busid, mp_bus_not_pci);
 	if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) {
-		set_bit(m->busid, mp_bus_not_pci);
 #if defined(CONFIG_EISA) || defined(CONFIG_MCA)
 		mp_bus_id_to_type[m->busid] = MP_BUS_ISA;
 #endif
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 9242436..d4a705f 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -124,7 +124,7 @@
  */
 
 /*
- * Some machines require the "reboot=b"  commandline option,
+ * Some machines require the "reboot=b" or "reboot=k"  commandline options,
  * this quirk makes that automatic.
  */
 static int __init set_bios_reboot(const struct dmi_system_id *d)
@@ -136,6 +136,15 @@
 	return 0;
 }
 
+static int __init set_kbd_reboot(const struct dmi_system_id *d)
+{
+	if (reboot_type != BOOT_KBD) {
+		reboot_type = BOOT_KBD;
+		printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident);
+	}
+	return 0;
+}
+
 static struct dmi_system_id __initdata reboot_dmi_table[] = {
 	{	/* Handle problems with rebooting on Dell E520's */
 		.callback = set_bios_reboot,
@@ -295,7 +304,7 @@
 		},
 	},
 	{ /* Handle reboot issue on Acer Aspire one */
-		.callback = set_bios_reboot,
+		.callback = set_kbd_reboot,
 		.ident = "Acer Aspire One A110",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index dbe34b9..dd74e46 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -108,16 +108,6 @@
 	SetPageReferenced(page);
 }
 
-static inline void get_huge_page_tail(struct page *page)
-{
-	/*
-	 * __split_huge_page_refcount() cannot run
-	 * from under us.
-	 */
-	VM_BUG_ON(atomic_read(&page->_count) < 0);
-	atomic_inc(&page->_count);
-}
-
 static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
 		unsigned long end, int write, struct page **pages, int *nr)
 {
@@ -211,6 +201,8 @@
 	do {
 		VM_BUG_ON(compound_head(page) != head);
 		pages[*nr] = page;
+		if (PageTail(page))
+			get_huge_page_tail(page);
 		(*nr)++;
 		page++;
 		refs++;
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index b499626..f4f29b1 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -45,6 +45,7 @@
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 	BUG_ON(!pte_none(*(kmap_pte-idx)));
 	set_pte(kmap_pte-idx, mk_pte(page, prot));
+	arch_flush_lazy_mmu_mode();
 
 	return (void *)vaddr;
 }
@@ -88,6 +89,7 @@
 		 */
 		kpte_clear_flush(kmap_pte-idx, vaddr);
 		kmap_atomic_idx_pop();
+		arch_flush_lazy_mmu_mode();
 	}
 #ifdef CONFIG_DEBUG_HIGHMEM
 	else {
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 1dab519..f927429 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -87,9 +87,9 @@
 	*/
 	if (current->flags & PF_RANDOMIZE) {
 		if (mmap_is_ia32())
-			rnd = (long)get_random_int() % (1<<8);
+			rnd = get_random_int() % (1<<8);
 		else
-			rnd = (long)(get_random_int() % (1<<28));
+			rnd = get_random_int() % (1<<28);
 	}
 	return rnd << PAGE_SHIFT;
 }
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index 81dbfde..7efd0c6 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -104,6 +104,8 @@
 	if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
 		return;
 	pxm = pa->proximity_domain_lo;
+	if (acpi_srat_revision >= 2)
+		pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8;
 	node = setup_node(pxm);
 	if (node < 0) {
 		printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
@@ -155,6 +157,8 @@
 	start = ma->base_address;
 	end = start + ma->length;
 	pxm = ma->proximity_domain;
+	if (acpi_srat_revision <= 1)
+		pxm &= 0xff;
 	node = setup_node(pxm);
 	if (node < 0) {
 		printk(KERN_ERR "SRAT: Too many proximity domains.\n");
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index bfab3fa..7c1b765 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -151,17 +151,18 @@
 	cleanup_addr = proglen; /* epilogue address */
 
 	for (pass = 0; pass < 10; pass++) {
+		u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen;
 		/* no prologue/epilogue for trivial filters (RET something) */
 		proglen = 0;
 		prog = temp;
 
-		if (seen) {
+		if (seen_or_pass0) {
 			EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */
 			EMIT4(0x48, 0x83, 0xec, 96);	/* subq  $96,%rsp	*/
 			/* note : must save %rbx in case bpf_error is hit */
-			if (seen & (SEEN_XREG | SEEN_DATAREF))
+			if (seen_or_pass0 & (SEEN_XREG | SEEN_DATAREF))
 				EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */
-			if (seen & SEEN_XREG)
+			if (seen_or_pass0 & SEEN_XREG)
 				CLEAR_X(); /* make sure we dont leek kernel memory */
 
 			/*
@@ -170,7 +171,7 @@
 			 *  r9 = skb->len - skb->data_len
 			 *  r8 = skb->data
 			 */
-			if (seen & SEEN_DATAREF) {
+			if (seen_or_pass0 & SEEN_DATAREF) {
 				if (offsetof(struct sk_buff, len) <= 127)
 					/* mov    off8(%rdi),%r9d */
 					EMIT4(0x44, 0x8b, 0x4f, offsetof(struct sk_buff, len));
@@ -260,9 +261,14 @@
 			case BPF_S_ALU_DIV_X: /* A /= X; */
 				seen |= SEEN_XREG;
 				EMIT2(0x85, 0xdb);	/* test %ebx,%ebx */
-				if (pc_ret0 != -1)
-					EMIT_COND_JMP(X86_JE, addrs[pc_ret0] - (addrs[i] - 4));
-				else {
+				if (pc_ret0 > 0) {
+					/* addrs[pc_ret0 - 1] is start address of target
+					 * (addrs[i] - 4) is the address following this jmp
+					 * ("xor %edx,%edx; div %ebx" being 4 bytes long)
+					 */
+					EMIT_COND_JMP(X86_JE, addrs[pc_ret0 - 1] -
+								(addrs[i] - 4));
+				} else {
 					EMIT_COND_JMP(X86_JNE, 2 + 5);
 					CLEAR_A();
 					EMIT1_off32(0xe9, cleanup_addr - (addrs[i] - 4)); /* jmp .+off32 */
@@ -335,12 +341,12 @@
 				}
 				/* fallinto */
 			case BPF_S_RET_A:
-				if (seen) {
+				if (seen_or_pass0) {
 					if (i != flen - 1) {
 						EMIT_JMP(cleanup_addr - addrs[i]);
 						break;
 					}
-					if (seen & SEEN_XREG)
+					if (seen_or_pass0 & SEEN_XREG)
 						EMIT4(0x48, 0x8b, 0x5d, 0xf8);  /* mov  -8(%rbp),%rbx */
 					EMIT1(0xc9);		/* leaveq */
 				}
@@ -483,8 +489,9 @@
 				goto common_load;
 			case BPF_S_LDX_B_MSH:
 				if ((int)K < 0) {
-					if (pc_ret0 != -1) {
-						EMIT_JMP(addrs[pc_ret0] - addrs[i]);
+					if (pc_ret0 > 0) {
+						/* addrs[pc_ret0 - 1] is the start address */
+						EMIT_JMP(addrs[pc_ret0 - 1] - addrs[i]);
 						break;
 					}
 					CLEAR_A();
@@ -568,8 +575,8 @@
 					break;
 				}
 				if (filter[i].jt != 0) {
-					if (filter[i].jf)
-						t_offset += is_near(f_offset) ? 2 : 6;
+					if (filter[i].jf && f_offset)
+						t_offset += is_near(f_offset) ? 2 : 5;
 					EMIT_COND_JMP(t_op, t_offset);
 					if (filter[i].jf)
 						EMIT_JMP(f_offset);
@@ -599,13 +606,14 @@
 		 * use it to give the cleanup instruction(s) addr
 		 */
 		cleanup_addr = proglen - 1; /* ret */
-		if (seen)
+		if (seen_or_pass0)
 			cleanup_addr -= 1; /* leaveq */
-		if (seen & SEEN_XREG)
+		if (seen_or_pass0 & SEEN_XREG)
 			cleanup_addr -= 4; /* mov  -8(%rbp),%rbx */
 
 		if (image) {
-			WARN_ON(proglen != oldproglen);
+			if (proglen != oldproglen)
+				pr_err("bpb_jit_compile proglen=%u != oldproglen=%u\n", proglen, oldproglen);
 			break;
 		}
 		if (proglen == oldproglen) {
diff --git a/arch/x86/oprofile/init.c b/arch/x86/oprofile/init.c
index cdfe4c5..f148cf6 100644
--- a/arch/x86/oprofile/init.c
+++ b/arch/x86/oprofile/init.c
@@ -21,6 +21,7 @@
 extern void op_nmi_exit(void);
 extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
 
+static int nmi_timer;
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
@@ -31,8 +32,9 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 	ret = op_nmi_init(ops);
 #endif
+	nmi_timer = (ret != 0);
 #ifdef CONFIG_X86_IO_APIC
-	if (ret < 0)
+	if (nmi_timer)
 		ret = op_nmi_timer_init(ops);
 #endif
 	ops->backtrace = x86_backtrace;
@@ -44,6 +46,7 @@
 void oprofile_arch_exit(void)
 {
 #ifdef CONFIG_X86_LOCAL_APIC
-	op_nmi_exit();
+	if (!nmi_timer)
+		op_nmi_exit();
 #endif
 }
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index 6b8759f..d24d3da 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -18,8 +18,9 @@
 obj-$(CONFIG_X86_MRST)		+= mrst.o
 
 obj-y				+= common.o early.o
-obj-y				+= amd_bus.o bus_numa.o
+obj-y				+= bus_numa.o
 
+obj-$(CONFIG_AMD_NB)		+= amd_bus.o
 obj-$(CONFIG_PCI_CNB20LE_QUIRK)	+= broadcom_bus.o
 
 ifeq ($(CONFIG_PCI_DEBUG),y)
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 50b3f14..53f9e68 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -149,7 +149,7 @@
 	struct acpi_resource_address64 addr;
 	acpi_status status;
 	unsigned long flags;
-	u64 start, end;
+	u64 start, orig_end, end;
 
 	status = resource_to_addr(acpi_res, &addr);
 	if (!ACPI_SUCCESS(status))
@@ -165,7 +165,21 @@
 		return AE_OK;
 
 	start = addr.minimum + addr.translation_offset;
-	end = addr.maximum + addr.translation_offset;
+	orig_end = end = addr.maximum + addr.translation_offset;
+
+	/* Exclude non-addressable range or non-addressable portion of range */
+	end = min(end, (u64)iomem_resource.end);
+	if (end <= start) {
+		dev_info(&info->bridge->dev,
+			"host bridge window [%#llx-%#llx] "
+			"(ignored, not CPU addressable)\n", start, orig_end);
+		return AE_OK;
+	} else if (orig_end != end) {
+		dev_info(&info->bridge->dev,
+			"host bridge window [%#llx-%#llx] "
+			"([%#llx-%#llx] ignored, not CPU addressable)\n",
+			start, orig_end, end + 1, orig_end);
+	}
 
 	res = &info->res[info->res_num];
 	res->name = info->name;
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 026e493..385a940 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -30,34 +30,6 @@
 	{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 },
 };
 
-static u64 __initdata fam10h_mmconf_start;
-static u64 __initdata fam10h_mmconf_end;
-static void __init get_pci_mmcfg_amd_fam10h_range(void)
-{
-	u32 address;
-	u64 base, msr;
-	unsigned segn_busn_bits;
-
-	/* assume all cpus from fam10h have mmconf */
-        if (boot_cpu_data.x86 < 0x10)
-		return;
-
-	address = MSR_FAM10H_MMIO_CONF_BASE;
-	rdmsrl(address, msr);
-
-	/* mmconfig is not enable */
-	if (!(msr & FAM10H_MMIO_CONF_ENABLE))
-		return;
-
-	base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
-
-	segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
-			 FAM10H_MMIO_CONF_BUSRANGE_MASK;
-
-	fam10h_mmconf_start = base;
-	fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
-}
-
 #define RANGE_NUM 16
 
 /**
@@ -85,6 +57,9 @@
 	u64 val;
 	u32 address;
 	bool found;
+	struct resource fam10h_mmconf_res, *fam10h_mmconf;
+	u64 fam10h_mmconf_start;
+	u64 fam10h_mmconf_end;
 
 	if (!early_pci_allowed())
 		return -1;
@@ -211,12 +186,17 @@
 		subtract_range(range, RANGE_NUM, 0, end);
 
 	/* get mmconfig */
-	get_pci_mmcfg_amd_fam10h_range();
+	fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res);
 	/* need to take out mmconf range */
-	if (fam10h_mmconf_end) {
-		printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end);
+	if (fam10h_mmconf) {
+		printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf);
+		fam10h_mmconf_start = fam10h_mmconf->start;
+		fam10h_mmconf_end = fam10h_mmconf->end;
 		subtract_range(range, RANGE_NUM, fam10h_mmconf_start,
 				 fam10h_mmconf_end + 1);
+	} else {
+		fam10h_mmconf_start = 0;
+		fam10h_mmconf_end = 0;
 	}
 
 	/* mmio resource */
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index 7000e74..fe73276 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -678,36 +678,40 @@
 	pentry = (struct sfi_device_table_entry *)sb->pentry;
 
 	for (i = 0; i < num; i++, pentry++) {
-		if (pentry->irq != (u8)0xff) { /* native RTE case */
+		int irq = pentry->irq;
+
+		if (irq != (u8)0xff) { /* native RTE case */
 			/* these SPI2 devices are not exposed to system as PCI
 			 * devices, but they have separate RTE entry in IOAPIC
 			 * so we have to enable them one by one here
 			 */
-			ioapic = mp_find_ioapic(pentry->irq);
+			ioapic = mp_find_ioapic(irq);
 			irq_attr.ioapic = ioapic;
-			irq_attr.ioapic_pin = pentry->irq;
+			irq_attr.ioapic_pin = irq;
 			irq_attr.trigger = 1;
 			irq_attr.polarity = 1;
-			io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr);
-		}
+			io_apic_set_pci_routing(NULL, irq, &irq_attr);
+		} else
+			irq = 0; /* No irq */
+
 		switch (pentry->type) {
 		case SFI_DEV_TYPE_IPC:
 			/* ID as IRQ is a hack that will go away */
-			pdev = platform_device_alloc(pentry->name, pentry->irq);
+			pdev = platform_device_alloc(pentry->name, irq);
 			if (pdev == NULL) {
 				pr_err("out of memory for SFI platform device '%s'.\n",
 							pentry->name);
 				continue;
 			}
-			install_irq_resource(pdev, pentry->irq);
+			install_irq_resource(pdev, irq);
 			pr_debug("info[%2d]: IPC bus, name = %16.16s, "
-				"irq = 0x%2x\n", i, pentry->name, pentry->irq);
+				"irq = 0x%2x\n", i, pentry->name, irq);
 			sfi_handle_ipc_dev(pdev);
 			break;
 		case SFI_DEV_TYPE_SPI:
 			memset(&spi_info, 0, sizeof(spi_info));
 			strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN);
-			spi_info.irq = pentry->irq;
+			spi_info.irq = irq;
 			spi_info.bus_num = pentry->host_num;
 			spi_info.chip_select = pentry->addr;
 			spi_info.max_speed_hz = pentry->max_freq;
@@ -724,7 +728,7 @@
 			memset(&i2c_info, 0, sizeof(i2c_info));
 			bus = pentry->host_num;
 			strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN);
-			i2c_info.irq = pentry->irq;
+			i2c_info.irq = irq;
 			i2c_info.addr = pentry->addr;
 			pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, "
 				"irq = 0x%2x, addr = 0x%x\n", i, bus,
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c
index 68e467f..edf435b 100644
--- a/arch/x86/platform/uv/tlb_uv.c
+++ b/arch/x86/platform/uv/tlb_uv.c
@@ -115,9 +115,6 @@
 
 /* base pnode in this partition */
 static int uv_base_pnode __read_mostly;
-/* position of pnode (which is nasid>>1): */
-static int uv_nshift __read_mostly;
-static unsigned long uv_mmask __read_mostly;
 
 static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
 static DEFINE_PER_CPU(struct bau_control, bau_control);
@@ -1426,7 +1423,7 @@
 {
 	int i;
 	int cpu;
-	unsigned long pa;
+	unsigned long gpa;
 	unsigned long m;
 	unsigned long n;
 	size_t dsize;
@@ -1442,9 +1439,9 @@
 	bau_desc = kmalloc_node(dsize, GFP_KERNEL, node);
 	BUG_ON(!bau_desc);
 
-	pa = uv_gpa(bau_desc); /* need the real nasid*/
-	n = pa >> uv_nshift;
-	m = pa & uv_mmask;
+	gpa = uv_gpa(bau_desc);
+	n = uv_gpa_to_gnode(gpa);
+	m = uv_gpa_to_offset(gpa);
 
 	/* the 14-bit pnode */
 	write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m));
@@ -1516,9 +1513,9 @@
 		bcp->queue_last		= pqp + (DEST_Q_SIZE - 1);
 	}
 	/*
-	 * need the pnode of where the memory was really allocated
+	 * need the gnode of where the memory was really allocated
 	 */
-	pn = uv_gpa(pqp) >> uv_nshift;
+	pn = uv_gpa_to_gnode(uv_gpa(pqp));
 	first = uv_physnodeaddr(pqp);
 	pn_first = ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) | first;
 	last = uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1));
@@ -1578,14 +1575,14 @@
 		ts_ns = base * mult1 * mult2;
 		ret = ts_ns / 1000;
 	} else {
-		/* 4 bits  0/1 for 10/80us, 3 bits of multiplier */
-		mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
+		/* 4 bits  0/1 for 10/80us base, 3 bits of multiplier */
+		mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL);
 		mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT;
 		if (mmr_image & (1L << UV2_ACK_UNITS_SHFT))
-			mult1 = 80;
+			base = 80;
 		else
-			mult1 = 10;
-		base = mmr_image & UV2_ACK_MASK;
+			base = 10;
+		mult1 = mmr_image & UV2_ACK_MASK;
 		ret = mult1 * base;
 	}
 	return ret;
@@ -1812,8 +1809,6 @@
 		zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
 	}
 
-	uv_nshift = uv_hub_info->m_val;
-	uv_mmask = (1UL << uv_hub_info->m_val) - 1;
 	nuvhubs = uv_num_possible_blades();
 	spin_lock_init(&disable_lock);
 	congested_cycles = usec_2_cycles(congested_respns_us);
@@ -1825,6 +1820,8 @@
 			uv_base_pnode = uv_blade_to_pnode(uvhub);
 	}
 
+	enable_timeouts();
+
 	if (init_per_cpu(nuvhubs, uv_base_pnode)) {
 		nobau = 1;
 		return 0;
@@ -1835,7 +1832,6 @@
 		if (uv_blade_nr_possible_cpus(uvhub))
 			init_uvhub(uvhub, vector, uv_base_pnode);
 
-	enable_timeouts();
 	alloc_intr_gate(vector, uv_bau_message_intr1);
 
 	for_each_possible_blade(uvhub) {
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 67d69f1..0fb662a 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1337,7 +1337,7 @@
 	int cpu = (long)hcpu;
 	switch (action) {
 	case CPU_UP_PREPARE:
-		per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+		xen_vcpu_setup(cpu);
 		if (xen_have_vector_callback)
 			xen_init_lock_cpu(cpu);
 		break;
@@ -1367,7 +1367,6 @@
 	xen_hvm_smp_init();
 	register_cpu_notifier(&xen_hvm_cpu_notifier);
 	xen_unplug_emulated_devices();
-	have_vcpu_info_placement = 0;
 	x86_init.irqs.intr_init = xen_init_IRQ;
 	xen_hvm_init_time_ops();
 	xen_hvm_init_mmu_ops();
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index acea42e..f8dcda4 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -192,9 +192,21 @@
 	domid_t domid = DOMID_SELF;
 	int ret;
 
-	ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid);
-	if (ret > 0)
-		max_pages = ret;
+	/*
+	 * For the initial domain we use the maximum reservation as
+	 * the maximum page.
+	 *
+	 * For guest domains the current maximum reservation reflects
+	 * the current maximum rather than the static maximum. In this
+	 * case the e820 map provided to us will cover the static
+	 * maximum region.
+	 */
+	if (xen_initial_domain()) {
+		ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid);
+		if (ret > 0)
+			max_pages = ret;
+	}
+
 	return min(max_pages, MAX_DOMAIN_PAGES);
 }
 
diff --git a/block/blk-core.c b/block/blk-core.c
index 847d04e..35ae52d 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -418,6 +418,7 @@
 	q->backing_dev_info.state = 0;
 	q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
 	q->backing_dev_info.name = "block";
+	q->node = node_id;
 
 	err = bdi_init(&q->backing_dev_info);
 	if (err) {
@@ -502,7 +503,7 @@
 	if (!uninit_q)
 		return NULL;
 
-	q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id);
+	q = blk_init_allocated_queue(uninit_q, rfn, lock);
 	if (!q)
 		blk_cleanup_queue(uninit_q);
 
@@ -514,18 +515,9 @@
 blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
 			 spinlock_t *lock)
 {
-	return blk_init_allocated_queue_node(q, rfn, lock, -1);
-}
-EXPORT_SYMBOL(blk_init_allocated_queue);
-
-struct request_queue *
-blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
-			      spinlock_t *lock, int node_id)
-{
 	if (!q)
 		return NULL;
 
-	q->node = node_id;
 	if (blk_init_free_list(q))
 		return NULL;
 
@@ -555,7 +547,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(blk_init_allocated_queue_node);
+EXPORT_SYMBOL(blk_init_allocated_queue);
 
 int blk_get_queue(struct request_queue *q)
 {
diff --git a/block/blk-map.c b/block/blk-map.c
index e663ac2..164cd00 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -204,10 +204,11 @@
 		if (!iov[i].iov_len)
 			return -EINVAL;
 
-		if (uaddr & queue_dma_alignment(q)) {
+		/*
+		 * Keep going so we check length of all segments
+		 */
+		if (uaddr & queue_dma_alignment(q))
 			unaligned = 1;
-			break;
-		}
 	}
 
 	if (unaligned || (q->dma_pad_mask & len) || map_data)
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index ae21919..23500ac 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -3169,7 +3169,7 @@
 		}
 	}
 
-	if (ret)
+	if (ret && ret != -EEXIST)
 		printk(KERN_ERR "cfq: cic link failed!\n");
 
 	return ret;
@@ -3185,6 +3185,7 @@
 {
 	struct io_context *ioc = NULL;
 	struct cfq_io_context *cic;
+	int ret;
 
 	might_sleep_if(gfp_mask & __GFP_WAIT);
 
@@ -3192,6 +3193,7 @@
 	if (!ioc)
 		return NULL;
 
+retry:
 	cic = cfq_cic_lookup(cfqd, ioc);
 	if (cic)
 		goto out;
@@ -3200,7 +3202,12 @@
 	if (cic == NULL)
 		goto err;
 
-	if (cfq_cic_link(cfqd, ioc, cic, gfp_mask))
+	ret = cfq_cic_link(cfqd, ioc, cic, gfp_mask);
+	if (ret == -EEXIST) {
+		/* someone has linked cic to ioc already */
+		cfq_cic_free(cic);
+		goto retry;
+	} else if (ret)
 		goto err_free;
 
 out:
@@ -4015,6 +4022,11 @@
 
 	if (blkio_alloc_blkg_stats(&cfqg->blkg)) {
 		kfree(cfqg);
+
+		spin_lock(&cic_index_lock);
+		ida_remove(&cic_index_ida, cfqd->cic_index);
+		spin_unlock(&cic_index_lock);
+
 		kfree(cfqd);
 		return NULL;
 	}
diff --git a/block/genhd.c b/block/genhd.c
index cbf7b88..b65f565 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -611,6 +611,12 @@
 	register_disk(disk);
 	blk_register_queue(disk);
 
+	/*
+	 * Take an extra ref on queue which will be put on disk_release()
+	 * so that it sticks around as long as @disk is there.
+	 */
+	WARN_ON_ONCE(blk_get_queue(disk->queue));
+
 	retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
 				   "bdi");
 	WARN_ON(retval);
@@ -1103,6 +1109,8 @@
 	disk_replace_part_tbl(disk, NULL);
 	free_part_stats(&disk->part0);
 	free_part_info(&disk->part0);
+	if (disk->queue)
+		blk_put_queue(disk->queue);
 	kfree(disk);
 }
 
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 4f4230b..5ef1f4c 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -24,6 +24,7 @@
 #include <linux/capability.h>
 #include <linux/completion.h>
 #include <linux/cdrom.h>
+#include <linux/ratelimit.h>
 #include <linux/slab.h>
 #include <linux/times.h>
 #include <asm/uaccess.h>
@@ -691,6 +692,57 @@
 }
 EXPORT_SYMBOL(scsi_cmd_ioctl);
 
+int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)
+{
+	if (bd && bd == bd->bd_contains)
+		return 0;
+
+	/* Actually none of these is particularly useful on a partition,
+	 * but they are safe.
+	 */
+	switch (cmd) {
+	case SCSI_IOCTL_GET_IDLUN:
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+	case SCSI_IOCTL_GET_PCI:
+	case SCSI_IOCTL_PROBE_HOST:
+	case SG_GET_VERSION_NUM:
+	case SG_SET_TIMEOUT:
+	case SG_GET_TIMEOUT:
+	case SG_GET_RESERVED_SIZE:
+	case SG_SET_RESERVED_SIZE:
+	case SG_EMULATED_HOST:
+		return 0;
+	case CDROM_GET_CAPABILITY:
+		/* Keep this until we remove the printk below.  udev sends it
+		 * and we do not want to spam dmesg about it.   CD-ROMs do
+		 * not have partitions, so we get here only for disks.
+		 */
+		return -ENOTTY;
+	default:
+		break;
+	}
+
+	/* In particular, rule out all resets and host-specific ioctls.  */
+	printk_ratelimited(KERN_WARNING
+			   "%s: sending ioctl %x to a partition!\n", current->comm, cmd);
+
+	return capable(CAP_SYS_RAWIO) ? 0 : -ENOTTY;
+}
+EXPORT_SYMBOL(scsi_verify_blk_ioctl);
+
+int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode,
+		       unsigned int cmd, void __user *arg)
+{
+	int ret;
+
+	ret = scsi_verify_blk_ioctl(bd, cmd);
+	if (ret < 0)
+		return ret;
+
+	return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg);
+}
+EXPORT_SYMBOL(scsi_cmd_blk_ioctl);
+
 static int __init blk_scsi_ioctl_init(void)
 {
 	blk_set_cmd_filter_defaults(&blk_default_cmd_filter);
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index e46d21a..671d4d6 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -945,7 +945,7 @@
 	crypto_unregister_template(&cryptd_tmpl);
 }
 
-module_init(cryptd_init);
+subsys_initcall(cryptd_init);
 module_exit(cryptd_exit);
 
 MODULE_LICENSE("GPL");
diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c
index 9ed9f60..88f160b 100644
--- a/crypto/sha512_generic.c
+++ b/crypto/sha512_generic.c
@@ -21,8 +21,6 @@
 #include <linux/percpu.h>
 #include <asm/byteorder.h>
 
-static DEFINE_PER_CPU(u64[80], msg_schedule);
-
 static inline u64 Ch(u64 x, u64 y, u64 z)
 {
         return z ^ (x & (y ^ z));
@@ -80,7 +78,7 @@
 
 static inline void BLEND_OP(int I, u64 *W)
 {
-	W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
+	W[I % 16] += s1(W[(I-2) % 16]) + W[(I-7) % 16] + s0(W[(I-15) % 16]);
 }
 
 static void
@@ -89,38 +87,48 @@
 	u64 a, b, c, d, e, f, g, h, t1, t2;
 
 	int i;
-	u64 *W = get_cpu_var(msg_schedule);
+	u64 W[16];
 
 	/* load the input */
         for (i = 0; i < 16; i++)
                 LOAD_OP(i, W, input);
 
-        for (i = 16; i < 80; i++) {
-                BLEND_OP(i, W);
-        }
-
 	/* load the state into our registers */
 	a=state[0];   b=state[1];   c=state[2];   d=state[3];
 	e=state[4];   f=state[5];   g=state[6];   h=state[7];
 
-	/* now iterate */
-	for (i=0; i<80; i+=8) {
-		t1 = h + e1(e) + Ch(e,f,g) + sha512_K[i  ] + W[i  ];
-		t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
-		t1 = g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[i+1];
-		t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
-		t1 = f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[i+2];
-		t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
-		t1 = e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[i+3];
-		t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
-		t1 = d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[i+4];
-		t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
-		t1 = c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[i+5];
-		t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
-		t1 = b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[i+6];
-		t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
-		t1 = a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[i+7];
-		t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+#define SHA512_0_15(i, a, b, c, d, e, f, g, h)			\
+	t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[i];	\
+	t2 = e0(a) + Maj(a, b, c);				\
+	d += t1;						\
+	h = t1 + t2
+
+#define SHA512_16_79(i, a, b, c, d, e, f, g, h)			\
+	BLEND_OP(i, W);						\
+	t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[(i)%16];	\
+	t2 = e0(a) + Maj(a, b, c);				\
+	d += t1;						\
+	h = t1 + t2
+
+	for (i = 0; i < 16; i += 8) {
+		SHA512_0_15(i, a, b, c, d, e, f, g, h);
+		SHA512_0_15(i + 1, h, a, b, c, d, e, f, g);
+		SHA512_0_15(i + 2, g, h, a, b, c, d, e, f);
+		SHA512_0_15(i + 3, f, g, h, a, b, c, d, e);
+		SHA512_0_15(i + 4, e, f, g, h, a, b, c, d);
+		SHA512_0_15(i + 5, d, e, f, g, h, a, b, c);
+		SHA512_0_15(i + 6, c, d, e, f, g, h, a, b);
+		SHA512_0_15(i + 7, b, c, d, e, f, g, h, a);
+	}
+	for (i = 16; i < 80; i += 8) {
+		SHA512_16_79(i, a, b, c, d, e, f, g, h);
+		SHA512_16_79(i + 1, h, a, b, c, d, e, f, g);
+		SHA512_16_79(i + 2, g, h, a, b, c, d, e, f);
+		SHA512_16_79(i + 3, f, g, h, a, b, c, d, e);
+		SHA512_16_79(i + 4, e, f, g, h, a, b, c, d);
+		SHA512_16_79(i + 5, d, e, f, g, h, a, b, c);
+		SHA512_16_79(i + 6, c, d, e, f, g, h, a, b);
+		SHA512_16_79(i + 7, b, c, d, e, f, g, h, a);
 	}
 
 	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
@@ -128,8 +136,6 @@
 
 	/* erase our data */
 	a = b = c = d = e = f = g = h = t1 = t2 = 0;
-	memset(W, 0, sizeof(__get_cpu_var(msg_schedule)));
-	put_cpu_var(msg_schedule);
 }
 
 static int
diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c
index 8c7b997..42163d8 100644
--- a/drivers/acpi/acpica/dsargs.c
+++ b/drivers/acpi/acpica/dsargs.c
@@ -387,5 +387,29 @@
 	status = acpi_ds_execute_arguments(node, node->parent,
 					   extra_desc->extra.aml_length,
 					   extra_desc->extra.aml_start);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Validate the region address/length via the host OS */
+
+	status = acpi_os_validate_address(obj_desc->region.space_id,
+					  obj_desc->region.address,
+					  (acpi_size) obj_desc->region.length,
+					  acpi_ut_get_node_name(node));
+
+	if (ACPI_FAILURE(status)) {
+		/*
+		 * Invalid address/length. We will emit an error message and mark
+		 * the region as invalid, so that it will cause an additional error if
+		 * it is ever used. Then return AE_OK.
+		 */
+		ACPI_EXCEPTION((AE_INFO, status,
+				"During address validation of OpRegion [%4.4s]",
+				node->name.ascii));
+		obj_desc->common.flags |= AOPOBJ_INVALID;
+		status = AE_OK;
+	}
+
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
index 7489b89..f151afe 100644
--- a/drivers/acpi/atomicio.c
+++ b/drivers/acpi/atomicio.c
@@ -76,7 +76,7 @@
 {
 	struct acpi_iomap *map;
 
-	map = __acpi_find_iomap(paddr, size);
+	map = __acpi_find_iomap(paddr, size/8);
 	if (map)
 		return map->vaddr + (paddr - map->paddr);
 	else
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 3b5c318..e56f3be 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -45,6 +45,8 @@
 static int node_to_pxm_map[MAX_NUMNODES]
 			= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
 
+unsigned char acpi_srat_revision __initdata;
+
 int pxm_to_node(int pxm)
 {
 	if (pxm < 0)
@@ -255,9 +257,13 @@
 
 static int __init acpi_parse_srat(struct acpi_table_header *table)
 {
+	struct acpi_table_srat *srat;
 	if (!table)
 		return -EINVAL;
 
+	srat = (struct acpi_table_srat *)table;
+	acpi_srat_revision = srat->header.revision;
+
 	/* Real work done in acpi_table_parse_srat below. */
 
 	return 0;
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index d06078d..dfafecb 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -595,6 +595,13 @@
 		if (ACPI_SUCCESS(status)) {
 			dev_info(root->bus->bridge,
 				"ACPI _OSC control (0x%02x) granted\n", flags);
+			if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
+				/*
+				 * We have ASPM control, but the FADT indicates
+				 * that it's unsupported. Clear it.
+				 */
+				pcie_clear_aspm(root->bus);
+			}
 		} else {
 			dev_info(root->bus->bridge,
 				"ACPI _OSC request failed (%s), "
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 02d2a4c..0c0669f 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -172,8 +172,30 @@
 	apic_id = map_mat_entry(handle, type, acpi_id);
 	if (apic_id == -1)
 		apic_id = map_madt_entry(type, acpi_id);
-	if (apic_id == -1)
-		return apic_id;
+	if (apic_id == -1) {
+		/*
+		 * On UP processor, there is no _MAT or MADT table.
+		 * So above apic_id is always set to -1.
+		 *
+		 * BIOS may define multiple CPU handles even for UP processor.
+		 * For example,
+		 *
+		 * Scope (_PR)
+                 * {
+		 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
+		 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
+		 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
+		 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
+		 * }
+		 *
+		 * Ignores apic_id and always return 0 for CPU0's handle.
+		 * Return -1 for other CPU's handle.
+		 */
+		if (acpi_id == 0)
+			return acpi_id;
+		else
+			return apic_id;
+	}
 
 #ifdef CONFIG_SMP
 	for_each_possible_cpu(i) {
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 6f6e771..6da6deb 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -113,6 +113,8 @@
 	PIIX_PATA_FLAGS		= ATA_FLAG_SLAVE_POSS,
 	PIIX_SATA_FLAGS		= ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR,
 
+	PIIX_FLAG_PIO16		= (1 << 30), /*support 16bit PIO only*/
+
 	PIIX_80C_PRI		= (1 << 5) | (1 << 4),
 	PIIX_80C_SEC		= (1 << 7) | (1 << 6),
 
@@ -147,6 +149,7 @@
 	ich8m_apple_sata,	/* locks up on second port enable */
 	tolapai_sata,
 	piix_pata_vmw,			/* PIIX4 for VMware, spurious DMA_ERR */
+	ich8_sata_snb,
 };
 
 struct piix_map_db {
@@ -177,6 +180,7 @@
 static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
 			      unsigned hints);
 static bool piix_irq_check(struct ata_port *ap);
+static int piix_port_start(struct ata_port *ap);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -298,21 +302,21 @@
 	/* SATA Controller IDE (PCH) */
 	{ 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
 	/* SATA Controller IDE (CPT) */
-	{ 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+	{ 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
 	/* SATA Controller IDE (CPT) */
-	{ 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+	{ 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
 	/* SATA Controller IDE (CPT) */
 	{ 0x8086, 0x1c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (CPT) */
 	{ 0x8086, 0x1c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (PBG) */
-	{ 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+	{ 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
 	/* SATA Controller IDE (PBG) */
 	{ 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (Panther Point) */
-	{ 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+	{ 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
 	/* SATA Controller IDE (Panther Point) */
-	{ 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+	{ 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
 	/* SATA Controller IDE (Panther Point) */
 	{ 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (Panther Point) */
@@ -338,6 +342,7 @@
 static struct ata_port_operations piix_sata_ops = {
 	.inherits		= &ata_bmdma32_port_ops,
 	.sff_irq_check		= piix_irq_check,
+	.port_start		= piix_port_start,
 };
 
 static struct ata_port_operations piix_pata_ops = {
@@ -478,6 +483,7 @@
 	[ich8_2port_sata]	= &ich8_2port_map_db,
 	[ich8m_apple_sata]	= &ich8m_apple_map_db,
 	[tolapai_sata]		= &tolapai_map_db,
+	[ich8_sata_snb]		= &ich8_map_db,
 };
 
 static struct ata_port_info piix_port_info[] = {
@@ -606,6 +612,19 @@
 		.port_ops	= &piix_vmw_ops,
 	},
 
+	/*
+	 * some Sandybridge chipsets have broken 32 mode up to now,
+	 * see https://bugzilla.kernel.org/show_bug.cgi?id=40592
+	 */
+	[ich8_sata_snb] =
+	{
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16,
+		.pio_mask	= ATA_PIO4,
+		.mwdma_mask	= ATA_MWDMA2,
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &piix_sata_ops,
+	},
+
 };
 
 static struct pci_bits piix_enable_bits[] = {
@@ -649,6 +668,14 @@
 	{ 0, }
 };
 
+static int piix_port_start(struct ata_port *ap)
+{
+	if (!(ap->flags & PIIX_FLAG_PIO16))
+		ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
+
+	return ata_bmdma_port_start(ap);
+}
+
 /**
  *	ich_pata_cable_detect - Probe host controller cable detect info
  *	@ap: Port for which cable detect info is desired
diff --git a/drivers/base/core.c b/drivers/base/core.c
index bc8729d..78445f4 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -22,6 +22,7 @@
 #include <linux/kallsyms.h>
 #include <linux/mutex.h>
 #include <linux/async.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -1742,6 +1743,8 @@
 		 */
 		list_del_init(&dev->kobj.entry);
 		spin_unlock(&devices_kset->list_lock);
+		/* Disable all device's runtime power management */
+		pm_runtime_disable(dev);
 
 		if (dev->bus && dev->bus->shutdown) {
 			dev_dbg(dev, "shutdown\n");
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 06ed6b4..3719c94 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -226,13 +226,13 @@
 	int loading = simple_strtol(buf, NULL, 10);
 	int i;
 
+	mutex_lock(&fw_lock);
+
+	if (!fw_priv->fw)
+		goto out;
+
 	switch (loading) {
 	case 1:
-		mutex_lock(&fw_lock);
-		if (!fw_priv->fw) {
-			mutex_unlock(&fw_lock);
-			break;
-		}
 		firmware_free_data(fw_priv->fw);
 		memset(fw_priv->fw, 0, sizeof(struct firmware));
 		/* If the pages are not owned by 'struct firmware' */
@@ -243,7 +243,6 @@
 		fw_priv->page_array_size = 0;
 		fw_priv->nr_pages = 0;
 		set_bit(FW_STATUS_LOADING, &fw_priv->status);
-		mutex_unlock(&fw_lock);
 		break;
 	case 0:
 		if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
@@ -274,7 +273,8 @@
 		fw_load_abort(fw_priv);
 		break;
 	}
-
+out:
+	mutex_unlock(&fw_lock);
 	return count;
 }
 
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index 1507915..d9cd600 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -288,7 +288,7 @@
 {
 	unsigned long irqflags;
 	int ret = 0;
-	unsigned int ticks = msecs_to_jiffies(timeout);
+	unsigned long ticks = msecs_to_jiffies(timeout);
 
 	spin_lock_irqsave(&lock->lock, irqflags);
 
@@ -359,7 +359,7 @@
 	/* Wait while the lock remains in an incompatible state */
 
 	while (lock->state != _UNLOCKED) {
-		unsigned int elapsed;
+		signed long elapsed;
 
 		spin_unlock_irqrestore(&lock->lock, irqflags);
 
@@ -373,7 +373,7 @@
 			goto done;
 		}
 
-		ticks = elapsed;
+		ticks = (unsigned long) elapsed;
 	}
 
 dolock:
@@ -447,7 +447,7 @@
 	struct genlock *lock;
 	unsigned long irqflags;
 	int ret = 0;
-	unsigned int ticks = msecs_to_jiffies(timeout);
+	unsigned long ticks = msecs_to_jiffies(timeout);
 
 	if (IS_ERR_OR_NULL(handle)) {
 		GENLOCK_LOG_ERR("Invalid handle\n");
@@ -474,7 +474,7 @@
 	}
 
 	while (lock->state != _UNLOCKED) {
-		unsigned int elapsed;
+		signed long elapsed;
 
 		spin_unlock_irqrestore(&lock->lock, irqflags);
 
@@ -488,7 +488,7 @@
 			break;
 		}
 
-		ticks = elapsed;
+		ticks = (unsigned long) elapsed;
 	}
 
 done:
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 793f796..5693ece 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -127,12 +127,13 @@
 		       nid, K(node_page_state(nid, NR_WRITEBACK)),
 		       nid, K(node_page_state(nid, NR_FILE_PAGES)),
 		       nid, K(node_page_state(nid, NR_FILE_MAPPED)),
-		       nid, K(node_page_state(nid, NR_ANON_PAGES)
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+		       nid, K(node_page_state(nid, NR_ANON_PAGES)
 			+ node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) *
-			HPAGE_PMD_NR
+			HPAGE_PMD_NR),
+#else
+		       nid, K(node_page_state(nid, NR_ANON_PAGES)),
 #endif
-		       ),
 		       nid, K(node_page_state(nid, NR_SHMEM)),
 		       nid, node_page_state(nid, NR_KERNEL_STACK) *
 				THREAD_SIZE / 1024,
@@ -143,13 +144,14 @@
 		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
 				node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
 		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
-		       nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+		       nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))
 			, nid,
 			K(node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) *
-			HPAGE_PMD_NR)
+			HPAGE_PMD_NR));
+#else
+		       nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
 #endif
-		       );
 	n += hugetlb_report_node_meminfo(nid, buf + n);
 	return n;
 }
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 577f4fd..184cf54 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -278,6 +278,9 @@
  * If a deferred resume was requested while the callback was running then carry
  * it out; otherwise send an idle notification for the device (if the suspend
  * failed) or for its parent (if the suspend succeeded).
+ * If ->runtime_suspend failed with -EAGAIN or -EBUSY, and if the RPM_AUTO
+ * flag is set and the next autosuspend-delay expiration time is in the
+ * future, schedule another autosuspend attempt.
  *
  * This function must be called under dev->power.lock with interrupts disabled.
  */
@@ -389,10 +392,21 @@
 	if (retval) {
 		__update_runtime_status(dev, RPM_ACTIVE);
 		dev->power.deferred_resume = 0;
-		if (retval == -EAGAIN || retval == -EBUSY)
+		if (retval == -EAGAIN || retval == -EBUSY) {
 			dev->power.runtime_error = 0;
-		else
+
+			/*
+			 * If the callback routine failed an autosuspend, and
+			 * if the last_busy time has been updated so that there
+			 * is a new autosuspend expiration time, automatically
+			 * reschedule another autosuspend.
+			 */
+			if ((rpmflags & RPM_AUTO) &&
+			    pm_runtime_autosuspend_expiration(dev) != 0)
+				goto repeat;
+		} else {
 			pm_runtime_cancel_pending(dev);
+		}
 	} else {
  no_callback:
 		__update_runtime_status(dev, RPM_SUSPENDED);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 8f4ef65..1dab802 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1716,7 +1716,7 @@
 	case CCISS_BIG_PASSTHRU:
 		return cciss_bigpassthru(h, argp);
 
-	/* scsi_cmd_ioctl handles these, below, though some are not */
+	/* scsi_cmd_blk_ioctl handles these, below, though some are not */
 	/* very meaningful for cciss.  SG_IO is the main one people want. */
 
 	case SG_GET_VERSION_NUM:
@@ -1727,9 +1727,9 @@
 	case SG_EMULATED_HOST:
 	case SG_IO:
 	case SCSI_IOCTL_SEND_COMMAND:
-		return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
+		return scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
 
-	/* scsi_cmd_ioctl would normally handle these, below, but */
+	/* scsi_cmd_blk_ioctl would normally handle these, below, but */
 	/* they aren't a good fit for cciss, as CD-ROMs are */
 	/* not supported, and we don't have any bus/target/lun */
 	/* which we present to the kernel. */
@@ -4533,6 +4533,13 @@
 		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
 		pmcsr |= PCI_D0;
 		pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+		/*
+		 * The P600 requires a small delay when changing states.
+		 * Otherwise we may think the board did not reset and we bail.
+		 * This for kdump only and is particular to the P600.
+		 */
+		msleep(500);
 	}
 	return 0;
 }
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 0e376d4..7333b9e 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -1744,12 +1744,11 @@
 static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode,
     unsigned int cmd, unsigned long arg)
 {
-	struct gendisk *disk = bdev->bd_disk;
 	void __user *usermem = (void __user *) arg;
 	int ret;
 
 	mutex_lock(&ub_mutex);
-	ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem);
+	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem);
 	mutex_unlock(&ub_mutex);
 
 	return ret;
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 079c088..5d7a934 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -236,8 +236,8 @@
 	if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
 		return -ENOTTY;
 
-	return scsi_cmd_ioctl(disk->queue, disk, mode, cmd,
-			      (void __user *)data);
+	return scsi_cmd_blk_ioctl(bdev, mode, cmd,
+				  (void __user *)data);
 }
 
 /* We provide getgeo only to please some old bootloader/partitioning tools */
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index 5cf2993..54139d0 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -667,7 +667,7 @@
 
 	if (operation == READ)
 		blkif->st_rd_sect += preq.nr_sects;
-	else if (operation == WRITE || operation == WRITE_FLUSH)
+	else if (operation & WRITE)
 		blkif->st_wr_sect += preq.nr_sects;
 
 	return 0;
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 695d441..55bc2fa 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -374,6 +374,11 @@
 
 	/* load patch and sysconfig files for AR3012 */
 	if (id->driver_info & BTUSB_ATH3012) {
+
+		/* New firmware with patch and sysconfig files already loaded */
+		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001)
+			return -ENODEV;
+
 		ret = ath3k_load_patch(udev);
 		if (ret < 0) {
 			BT_ERR("Loading patch file failed");
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 14776e5..e4b6b6b 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -54,11 +54,15 @@
 #define BTUSB_BCM92035		0x10
 #define BTUSB_BROKEN_ISOC	0x20
 #define BTUSB_WRONG_SCO_MTU	0x40
+#define BTUSB_ATH3012		0x80
 
 static struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
 
+	/* Broadcom SoftSailing reporting vendor specific */
+	{ USB_DEVICE(0x05ac, 0x21e1) },
+
 	/* Apple MacBookPro 7,1 */
 	{ USB_DEVICE(0x05ac, 0x8213) },
 
@@ -71,9 +75,15 @@
 	/* Apple MacBookAir3,1, MacBookAir3,2 */
 	{ USB_DEVICE(0x05ac, 0x821b) },
 
+	/* Apple MacBookAir4,1 */
+	{ USB_DEVICE(0x05ac, 0x821f) },
+
 	/* Apple MacBookPro8,2 */
 	{ USB_DEVICE(0x05ac, 0x821a) },
 
+	/* Apple MacMini5,1 */
+	{ USB_DEVICE(0x05ac, 0x8281) },
+
 	/* AVM BlueFRITZ! USB v2.0 */
 	{ USB_DEVICE(0x057c, 0x3800) },
 
@@ -109,7 +119,7 @@
 	{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
 
 	/* Atheros 3012 with sflash firmware */
-	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -913,6 +923,15 @@
 	if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
 		return -ENODEV;
 
+	if (id->driver_info & BTUSB_ATH3012) {
+		struct usb_device *udev = interface_to_usbdev(intf);
+
+		/* Old firmware would otherwise let ath3k driver load
+		 * patch and sysconfig files */
+		if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
+			return -ENODEV;
+	}
+
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 332922e..8f51e2d 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -48,6 +48,7 @@
 static int hcismd_set_enable(const char *val, struct kernel_param *kp);
 module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
 
+static void hci_dev_smd_open(struct work_struct *worker);
 static void hci_dev_restart(struct work_struct *worker);
 
 struct hci_smd_data {
@@ -315,6 +316,8 @@
 	struct hci_dev *hdev = hs.hdev;
 	struct hci_smd_data *hsmd = &hs;
 	struct work_struct *reset_worker;
+	struct work_struct *open_worker;
+
 	int len = 0;
 
 	if (!hdev) {
@@ -334,6 +337,13 @@
 	case SMD_EVENT_OPEN:
 		BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
 		hci_smd_open(hdev);
+		open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
+		if (!open_worker) {
+			BT_ERR("Out of memory");
+			break;
+		}
+		INIT_WORK(open_worker, hci_dev_smd_open);
+		schedule_work(open_worker);
 		break;
 	case SMD_EVENT_CLOSE:
 		BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
@@ -384,9 +394,24 @@
 
 }
 
-static int hci_smd_register_dev(struct hci_smd_data *hsmd)
+static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
 {
-	static struct hci_dev *hdev;
+	struct hci_dev *hdev;
+
+	hdev = hsmd->hdev;
+
+	if (hci_register_dev(hdev) < 0) {
+		BT_ERR("Can't register HCI device");
+		hci_free_dev(hdev);
+		hsmd->hdev = NULL;
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int hci_smd_register_smd(struct hci_smd_data *hsmd)
+{
+	struct hci_dev *hdev;
 	int rc;
 
 	/* Initialize and register HCI device */
@@ -421,7 +446,7 @@
 	if (rc < 0) {
 		BT_ERR("Cannot open the command channel");
 		hci_free_dev(hdev);
-		hdev = NULL;
+		hsmd->hdev = NULL;
 		return -ENODEV;
 	}
 
@@ -430,18 +455,13 @@
 	if (rc < 0) {
 		BT_ERR("Failed to open the Data channel");
 		hci_free_dev(hdev);
-		hdev = NULL;
+		hsmd->hdev = NULL;
 		return -ENODEV;
 	}
 
 	/* Disable the read interrupts on the channel */
 	smd_disable_read_intr(hsmd->event_channel);
 	smd_disable_read_intr(hsmd->data_channel);
-	if (hci_register_dev(hdev) < 0) {
-		BT_ERR("Can't register HCI device");
-		hci_free_dev(hdev);
-		return -ENODEV;
-	}
 	return 0;
 }
 
@@ -478,7 +498,15 @@
 {
 	mutex_lock(&hci_smd_enable);
 	hci_smd_deregister_dev(&hs);
-	hci_smd_register_dev(&hs);
+	hci_smd_register_smd(&hs);
+	mutex_unlock(&hci_smd_enable);
+	kfree(worker);
+}
+
+static void hci_dev_smd_open(struct work_struct *worker)
+{
+	mutex_lock(&hci_smd_enable);
+	hci_smd_hci_register_dev(&hs);
 	mutex_unlock(&hci_smd_enable);
 	kfree(worker);
 }
@@ -497,7 +525,7 @@
 	switch (hcismd_set) {
 
 	case 1:
-		hci_smd_register_dev(&hs);
+		hci_smd_register_smd(&hs);
 	break;
 	case 0:
 		hci_smd_deregister_dev(&hs);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 75fb965..b693cbd 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2741,12 +2741,11 @@
 {
 	void __user *argp = (void __user *)arg;
 	int ret;
-	struct gendisk *disk = bdev->bd_disk;
 
 	/*
 	 * Try the generic SCSI command ioctl's first.
 	 */
-	ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
+	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
 	if (ret != -ENOTTY)
 		return ret;
 
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7d28604..926bd69 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
@@ -49,11 +50,14 @@
 #define EVENT_MASK_SIZE 1000
 #define USER_SPACE_DATA 8000
 #define PKT_SIZE 4096
-#define MAX_EQUIP_ID 12
+#define MAX_EQUIP_ID 15
+#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_registration;
-extern unsigned int diag_threshold_registration;
+extern unsigned int diag_max_reg;
+extern unsigned int diag_threshold_reg;
 
 #define APPEND_DEBUG(ch) \
 do {							\
@@ -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;
@@ -156,11 +164,16 @@
 	unsigned char *buf_in_qdsp_1;
 	unsigned char *buf_in_qdsp_2;
 	unsigned char *buf_in_qdsp_cntl;
-	unsigned char *buf_in_wcnss;
+	unsigned char *buf_in_wcnss_1;
+	unsigned char *buf_in_wcnss_2;
 	unsigned char *buf_in_wcnss_cntl;
 	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;
@@ -171,7 +184,8 @@
 	int in_busy_2;
 	int in_busy_qdsp_1;
 	int in_busy_qdsp_2;
-	int in_busy_wcnss;
+	int in_busy_wcnss_1;
+	int in_busy_wcnss_2;
 	int read_len_legacy;
 	unsigned char *hdlc_buf;
 	unsigned hdlc_count;
@@ -190,6 +204,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;
@@ -203,7 +224,8 @@
 	struct diag_request *write_ptr_svc;
 	struct diag_request *write_ptr_qdsp_1;
 	struct diag_request *write_ptr_qdsp_2;
-	struct diag_request *write_ptr_wcnss;
+	struct diag_request *write_ptr_wcnss_1;
+	struct diag_request *write_ptr_wcnss_2;
 	int logging_mode;
 	int mask_check;
 	int logging_process_id;
@@ -228,6 +250,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 +261,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 e24d896..7e2333a 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 */
@@ -60,8 +60,8 @@
 static unsigned int max_clients = 15;
 static unsigned int threshold_client_limit = 30;
 /* This is the maximum number of pkt registrations supported at initialization*/
-unsigned int diag_max_registration = 600;
-unsigned int diag_threshold_registration = 750;
+unsigned int diag_max_reg = 600;
+unsigned int diag_threshold_reg = 750;
 
 /* Timer variables */
 static struct timer_list drain_timer;
@@ -230,7 +230,7 @@
 	}
 #endif /* DIAG over USB */
 	/* Delete the pkt response table entry for the exiting process */
-	for (i = 0; i < diag_max_registration; i++)
+	for (i = 0; i < diag_max_reg; i++)
 			if (driver->table[i].process_id == current->tgid)
 					driver->table[i].process_id = 0;
 
@@ -286,13 +286,13 @@
 	mutex_lock(&driver->diagchar_mutex);
 	/* reset polling flag */
 	driver->polling_reg_flag = 0;
-	for (i = 0; i < diag_max_registration; i++) {
+	for (i = 0; i < diag_max_reg; i++) {
 		if (driver->table[i].client_id == proc_num) {
 			driver->table[i].process_id = 0;
 		}
 	}
 	/* re-scan the registration table */
-	for (i = 0; i < diag_max_registration; i++) {
+	for (i = 0; i < diag_max_reg; i++) {
 		if (diag_find_polling_reg(i) == 1) {
 			driver->polling_reg_flag = 1;
 			break;
@@ -335,7 +335,7 @@
 		struct bindpkt_params_per_process *pkt_params =
 			 (struct bindpkt_params_per_process *) ioarg;
 		mutex_lock(&driver->diagchar_mutex);
-		for (i = 0; i < diag_max_registration; i++) {
+		for (i = 0; i < diag_max_reg; i++) {
 			if (driver->table[i].process_id == 0) {
 				diag_add_reg(i, pkt_params->params,
 						&success, &count_entries);
@@ -347,19 +347,20 @@
 				}
 			}
 		}
-		if (i < diag_threshold_registration) {
+		if (i < diag_threshold_reg) {
 			/* Increase table size by amount required */
-			diag_max_registration += pkt_params->count -
+			diag_max_reg += pkt_params->count -
 							 count_entries;
 			/* Make sure size doesnt go beyond threshold */
-			if (diag_max_registration > diag_threshold_registration)
-				diag_max_registration =
-						 diag_threshold_registration;
+			if (diag_max_reg > diag_threshold_reg) {
+				diag_max_reg = diag_threshold_reg;
+				pr_info("diag: best case memory allocation\n");
+			}
 			temp_buf = krealloc(driver->table,
-					 diag_max_registration*sizeof(struct
+					 diag_max_reg*sizeof(struct
 					 diag_master_table), GFP_KERNEL);
 			if (!temp_buf) {
-				diag_max_registration -= pkt_params->count -
+				diag_max_reg -= pkt_params->count -
 							 count_entries;
 				pr_alert("diag: Insufficient memory for reg.");
 				mutex_unlock(&driver->diagchar_mutex);
@@ -367,7 +368,7 @@
 			} else {
 				driver->table = temp_buf;
 			}
-			for (j = i; j < diag_max_registration; j++) {
+			for (j = i; j < diag_max_reg; j++) {
 				diag_add_reg(j, pkt_params->params,
 						&success, &count_entries);
 				if (pkt_params->count > count_entries) {
@@ -377,6 +378,7 @@
 					return success;
 				}
 			}
+			mutex_unlock(&driver->diagchar_mutex);
 		} else {
 			mutex_unlock(&driver->diagchar_mutex);
 			pr_err("Max size reached, Pkt Registration failed for"
@@ -422,7 +424,8 @@
 			driver->in_busy_2 = 1;
 			driver->in_busy_qdsp_1 = 1;
 			driver->in_busy_qdsp_2 = 1;
-			driver->in_busy_wcnss = 1;
+			driver->in_busy_wcnss_1 = 1;
+			driver->in_busy_wcnss_2 = 1;
 #ifdef CONFIG_DIAG_SDIO_PIPE
 			driver->in_busy_sdio = 1;
 #endif
@@ -432,7 +435,8 @@
 			driver->in_busy_2 = 0;
 			driver->in_busy_qdsp_1 = 0;
 			driver->in_busy_qdsp_2 = 0;
-			driver->in_busy_wcnss = 0;
+			driver->in_busy_wcnss_1 = 0;
+			driver->in_busy_wcnss_2 = 0;
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -463,9 +467,10 @@
 			diagfwd_disconnect();
 			driver->in_busy_1 = 0;
 			driver->in_busy_2 = 0;
+			driver->in_busy_qdsp_1 = 0;
 			driver->in_busy_qdsp_2 = 0;
-			driver->in_busy_qdsp_2 = 0;
-			driver->in_busy_wcnss = 0;
+			driver->in_busy_wcnss_1 = 0;
+			driver->in_busy_wcnss_2 = 0;
 			/* Poll SMD channels to check for data*/
 			if (driver->ch)
 				queue_work(driver->diag_wq,
@@ -605,16 +610,27 @@
 			driver->in_busy_qdsp_2 = 0;
 		}
 		/* copy wncss data */
-		if (driver->in_busy_wcnss == 1) {
+		if (driver->in_busy_wcnss_1 == 1) {
 			num_data++;
 			/*Copy the length of data being passed*/
 			COPY_USER_SPACE_OR_EXIT(buf+ret,
-				 (driver->write_ptr_wcnss->length), 4);
+				 (driver->write_ptr_wcnss_1->length), 4);
 			/*Copy the actual data being passed*/
 			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
-							buf_in_wcnss),
-					 driver->write_ptr_wcnss->length);
-			driver->in_busy_wcnss = 0;
+							buf_in_wcnss_1),
+					 driver->write_ptr_wcnss_1->length);
+			driver->in_busy_wcnss_1 = 0;
+		}
+		if (driver->in_busy_wcnss_2 == 1) {
+			num_data++;
+			/*Copy the length of data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+				 (driver->write_ptr_wcnss_2->length), 4);
+			/*Copy the actual data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
+							buf_in_wcnss_2),
+					 driver->write_ptr_wcnss_2->length);
+			driver->in_busy_wcnss_2 = 0;
 		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		/* copy 9K data over SDIO */
@@ -766,6 +782,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 079e04b..65ddfec 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;
@@ -218,7 +271,8 @@
 			queue_work(driver->diag_wq, &(driver->
 						diag_read_smd_qdsp_work));
 		}  else if (proc_num == WCNSS_DATA) {
-			driver->in_busy_wcnss = 0;
+			driver->in_busy_wcnss_1 = 0;
+			driver->in_busy_wcnss_2 = 0;
 			queue_work(driver->diag_wq, &(driver->
 				diag_read_smd_wcnss_work));
 		}
@@ -290,11 +344,21 @@
 
 void __diag_smd_wcnss_send_req(void)
 {
-	void *buf = driver->buf_in_wcnss;
-	int *in_busy_wcnss_ptr = &(driver->in_busy_wcnss);
-	struct diag_request *write_ptr_wcnss = driver->write_ptr_wcnss;
+	void *buf = NULL;
+	int *in_busy_wcnss_ptr = NULL;
+	struct diag_request *write_ptr_wcnss = NULL;
 
-	if ((!driver->in_busy_wcnss) && driver->ch_wcnss && buf) {
+	if (!driver->in_busy_wcnss_1) {
+		buf = driver->buf_in_wcnss_1;
+		write_ptr_wcnss = driver->write_ptr_wcnss_1;
+		in_busy_wcnss_ptr = &(driver->in_busy_wcnss_1);
+	} else if (!driver->in_busy_wcnss_2) {
+		buf = driver->buf_in_wcnss_2;
+		write_ptr_wcnss = driver->write_ptr_wcnss_2;
+		in_busy_wcnss_ptr = &(driver->in_busy_wcnss_2);
+	}
+
+	if (driver->ch_wcnss && buf) {
 		int r = smd_read_avail(driver->ch_wcnss);
 		if (r > IN_BUF_SIZE) {
 			if (r < MAX_IN_BUF_SIZE) {
@@ -400,8 +464,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 +510,19 @@
 
 }
 
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bits)
+void diag_toggle_event_mask(int toggle)
+{
+	uint8_t *ptr = driver->event_masks;
+
+	mutex_lock(&driver->diagchar_mutex);
+	if (toggle)
+		memset(ptr, 0xFF, EVENT_MASK_SIZE);
+	else
+		memset(ptr, 0, EVENT_MASK_SIZE);
+	mutex_unlock(&driver->diagchar_mutex);
+}
+
+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 +532,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,13 +543,9 @@
 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;
+	int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
 	struct mask_info *ptr = (struct mask_info *)driver->log_masks;
 
 	mutex_lock(&driver->diagchar_mutex);
@@ -485,8 +556,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 +643,124 @@
 	}
 }
 
+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;
+
+	for (i = 0; i < MAX_EQUIP_ID; i++) {
+		size = (ptr->num_items+7)/8;
+		/* 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 +773,94 @@
 	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;
+			memcpy(driver->apps_rsp_buf+6, driver->event_masks,
+							 EVENT_LAST_ID/8+1);
+			/* 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);
+		diag_toggle_event_mask(*(buf+1));
+		diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#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++;
@@ -598,7 +876,7 @@
 	}
 
 	pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
-	for (i = 0; i < diag_max_registration; i++) {
+	for (i = 0; i < diag_max_reg; i++) {
 		entry = driver->table[i];
 		if (entry.process_id != NO_PROCESS) {
 			if (entry.cmd_code == cmd_code && entry.subsys_id ==
@@ -632,70 +910,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 +993,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 +1096,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 +1133,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 +1145,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++)
@@ -1031,7 +1272,8 @@
 	driver->in_busy_2 = 0;
 	driver->in_busy_qdsp_1 = 0;
 	driver->in_busy_qdsp_2 = 0;
-	driver->in_busy_wcnss = 0;
+	driver->in_busy_wcnss_1 = 0;
+	driver->in_busy_wcnss_2 = 0;
 
 	/* Poll SMD channels to check for data*/
 	queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
@@ -1065,7 +1307,8 @@
 		driver->in_busy_2 = 1;
 		driver->in_busy_qdsp_1 = 1;
 		driver->in_busy_qdsp_2 = 1;
-		driver->in_busy_wcnss = 1;
+		driver->in_busy_wcnss_1 = 1;
+		driver->in_busy_wcnss_2 = 1;
 	}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
@@ -1097,8 +1340,13 @@
 		driver->in_busy_qdsp_2 = 0;
 		APPEND_DEBUG('P');
 		queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
-	} else if (buf == (void *)driver->buf_in_wcnss) {
-		driver->in_busy_wcnss = 0;
+	} else if (buf == driver->buf_in_wcnss_1) {
+		driver->in_busy_wcnss_1 = 0;
+		APPEND_DEBUG('r');
+		queue_work(driver->diag_wq,
+			 &(driver->diag_read_smd_wcnss_work));
+	} else if (buf == driver->buf_in_wcnss_2) {
+		driver->in_busy_wcnss_2 = 0;
 		APPEND_DEBUG('R');
 		queue_work(driver->diag_wq,
 			 &(driver->diag_read_smd_wcnss_work));
@@ -1311,6 +1559,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)
@@ -1331,9 +1599,33 @@
 		if (driver->buf_in_qdsp_2 == NULL)
 			goto err;
 	}
-	if (driver->buf_in_wcnss == NULL) {
-		driver->buf_in_wcnss = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_wcnss == NULL)
+	if (driver->buf_in_wcnss_1 == NULL) {
+		driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		if (driver->buf_in_wcnss_1 == NULL)
+			goto err;
+	}
+	if (driver->buf_in_wcnss_2 == NULL) {
+		driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		if (driver->buf_in_wcnss_2 == 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 &&
@@ -1354,7 +1646,7 @@
 	if (driver->log_masks == NULL &&
 	    (driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL)) == NULL)
 		goto err;
-	driver->log_masks_length = 8*MAX_EQUIP_ID;
+	driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
 	if (driver->event_masks == NULL &&
 	    (driver->event_masks = kzalloc(EVENT_MASK_SIZE,
 					    GFP_KERNEL)) == NULL)
@@ -1374,7 +1666,7 @@
 							, GFP_KERNEL)) == NULL)
 		goto err;
 	if (driver->table == NULL &&
-	     (driver->table = kzalloc(diag_max_registration*
+	     (driver->table = kzalloc(diag_max_reg*
 		      sizeof(struct diag_master_table),
 		       GFP_KERNEL)) == NULL)
 		goto err;
@@ -1402,12 +1694,19 @@
 		if (driver->write_ptr_qdsp_2 == NULL)
 			goto err;
 	}
-	if (driver->write_ptr_wcnss == NULL) {
-		driver->write_ptr_wcnss = kzalloc(
+	if (driver->write_ptr_wcnss_1 == NULL) {
+		driver->write_ptr_wcnss_1 = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_wcnss == NULL)
+		if (driver->write_ptr_wcnss_1 == NULL)
 			goto err;
 	}
+	if (driver->write_ptr_wcnss_2 == NULL) {
+		driver->write_ptr_wcnss_2 = kzalloc(
+			sizeof(struct diag_request), GFP_KERNEL);
+		if (driver->write_ptr_wcnss_2 == NULL)
+			goto err;
+	}
+
 	if (driver->usb_read_ptr == NULL) {
 		driver->usb_read_ptr = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
@@ -1419,7 +1718,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 +1726,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 +1749,18 @@
 	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_in_wcnss_1);
+		kfree(driver->buf_in_wcnss_2);
+		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);
@@ -1459,7 +1775,8 @@
 		kfree(driver->write_ptr_2);
 		kfree(driver->write_ptr_qdsp_1);
 		kfree(driver->write_ptr_qdsp_2);
-		kfree(driver->write_ptr_wcnss);
+		kfree(driver->write_ptr_wcnss_1);
+		kfree(driver->write_ptr_wcnss_2);
 		kfree(driver->usb_read_ptr);
 		kfree(driver->apps_rsp_buf);
 		kfree(driver->user_space_data);
@@ -1482,11 +1799,18 @@
 #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_in_wcnss_1);
+	kfree(driver->buf_in_wcnss_2);
+	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);
@@ -1501,7 +1825,8 @@
 	kfree(driver->write_ptr_2);
 	kfree(driver->write_ptr_qdsp_1);
 	kfree(driver->write_ptr_qdsp_2);
-	kfree(driver->write_ptr_wcnss);
+	kfree(driver->write_ptr_wcnss_1);
+	kfree(driver->write_ptr_wcnss_2);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
 	kfree(driver->user_space_data);
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..171168f 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;
 	}
 }
 
@@ -148,6 +160,7 @@
 						 bindpkt_params), GFP_KERNEL);
 				if (temp == NULL) {
 					pr_alert("diag: Memory alloc fail\n");
+					kfree(pkt_params);
 					return;
 				}
 				for (j = 0; j < pkt_params->count; j++) {
@@ -259,6 +272,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 +297,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 +309,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/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index f5367ef..d1a9fe6 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -122,19 +122,19 @@
 				"failed to enable clock in probe\n");
 		return -EPERM;
 	}
-	val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET) &
-					PRNG_LFSR_CFG_MASK;
-	val |= PRNG_LFSR_CFG_MASK;
-	writel_relaxed(val, msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
-
-	/* The PRNG CONFIG register should be first written before reading */
-	mb();
-
 	/* Enable PRNG h/w only if it is NOT ON */
 	val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET) &
 					PRNG_HW_ENABLE;
 	/* PRNG H/W is not ON */
 	if (val != PRNG_HW_ENABLE) {
+		val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET) &
+					PRNG_LFSR_CFG_MASK;
+		val |= PRNG_LFSR_CFG_MASK;
+		writel_relaxed(val, msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
+
+		/* The PRNG CONFIG register should be first written */
+		mb();
+
 		reg_val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET)
 						& PRNG_CONFIG_MASK;
 		reg_val |= PRNG_HW_ENABLE;
@@ -242,9 +242,6 @@
 
 static int __init msm_rng_init(void)
 {
-	if (cpu_is_apq8064())
-		return -ENODEV;
-
 	return platform_driver_register(&rng_driver);
 }
 
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index bd48925..59013e3 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -33,6 +33,8 @@
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 #endif
+#include <mach/msm_subsystem_map.h>
+#include <mach/iommu_domains.h>
 
 #define DRIVER_NAME "msm_rotator"
 
@@ -146,6 +148,33 @@
 	CLK_SUSPEND,
 };
 
+int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
+	unsigned long *start, unsigned long *len,
+	struct ion_handle **pihdl)
+{
+	if (!msm_rotator_dev->client)
+		return -EINVAL;
+
+	*pihdl = ion_import_fd(msm_rotator_dev->client, mem_id);
+	if (IS_ERR_OR_NULL(*pihdl)) {
+		pr_err("ion_import_fd() failed\n");
+		return PTR_ERR(*pihdl);
+	}
+	pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
+		ion_share(msm_rotator_dev->client, *pihdl));
+
+	if (ion_map_iommu(msm_rotator_dev->client,
+		*pihdl,	ROTATOR_DOMAIN, GEN_POOL,
+		SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
+		pr_err("ion_map_iommu() failed\n");
+		return -EINVAL;
+	}
+
+	pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
+		__func__, mem_id, *start, *len);
+	return 0;
+}
+
 int msm_rotator_imem_allocate(int requestor)
 {
 	int rc = 0;
@@ -748,8 +777,9 @@
 	return 0;
 }
 
-static int get_img(struct msmfb_data *fbd, unsigned long *start,
-	unsigned long *len, struct file **p_file, struct ion_handle **p_ihdl)
+static int get_img(struct msmfb_data *fbd, unsigned char src,
+	unsigned long *start, unsigned long *len, struct file **p_file,
+	int *p_need, struct ion_handle **p_ihdl)
 {
 	int ret = 0;
 #ifdef CONFIG_FB
@@ -760,20 +790,30 @@
 	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);
-		if (file == NULL)
+		if (file == NULL) {
+			pr_err("fget_light returned NULL\n");
 			return -EINVAL;
+		}
 
 		if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
 			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
-			if (get_fb_phys_info(start, len, fb_num))
+			if (get_fb_phys_info(start, len, fb_num,
+				ROTATOR_SUBSYSTEM_ID)) {
+				pr_err("get_fb_phys_info() failed\n");
 				ret = -1;
-			else
+			} else {
 				*p_file = file;
-		} else
+				*p_need = put_needed;
+			}
+		} else {
+			pr_err("invalid FB_MAJOR failed\n");
 			ret = -1;
+		}
 		if (ret)
 			fput_light(file, put_needed);
 		return ret;
@@ -781,15 +821,8 @@
 #endif
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	*p_ihdl = ion_import_fd(msm_rotator_dev->client,
-		fbd->memory_id);
-	if (IS_ERR_OR_NULL(*p_ihdl))
-		return PTR_ERR(*p_ihdl);
-	if (!ion_phys(msm_rotator_dev->client, *p_ihdl, start,
-		(size_t *) len))
-		return 0;
-	else
-		return -ENOMEM;
+	return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
+		len, p_ihdl);
 #endif
 #ifdef CONFIG_ANDROID_PMEM
 	if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
@@ -807,8 +840,13 @@
 		put_pmem_file(p_file);
 #endif
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	if (!IS_ERR_OR_NULL(p_ihdl))
+	if (!IS_ERR_OR_NULL(p_ihdl)) {
+		pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
+		ion_unmap_iommu(msm_rotator_dev->client,
+			p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
+
 		ion_free(msm_rotator_dev->client, p_ihdl);
+	}
 #endif
 }
 static int msm_rotator_do_rotate(unsigned long arg)
@@ -822,6 +860,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,16 +911,18 @@
 		goto do_rotate_unlock_mutex;
 	}
 
-	rc = get_img(&info.src, (unsigned long *)&in_paddr,
-			(unsigned long *)&src_len, &srcp0_file, &srcp0_ihdl);
+	rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
+			(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);
 		goto do_rotate_unlock_mutex;
 	}
 
-	rc = get_img(&info.dst, (unsigned long *)&out_paddr,
-			(unsigned long *)&dst_len, &dstp0_file, &dstp0_ihdl);
+	rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
+			(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);
@@ -909,9 +950,9 @@
 			goto do_rotate_unlock_mutex;
 		}
 
-		rc = get_img(&info.src_chroma,
+		rc = get_img(&info.src_chroma, 1,
 				(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",
@@ -919,9 +960,9 @@
 			goto do_rotate_unlock_mutex;
 		}
 
-		rc = get_img(&info.dst_chroma,
+		rc = get_img(&info.dst_chroma, 0,
 				(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 +1130,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);
@@ -1502,7 +1548,8 @@
 		clk_disable(msm_rotator_dev->imem_clk);
 #endif
 	if (ver != pdata->hardware_version_number)
-		pr_info("%s: invalid HW version\n", DRIVER_NAME);
+		pr_info("%s: invalid HW version ver 0x%x\n",
+			DRIVER_NAME, ver);
 
 	msm_rotator_dev->irq = platform_get_irq(pdev, 0);
 	if (msm_rotator_dev->irq < 0) {
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index c044060..75ec72d 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -42,3 +42,4 @@
 
 # ARM SoC drivers
 obj-$(CONFIG_UX500_SOC_DB8500)		+= db8500-cpufreq.o
+obj-$(CONFIG_MSM_DCVS)			+= cpufreq_gov_msm.o
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/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
new file mode 100644
index 0000000..9c49f80
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -0,0 +1,176 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/kobject.h>
+#include <linux/cpufreq.h>
+#include <linux/platform_device.h>
+#include <mach/msm_dcvs.h>
+
+struct msm_gov {
+	int cpu;
+	unsigned int cur_freq;
+	unsigned int min_freq;
+	unsigned int max_freq;
+	struct msm_dcvs_freq gov_notifier;
+	struct cpufreq_policy *policy;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct mutex, gov_mutex);
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_gov, msm_gov_info);
+static char core_name[NR_CPUS][10];
+
+static void msm_gov_check_limits(struct cpufreq_policy *policy)
+{
+	struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
+
+	if (policy->max < gov->cur_freq)
+		__cpufreq_driver_target(policy, policy->max,
+				CPUFREQ_RELATION_H);
+	else if (policy->min > gov->min_freq)
+		__cpufreq_driver_target(policy, policy->min,
+				CPUFREQ_RELATION_L);
+	else
+		__cpufreq_driver_target(policy, gov->cur_freq,
+				CPUFREQ_RELATION_L);
+
+	gov->cur_freq = policy->cur;
+	gov->min_freq = policy->min;
+	gov->max_freq = policy->max;
+}
+
+static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
+		unsigned int freq)
+{
+	int ret = -EINVAL;
+	struct msm_gov *gov =
+		container_of(self, struct msm_gov, gov_notifier);
+
+	mutex_lock(&per_cpu(gov_mutex, gov->cpu));
+
+	if (freq < gov->min_freq)
+		freq = gov->min_freq;
+	if (freq > gov->max_freq)
+		freq = gov->max_freq;
+
+	ret = __cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
+	gov->cur_freq = gov->policy->cur;
+
+	mutex_unlock(&per_cpu(gov_mutex, gov->cpu));
+
+	if (!ret)
+		return gov->cur_freq;
+
+	return ret;
+}
+
+static unsigned int msm_dcvs_freq_get(struct msm_dcvs_freq *self)
+{
+	struct msm_gov *gov =
+		container_of(self, struct msm_gov, gov_notifier);
+
+	return gov->cur_freq;
+}
+
+static int cpufreq_governor_msm(struct cpufreq_policy *policy,
+		unsigned int event)
+{
+	unsigned int cpu = policy->cpu;
+	int ret = 0;
+	int handle = 0;
+	struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
+	struct msm_dcvs_freq *dcvs_notifier =
+			&(per_cpu(msm_gov_info, cpu).gov_notifier);
+
+	switch (event) {
+	case CPUFREQ_GOV_START:
+		if (!cpu_online(cpu))
+			return -EINVAL;
+		BUG_ON(!policy->cur);
+		mutex_lock(&per_cpu(gov_mutex, cpu));
+		per_cpu(msm_gov_info, cpu).cpu = cpu;
+		gov->policy = policy;
+		dcvs_notifier->core_name = core_name[cpu];
+		dcvs_notifier->set_frequency = msm_dcvs_freq_set;
+		dcvs_notifier->get_frequency = msm_dcvs_freq_get;
+		handle = msm_dcvs_freq_sink_register(dcvs_notifier);
+		BUG_ON(handle < 0);
+		msm_gov_check_limits(policy);
+		mutex_unlock(&per_cpu(gov_mutex, cpu));
+		break;
+
+	case CPUFREQ_GOV_STOP:
+		mutex_lock(&per_cpu(gov_mutex, cpu));
+		msm_dcvs_freq_sink_unregister(dcvs_notifier);
+		mutex_unlock(&per_cpu(gov_mutex, cpu));
+		break;
+
+	case CPUFREQ_GOV_LIMITS:
+		mutex_lock(&per_cpu(gov_mutex, cpu));
+		msm_gov_check_limits(policy);
+		mutex_unlock(&per_cpu(gov_mutex, cpu));
+		break;
+	};
+
+	return ret;
+}
+
+struct cpufreq_governor cpufreq_gov_msm = {
+	.name = "msm-dcvs",
+	.governor = cpufreq_governor_msm,
+	.owner = THIS_MODULE,
+};
+
+static int __devinit msm_gov_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	int cpu;
+	uint32_t group_id = 0x43505530; /* CPU0 */
+	struct msm_dcvs_core_info *core = NULL;
+
+	core = pdev->dev.platform_data;
+
+	for_each_possible_cpu(cpu) {
+		mutex_init(&per_cpu(gov_mutex, cpu));
+		snprintf(core_name[cpu], 10, "cpu%d", cpu);
+		ret = msm_dcvs_register_core(core_name[cpu], group_id, core);
+		if (ret)
+			pr_err("Unable to register core for %d\n", cpu);
+	}
+
+	return cpufreq_register_governor(&cpufreq_gov_msm);
+}
+
+static int __devexit msm_gov_remove(struct platform_device *pdev)
+{
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver msm_gov_driver = {
+	.probe = msm_gov_probe,
+	.remove = __devexit_p(msm_gov_remove),
+	.driver = {
+		.name = "msm_dcvs_gov",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init cpufreq_gov_msm_init(void)
+{
+	return platform_driver_register(&msm_gov_driver);
+}
+late_initcall(cpufreq_gov_msm_init);
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index bce576d..ad683ec 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -54,6 +54,9 @@
 
 static int cpu_family = CPU_OPTERON;
 
+/* array to map SW pstate number to acpi state */
+static u32 ps_to_as[8];
+
 /* core performance boost */
 static bool cpb_capable, cpb_enabled;
 static struct msr __percpu *msrs;
@@ -80,9 +83,9 @@
 }
 
 static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data,
-		u32 pstate)
+				     u32 pstate)
 {
-	return data[pstate].frequency;
+	return data[ps_to_as[pstate]].frequency;
 }
 
 /* Return the vco fid for an input fid
@@ -926,23 +929,27 @@
 			invalidate_entry(powernow_table, i);
 			continue;
 		}
-		rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
-		if (!(hi & HW_PSTATE_VALID_MASK)) {
-			pr_debug("invalid pstate %d, ignoring\n", index);
-			invalidate_entry(powernow_table, i);
-			continue;
-		}
 
-		powernow_table[i].index = index;
+		ps_to_as[index] = i;
 
 		/* Frequency may be rounded for these */
 		if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
 				 || boot_cpu_data.x86 == 0x11) {
+
+			rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
+			if (!(hi & HW_PSTATE_VALID_MASK)) {
+				pr_debug("invalid pstate %d, ignoring\n", index);
+				invalidate_entry(powernow_table, i);
+				continue;
+			}
+
 			powernow_table[i].frequency =
 				freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7);
 		} else
 			powernow_table[i].frequency =
 				data->acpi_data.states[i].core_frequency * 1000;
+
+		powernow_table[i].index = index;
 	}
 	return 0;
 }
@@ -1189,7 +1196,8 @@
 	powernow_k8_acpi_pst_values(data, newstate);
 
 	if (cpu_family == CPU_HW_PSTATE)
-		ret = transition_frequency_pstate(data, newstate);
+		ret = transition_frequency_pstate(data,
+			data->powernow_table[newstate].index);
 	else
 		ret = transition_frequency_fidvid(data, newstate);
 	if (ret) {
@@ -1202,7 +1210,7 @@
 
 	if (cpu_family == CPU_HW_PSTATE)
 		pol->cur = find_khz_freq_from_pstate(data->powernow_table,
-				newstate);
+				data->powernow_table[newstate].index);
 	else
 		pol->cur = find_khz_freq_from_fid(data->currfid);
 	ret = 0;
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 5276bcc..0d3c4c3 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/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index 3cf303e..38a3297 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -342,11 +342,13 @@
 		else
 			op.config |= CFG_MID_FRAG;
 
-		writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A);
-		writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B);
-		writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C);
-		writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D);
-		writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E);
+		if (first_block) {
+			writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A);
+			writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B);
+			writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C);
+			writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D);
+			writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E);
+		}
 	}
 
 	memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config));
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 36144f8..9e9318a 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1279,7 +1279,7 @@
 
 		tasklet_init(&atchan->tasklet, atc_tasklet,
 				(unsigned long)atchan);
-		atc_enable_irq(atchan);
+		atc_enable_chan_irq(atdma, i);
 	}
 
 	/* set base routines */
@@ -1348,7 +1348,7 @@
 		struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 
 		/* Disable interrupts */
-		atc_disable_irq(atchan);
+		atc_disable_chan_irq(atdma, chan->chan_id);
 		tasklet_disable(&atchan->tasklet);
 
 		tasklet_kill(&atchan->tasklet);
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index 087dbf1..19ed470 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -319,28 +319,27 @@
 }
 
 
-static void atc_setup_irq(struct at_dma_chan *atchan, int on)
+static void atc_setup_irq(struct at_dma *atdma, int chan_id, int on)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
-	u32		ebci;
+	u32 ebci;
 
 	/* enable interrupts on buffer transfer completion & error */
-	ebci =    AT_DMA_BTC(atchan->chan_common.chan_id)
-		| AT_DMA_ERR(atchan->chan_common.chan_id);
+	ebci =    AT_DMA_BTC(chan_id)
+		| AT_DMA_ERR(chan_id);
 	if (on)
 		dma_writel(atdma, EBCIER, ebci);
 	else
 		dma_writel(atdma, EBCIDR, ebci);
 }
 
-static inline void atc_enable_irq(struct at_dma_chan *atchan)
+static void atc_enable_chan_irq(struct at_dma *atdma, int chan_id)
 {
-	atc_setup_irq(atchan, 1);
+	atc_setup_irq(atdma, chan_id, 1);
 }
 
-static inline void atc_disable_irq(struct at_dma_chan *atchan)
+static void atc_disable_chan_irq(struct at_dma *atdma, int chan_id)
 {
-	atc_setup_irq(atchan, 0);
+	atc_setup_irq(atdma, chan_id, 0);
 }
 
 
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index ee76c8e..7f97c30 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -262,6 +262,7 @@
 static char ohci_driver_name[] = KBUILD_MODNAME;
 
 #define PCI_DEVICE_ID_AGERE_FW643	0x5901
+#define PCI_DEVICE_ID_CREATIVE_SB1394	0x4001
 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW	0x2380
 #define PCI_DEVICE_ID_TI_TSB12LV22	0x8009
 #define PCI_VENDOR_ID_PINNACLE_SYSTEMS	0x11bd
@@ -285,6 +286,9 @@
 	{PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
 		QUIRK_NO_MSI},
 
+	{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID,
+		QUIRK_RESET_PACKET},
+
 	{PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID,
 		QUIRK_NO_MSI},
 
@@ -295,7 +299,7 @@
 		QUIRK_NO_MSI},
 
 	{PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID,
-		QUIRK_CYCLE_TIMER},
+		QUIRK_CYCLE_TIMER | QUIRK_NO_MSI},
 
 	{PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID,
 		QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A},
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index ce33f46..2763643 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -738,6 +738,37 @@
 	ibft_cleanup();
 }
 
+#ifdef CONFIG_ACPI
+static const struct {
+	char *sign;
+} ibft_signs[] = {
+	/*
+	 * One spec says "IBFT", the other says "iBFT". We have to check
+	 * for both.
+	 */
+	{ ACPI_SIG_IBFT },
+	{ "iBFT" },
+};
+
+static void __init acpi_find_ibft_region(void)
+{
+	int i;
+	struct acpi_table_header *table = NULL;
+
+	if (acpi_disabled)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) {
+		acpi_get_table(ibft_signs[i].sign, 0, &table);
+		ibft_addr = (struct acpi_table_ibft *)table;
+	}
+}
+#else
+static void __init acpi_find_ibft_region(void)
+{
+}
+#endif
+
 /*
  * ibft_init() - creates sysfs tree entries for the iBFT data.
  */
@@ -745,9 +776,16 @@
 {
 	int rc = 0;
 
+	/*
+	   As on UEFI systems the setup_arch()/find_ibft_region()
+	   is called before ACPI tables are parsed and it only does
+	   legacy finding.
+	*/
+	if (!ibft_addr)
+		acpi_find_ibft_region();
+
 	if (ibft_addr) {
-		printk(KERN_INFO "iBFT detected at 0x%llx.\n",
-		       (u64)isa_virt_to_bus(ibft_addr));
+		pr_info("iBFT detected.\n");
 
 		rc = ibft_check_device();
 		if (rc)
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index bfe7232..4da4eb9 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -45,13 +45,6 @@
 static const struct {
 	char *sign;
 } ibft_signs[] = {
-#ifdef CONFIG_ACPI
-	/*
-	 * One spec says "IBFT", the other says "iBFT". We have to check
-	 * for both.
-	 */
-	{ ACPI_SIG_IBFT },
-#endif
 	{ "iBFT" },
 	{ "BIFT" },	/* Broadcom iSCSI Offload */
 };
@@ -62,14 +55,6 @@
 #define VGA_MEM 0xA0000 /* VGA buffer */
 #define VGA_SIZE 0x20000 /* 128kB */
 
-#ifdef CONFIG_ACPI
-static int __init acpi_find_ibft(struct acpi_table_header *header)
-{
-	ibft_addr = (struct acpi_table_ibft *)header;
-	return 0;
-}
-#endif /* CONFIG_ACPI */
-
 static int __init find_ibft_in_mem(void)
 {
 	unsigned long pos;
@@ -94,6 +79,7 @@
 				 * the table cannot be valid. */
 				if (pos + len <= (IBFT_END-1)) {
 					ibft_addr = (struct acpi_table_ibft *)virt;
+					pr_info("iBFT found at 0x%lx.\n", pos);
 					goto done;
 				}
 			}
@@ -108,20 +94,12 @@
  */
 unsigned long __init find_ibft_region(unsigned long *sizep)
 {
-#ifdef CONFIG_ACPI
-	int i;
-#endif
 	ibft_addr = NULL;
 
-#ifdef CONFIG_ACPI
-	for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++)
-		acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft);
-#endif /* CONFIG_ACPI */
-
 	/* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
 	 * only use ACPI for this */
 
-	if (!ibft_addr && !efi_enabled)
+	if (!efi_enabled)
 		find_ibft_in_mem();
 
 	if (ibft_addr) {
diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c
index f10fc52..1eedb6f 100644
--- a/drivers/firmware/sigma.c
+++ b/drivers/firmware/sigma.c
@@ -14,13 +14,34 @@
 #include <linux/module.h>
 #include <linux/sigma.h>
 
-/* Return: 0==OK, <0==error, =1 ==no more actions */
-static int
-process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
+static size_t sigma_action_size(struct sigma_action *sa)
 {
-	struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos);
+	size_t payload = 0;
+
+	switch (sa->instr) {
+	case SIGMA_ACTION_WRITEXBYTES:
+	case SIGMA_ACTION_WRITESINGLE:
+	case SIGMA_ACTION_WRITESAFELOAD:
+		payload = sigma_action_len(sa);
+		break;
+	default:
+		break;
+	}
+
+	payload = ALIGN(payload, 2);
+
+	return payload + sizeof(struct sigma_action);
+}
+
+/*
+ * Returns a negative error value in case of an error, 0 if processing of
+ * the firmware should be stopped after this action, 1 otherwise.
+ */
+static int
+process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
+{
 	size_t len = sigma_action_len(sa);
-	int ret = 0;
+	int ret;
 
 	pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
 		sa->instr, sa->addr, len);
@@ -29,44 +50,50 @@
 	case SIGMA_ACTION_WRITEXBYTES:
 	case SIGMA_ACTION_WRITESINGLE:
 	case SIGMA_ACTION_WRITESAFELOAD:
-		if (ssfw->fw->size < ssfw->pos + len)
-			return -EINVAL;
 		ret = i2c_master_send(client, (void *)&sa->addr, len);
 		if (ret < 0)
 			return -EINVAL;
 		break;
-
 	case SIGMA_ACTION_DELAY:
-		ret = 0;
 		udelay(len);
 		len = 0;
 		break;
-
 	case SIGMA_ACTION_END:
-		return 1;
-
+		return 0;
 	default:
 		return -EINVAL;
 	}
 
-	/* when arrive here ret=0 or sent data */
-	ssfw->pos += sigma_action_size(sa, len);
-	return ssfw->pos == ssfw->fw->size;
+	return 1;
 }
 
 static int
 process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
 {
-	pr_debug("%s: processing %p\n", __func__, ssfw);
+	struct sigma_action *sa;
+	size_t size;
+	int ret;
 
-	while (1) {
-		int ret = process_sigma_action(client, ssfw);
+	while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
+		sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
+
+		size = sigma_action_size(sa);
+		ssfw->pos += size;
+		if (ssfw->pos > ssfw->fw->size || size == 0)
+			break;
+
+		ret = process_sigma_action(client, sa);
+
 		pr_debug("%s: action returned %i\n", __func__, ret);
-		if (ret == 1)
-			return 0;
-		else if (ret)
+
+		if (ret <= 0)
 			return ret;
 	}
+
+	if (ssfw->pos != ssfw->fw->size)
+		return -EINVAL;
+
+	return 0;
 }
 
 int process_sigma_firmware(struct i2c_client *client, const char *name)
@@ -89,16 +116,24 @@
 
 	/* then verify the header */
 	ret = -EINVAL;
-	if (fw->size < sizeof(*ssfw_head))
+
+	/*
+	 * Reject too small or unreasonable large files. The upper limit has been
+	 * chosen a bit arbitrarily, but it should be enough for all practical
+	 * purposes and having the limit makes it easier to avoid integer
+	 * overflows later in the loading process.
+	 */
+	if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000)
 		goto done;
 
 	ssfw_head = (void *)fw->data;
 	if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
 		goto done;
 
-	crc = crc32(0, fw->data, fw->size);
+	crc = crc32(0, fw->data + sizeof(*ssfw_head),
+			fw->size - sizeof(*ssfw_head));
 	pr_debug("%s: crc=%x\n", __func__, crc);
-	if (crc != ssfw_head->crc)
+	if (crc != le32_to_cpu(ssfw_head->crc))
 		goto done;
 
 	ssfw.pos = sizeof(*ssfw_head);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8f3263e..8328ee2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -477,4 +477,12 @@
 	  This option enables support for on-chip GPIO found on Qualcomm PM8xxx
 	  PMICs through RPC.
 
+config GPIO_QPNP
+	depends on ARCH_MSMCOPPER
+	depends on OF_SPMI
+	depends on MSM_QPNP_INT
+	tristate "Qualcomm QPNP GPIO support"
+	help
+	  Say 'y' here to include support for the Qualcomm QPNP gpio
+	  support. QPNP is a SPMI based PMIC implementation.
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 83972f1..db19ac8 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -51,3 +51,4 @@
 obj-$(CONFIG_GPIO_PM8XXX)	+= pm8xxx-gpio.o
 obj-$(CONFIG_GPIO_PM8XXX_MPP) 	+= pm8xxx-mpp.o
 obj-$(CONFIG_GPIO_PM8XXX_RPC)	+= gpio-pm8xxx-rpc.o
+obj-$(CONFIG_GPIO_QPNP)		+= qpnp-gpio.o
diff --git a/drivers/gpio/pm8xxx-gpio.c b/drivers/gpio/pm8xxx-gpio.c
index 53305e3..f317c37 100644
--- a/drivers/gpio/pm8xxx-gpio.c
+++ b/drivers/gpio/pm8xxx-gpio.c
@@ -1,7 +1,7 @@
 /*
  * Qualcomm PMIC8XXX GPIO driver
  *
- * 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
@@ -302,7 +302,7 @@
 	pm_gpio_chip->gpio_chip.set = pm_gpio_write;
 	pm_gpio_chip->gpio_chip.dbg_show = pm_gpio_dbg_show;
 	pm_gpio_chip->gpio_chip.ngpio = pdata->gpio_cdata.ngpios;
-	pm_gpio_chip->gpio_chip.can_sleep = 1;
+	pm_gpio_chip->gpio_chip.can_sleep = 0;
 	pm_gpio_chip->gpio_chip.dev = &pdev->dev;
 	pm_gpio_chip->gpio_chip.base = pdata->gpio_base;
 	pm_gpio_chip->irq_base = platform_get_irq(pdev, 0);
diff --git a/drivers/gpio/pm8xxx-mpp.c b/drivers/gpio/pm8xxx-mpp.c
index 82a11a2..9afd5d1 100644
--- a/drivers/gpio/pm8xxx-mpp.c
+++ b/drivers/gpio/pm8xxx-mpp.c
@@ -1,7 +1,7 @@
 /*
  * Qualcomm PM8XXX Multi-Purpose Pin (MPP) driver
  *
- * 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
@@ -250,7 +250,7 @@
 	mpp_chip->gpio_chip.set = pm8xxx_mpp_set;
 	mpp_chip->gpio_chip.dbg_show = pm8xxx_mpp_dbg_show;
 	mpp_chip->gpio_chip.ngpio = pdata->core_data.nmpps;
-	mpp_chip->gpio_chip.can_sleep = 1;
+	mpp_chip->gpio_chip.can_sleep = 0;
 	mpp_chip->gpio_chip.dev = &pdev->dev;
 	mpp_chip->gpio_chip.base = pdata->mpp_base;
 	mpp_chip->irq_base = platform_get_irq(pdev, 0);
diff --git a/drivers/gpio/qpnp-gpio.c b/drivers/gpio/qpnp-gpio.c
new file mode 100644
index 0000000..b09b040
--- /dev/null
+++ b/drivers/gpio/qpnp-gpio.c
@@ -0,0 +1,706 @@
+/* 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/interrupt.h>
+#include <linux/types.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/qpnp/gpio.h>
+
+#include <mach/qpnp.h>
+
+#define Q_REG_ADDR(q_spec, reg_index)	\
+		((q_spec)->offset + reg_index)
+
+#define Q_REG_STATUS1			0x8
+#define Q_NUM_CTL_REGS			5
+
+/* control register base address offsets */
+#define Q_REG_IO_CTL1			0x42
+#define Q_REG_INPUT_CTL1		0x43
+#define Q_REG_OUTPUT_CTL1		0x44
+#define Q_REG_OUTPUT_CTL2		0x45
+#define Q_REG_EN_CTL1			0x46
+
+/* control register regs array indices */
+#define Q_REG_I_IO_CTL1			0
+#define Q_REG_I_INPUT_CTL1		1
+#define Q_REG_I_OUTPUT_CTL1		2
+#define Q_REG_I_OUTPUT_CTL2		3
+#define Q_REG_I_EN_CTL1			4
+
+/* control register configuration */
+#define Q_REG_VIN_SHIFT			0
+#define Q_REG_VIN_MASK			0x7
+#define Q_REG_PULL_SHIFT		4
+#define Q_REG_PULL_MASK			0x70
+#define Q_REG_INPUT_EN_SHIFT		7
+#define Q_REG_INPUT_EN_MASK		0x80
+#define Q_REG_OUT_STRENGTH_SHIFT	0
+#define Q_REG_OUT_STRENGTH_MASK		0x3
+#define Q_REG_OUT_TYPE_SHIFT		6
+#define Q_REG_OUT_TYPE_MASK		0x40
+#define Q_REG_OUT_INVERT_SHIFT		0
+#define Q_REG_OUT_INVERT_MASK		0x1
+#define Q_REG_SRC_SEL_SHIFT		1
+#define Q_REG_SRC_SEL_MASK		0xE
+#define Q_REG_OUTPUT_EN_SHIFT		7
+#define Q_REG_OUTPUT_EN_MASK		0x80
+#define Q_REG_MASTER_EN_SHIFT		7
+#define Q_REG_MASTER_EN_MASK		0x80
+
+
+struct qpnp_gpio_spec {
+	uint8_t slave;			/* 0-15 */
+	uint16_t offset;		/* 0-255 */
+	uint32_t gpio_chip_idx;		/* offset from gpio_chip base */
+	int irq;			/* logical IRQ number */
+	u8 regs[Q_NUM_CTL_REGS];	/* Control regs */
+};
+
+struct qpnp_gpio_chip {
+	struct gpio_chip	gpio_chip;
+	struct spmi_device	*spmi;
+	struct qpnp_gpio_spec	**pmic_gpios;
+	struct qpnp_gpio_spec	**chip_gpios;
+	uint32_t		pmic_gpio_lowest;
+	uint32_t		pmic_gpio_highest;
+	struct device_node	*int_ctrl;
+	struct list_head	chip_list;
+};
+
+static LIST_HEAD(qpnp_gpio_chips);
+static DEFINE_MUTEX(qpnp_gpio_chips_lock);
+
+static inline void qpnp_pmic_gpio_set_spec(struct qpnp_gpio_chip *q_chip,
+					      uint32_t pmic_gpio,
+					      struct qpnp_gpio_spec *spec)
+{
+	q_chip->pmic_gpios[pmic_gpio - q_chip->pmic_gpio_lowest] = spec;
+}
+
+static inline struct qpnp_gpio_spec *qpnp_pmic_gpio_get_spec(
+						struct qpnp_gpio_chip *q_chip,
+						uint32_t pmic_gpio)
+{
+	if (pmic_gpio < q_chip->pmic_gpio_lowest ||
+	    pmic_gpio > q_chip->pmic_gpio_highest)
+		return NULL;
+
+	return q_chip->pmic_gpios[pmic_gpio - q_chip->pmic_gpio_lowest];
+}
+
+static inline struct qpnp_gpio_spec *qpnp_chip_gpio_get_spec(
+						struct qpnp_gpio_chip *q_chip,
+						uint32_t chip_gpio)
+{
+	if (chip_gpio > q_chip->gpio_chip.ngpio)
+		return NULL;
+
+	return q_chip->chip_gpios[chip_gpio];
+}
+
+static inline void qpnp_chip_gpio_set_spec(struct qpnp_gpio_chip *q_chip,
+					      uint32_t chip_gpio,
+					      struct qpnp_gpio_spec *spec)
+{
+	q_chip->chip_gpios[chip_gpio] = spec;
+}
+
+int qpnp_gpio_config(int gpio, struct qpnp_gpio_cfg *param)
+{
+	int rc, chip_offset;
+	struct qpnp_gpio_chip *q_chip;
+	struct qpnp_gpio_spec *q_spec = NULL;
+	struct gpio_chip *gpio_chip;
+
+	if (param == NULL)
+		return -EINVAL;
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_for_each_entry(q_chip, &qpnp_gpio_chips, chip_list) {
+		gpio_chip = &q_chip->gpio_chip;
+		if (gpio >= gpio_chip->base
+				&& gpio < gpio_chip->base + gpio_chip->ngpio) {
+			chip_offset = gpio - gpio_chip->base;
+			q_spec = qpnp_chip_gpio_get_spec(q_chip, chip_offset);
+			if (WARN_ON(!q_spec)) {
+				mutex_unlock(&qpnp_gpio_chips_lock);
+				return -ENODEV;
+			}
+			break;
+		}
+	}
+	mutex_unlock(&qpnp_gpio_chips_lock);
+	if (!q_spec) {
+		pr_err("gpio %d not handled by any pmic\n", gpio);
+		return -EINVAL;
+	}
+
+	q_spec->regs[Q_REG_I_IO_CTL1] = (param->vin_sel <<
+					Q_REG_VIN_SHIFT) & Q_REG_VIN_MASK;
+	q_spec->regs[Q_REG_I_IO_CTL1] |= (param->pull <<
+					Q_REG_PULL_SHIFT) & Q_REG_PULL_MASK;
+	q_spec->regs[Q_REG_I_INPUT_CTL1] = ((param->direction &
+			QPNP_GPIO_DIR_IN) ? ((1 << Q_REG_INPUT_EN_SHIFT)) : 0);
+
+	if (param->direction & QPNP_GPIO_DIR_OUT) {
+		q_spec->regs[Q_REG_I_OUTPUT_CTL1] = (param->out_strength
+			 << Q_REG_OUT_STRENGTH_SHIFT) & Q_REG_OUT_STRENGTH_MASK;
+		q_spec->regs[Q_REG_I_OUTPUT_CTL1] |= (param->output_type
+			 << Q_REG_OUT_TYPE_SHIFT) & Q_REG_OUT_TYPE_MASK;
+	} else {
+		q_spec->regs[Q_REG_I_OUTPUT_CTL1] = 0;
+	}
+
+	if (param->direction & QPNP_GPIO_DIR_OUT) {
+		q_spec->regs[Q_REG_I_OUTPUT_CTL2] = (param->inv_int_pol
+			    << Q_REG_OUT_INVERT_SHIFT) & Q_REG_OUT_INVERT_MASK;
+		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |= (param->src_select
+			    << Q_REG_SRC_SEL_SHIFT) & Q_REG_SRC_SEL_MASK;
+		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |= (1 <<
+			      Q_REG_OUTPUT_EN_SHIFT) & Q_REG_OUTPUT_EN_MASK;
+	} else {
+		q_spec->regs[Q_REG_I_OUTPUT_CTL2] = 0;
+	}
+
+	q_spec->regs[Q_REG_I_EN_CTL1] = (param->master_en <<
+				Q_REG_MASTER_EN_SHIFT) & Q_REG_MASTER_EN_MASK;
+
+	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
+			      Q_REG_ADDR(q_spec, Q_REG_IO_CTL1),
+			      &q_spec->regs[Q_REG_I_IO_CTL1], Q_NUM_CTL_REGS);
+	if (rc)
+		dev_err(&q_chip->spmi->dev, "%s: unable to write master"
+						" enable\n", __func__);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_gpio_config);
+
+int qpnp_gpio_map_gpio(uint16_t slave_id, uint32_t pmic_gpio)
+{
+	struct qpnp_gpio_chip *q_chip;
+	struct qpnp_gpio_spec *q_spec = NULL;
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_for_each_entry(q_chip, &qpnp_gpio_chips, chip_list) {
+		if (q_chip->spmi->sid != slave_id)
+			continue;
+		if (q_chip->pmic_gpio_lowest <= pmic_gpio &&
+		    q_chip->pmic_gpio_highest >= pmic_gpio) {
+			q_spec = qpnp_pmic_gpio_get_spec(q_chip, pmic_gpio);
+			mutex_unlock(&qpnp_gpio_chips_lock);
+			if (WARN_ON(!q_spec))
+				return -ENODEV;
+			return q_chip->gpio_chip.base + q_spec->gpio_chip_idx;
+		}
+	}
+	mutex_unlock(&qpnp_gpio_chips_lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(qpnp_gpio_map_gpio);
+
+static int qpnp_gpio_to_irq(struct gpio_chip *gpio_chip, unsigned offset)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (!q_spec)
+		return -EINVAL;
+
+	return q_spec->irq;
+}
+
+static int qpnp_gpio_get(struct gpio_chip *gpio_chip, unsigned offset)
+{
+	int rc, ret_val;
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec = NULL;
+	u8 buf[1];
+
+	if (WARN_ON(!q_chip))
+		return -ENODEV;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		return -ENODEV;
+
+	/* gpio val is from RT status iff input is enabled */
+	if (q_spec->regs[Q_REG_I_INPUT_CTL1] & Q_REG_INPUT_EN_MASK) {
+		/* INT_RT_STS */
+		rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
+				Q_REG_ADDR(q_spec, Q_REG_STATUS1),
+				&buf[0], 1);
+		return buf[0];
+
+	} else {
+		ret_val = (q_spec->regs[Q_REG_I_OUTPUT_CTL2] &
+			       Q_REG_OUT_INVERT_MASK) >> Q_REG_OUT_INVERT_SHIFT;
+		return ret_val;
+	}
+
+	return 0;
+}
+
+static int __qpnp_gpio_set(struct qpnp_gpio_chip *q_chip,
+			   struct qpnp_gpio_spec *q_spec, int value)
+{
+	int rc;
+
+	if (!q_chip || !q_spec)
+		return -EINVAL;
+
+	q_spec->regs[Q_REG_I_OUTPUT_CTL2] &= ~(1 << Q_REG_OUT_INVERT_SHIFT);
+
+	if (value)
+		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |=
+					    (1 << Q_REG_OUT_INVERT_SHIFT);
+
+	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
+			      Q_REG_ADDR(q_spec, Q_REG_OUTPUT_CTL2),
+			      &q_spec->regs[Q_REG_I_OUTPUT_CTL2], 1);
+	if (rc)
+		dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
+								__func__);
+	return rc;
+}
+
+
+static void qpnp_gpio_set(struct gpio_chip *gpio_chip,
+		unsigned offset, int value)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	if (WARN_ON(!q_chip))
+		return;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		return;
+
+	__qpnp_gpio_set(q_chip, q_spec, value);
+}
+
+static int qpnp_gpio_set_direction(struct qpnp_gpio_chip *q_chip,
+				   struct qpnp_gpio_spec *q_spec, int direction)
+{
+	int rc;
+
+	if (!q_chip || !q_spec)
+		return -EINVAL;
+
+	if (direction & QPNP_GPIO_DIR_IN) {
+		q_spec->regs[Q_REG_I_INPUT_CTL1] |=
+					(1 << Q_REG_INPUT_EN_SHIFT);
+		q_spec->regs[Q_REG_I_OUTPUT_CTL2] &=
+					~(1 << Q_REG_OUTPUT_EN_SHIFT);
+	} else {
+		q_spec->regs[Q_REG_I_INPUT_CTL1] &=
+					~(1 << Q_REG_INPUT_EN_SHIFT);
+		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |=
+					(1 << Q_REG_OUTPUT_EN_SHIFT);
+	}
+
+	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
+			      Q_REG_ADDR(q_spec, Q_REG_INPUT_CTL1),
+			      &q_spec->regs[Q_REG_I_INPUT_CTL1], 3);
+	return rc;
+}
+
+static int qpnp_gpio_direction_input(struct gpio_chip *gpio_chip,
+		unsigned offset)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	if (WARN_ON(!q_chip))
+		return -ENODEV;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		return -ENODEV;
+
+	return qpnp_gpio_set_direction(q_chip, q_spec, QPNP_GPIO_DIR_IN);
+}
+
+static int qpnp_gpio_direction_output(struct gpio_chip *gpio_chip,
+		unsigned offset,
+		int val)
+{
+	int rc;
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	if (WARN_ON(!q_chip))
+		return -ENODEV;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		return -ENODEV;
+
+	rc = __qpnp_gpio_set(q_chip, q_spec, val);
+	if (rc)
+		return rc;
+
+	rc = qpnp_gpio_set_direction(q_chip, q_spec, QPNP_GPIO_DIR_OUT);
+
+	return rc;
+}
+
+static int qpnp_gpio_of_gpio_xlate(struct gpio_chip *gpio_chip,
+				   struct device_node *np,
+				   const void *gpio_spec, u32 *flags)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+	const __be32 *gpio = gpio_spec;
+	u32 n = be32_to_cpup(gpio);
+
+	if (WARN_ON(gpio_chip->of_gpio_n_cells < 2)) {
+		pr_err("%s: of_gpio_n_cells < 2\n", __func__);
+		return -EINVAL;
+	}
+
+	q_spec = qpnp_pmic_gpio_get_spec(q_chip, n);
+	if (!q_spec) {
+		pr_err("%s: no such PMIC gpio %u in device topology\n",
+							__func__, n);
+		return -EINVAL;
+	}
+
+	if (flags)
+		*flags = be32_to_cpu(gpio[1]);
+
+	return q_spec->gpio_chip_idx;
+}
+
+static int qpnp_gpio_config_default(struct spmi_device *spmi,
+					const __be32 *prop, int gpio)
+{
+	struct qpnp_gpio_cfg param;
+	int rc;
+
+	dev_dbg(&spmi->dev, "%s: p[0]: 0x%x p[1]: 0x%x p[2]: 0x%x p[3]:"
+		" 0x%x p[4]: 0x%x p[5]: 0x%x p[6]: 0x%x p[7]: 0x%x"
+		" p[8]: 0x%x\n", __func__,
+		be32_to_cpup(&prop[0]), be32_to_cpup(&prop[1]),
+		be32_to_cpup(&prop[2]), be32_to_cpup(&prop[3]),
+		be32_to_cpup(&prop[4]), be32_to_cpup(&prop[5]),
+		be32_to_cpup(&prop[6]), be32_to_cpup(&prop[7]),
+		be32_to_cpup(&prop[8]));
+
+	param.direction    =	be32_to_cpup(&prop[0]);
+	param.output_type  =	be32_to_cpup(&prop[1]);
+	param.output_value =	be32_to_cpup(&prop[2]);
+	param.pull	   =	be32_to_cpup(&prop[3]);
+	param.vin_sel	   =	be32_to_cpup(&prop[4]);
+	param.out_strength =	be32_to_cpup(&prop[5]);
+	param.src_select   =	be32_to_cpup(&prop[6]);
+	param.inv_int_pol  =	be32_to_cpup(&prop[7]);
+	param.master_en    =	be32_to_cpup(&prop[8]);
+
+	rc = qpnp_gpio_config(gpio, &param);
+	if (rc)
+		dev_err(&spmi->dev, "%s: unable to set default config for"
+				" gpio %d\n", __func__, gpio);
+	return rc;
+}
+
+static int qpnp_gpio_free_chip(struct qpnp_gpio_chip *q_chip)
+{
+	struct spmi_device *spmi = q_chip->spmi;
+	int rc, i;
+
+	if (q_chip->chip_gpios)
+		for (i = 0; i < spmi->num_dev_node; i++)
+			kfree(q_chip->chip_gpios[i]);
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_del(&q_chip->chip_list);
+	mutex_unlock(&qpnp_gpio_chips_lock);
+	rc = gpiochip_remove(&q_chip->gpio_chip);
+	if (rc)
+		dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
+				__func__);
+	kfree(q_chip->chip_gpios);
+	kfree(q_chip->pmic_gpios);
+	kfree(q_chip);
+	return rc;
+}
+
+static int qpnp_gpio_probe(struct spmi_device *spmi)
+{
+	struct qpnp_gpio_chip *q_chip;
+	struct resource *res;
+	struct qpnp_gpio_spec *q_spec;
+	const __be32 *prop;
+	int i, rc, ret, gpio, len;
+	int lowest_gpio = INT_MAX, highest_gpio = INT_MIN;
+	u32 intspec[3];
+
+	q_chip = kzalloc(sizeof(*q_chip), GFP_KERNEL);
+	if (!q_chip) {
+		dev_err(&spmi->dev, "%s: Can't allocate gpio_chip\n",
+								__func__);
+		return -ENOMEM;
+	}
+	q_chip->spmi = spmi;
+	dev_set_drvdata(&spmi->dev, q_chip);
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_add(&q_chip->chip_list, &qpnp_gpio_chips);
+	mutex_unlock(&qpnp_gpio_chips_lock);
+
+	/* first scan through nodes to find the range required for allocation */
+	for (i = 0; i < spmi->num_dev_node; i++) {
+		prop = of_get_property(spmi->dev_node[i].of_node,
+						"qcom,qpnp-gpio-num", &len);
+		if (!prop) {
+			dev_err(&spmi->dev, "%s: unable to get"
+				" qcom,qpnp-gpio-num property\n", __func__);
+			ret = -EINVAL;
+			goto err_probe;
+		} else if (len != sizeof(__be32)) {
+			dev_err(&spmi->dev, "%s: Invalid qcom,qpnp-gpio-num"
+				" property\n", __func__);
+			ret = -EINVAL;
+			goto err_probe;
+		}
+
+		gpio = be32_to_cpup(prop);
+		if (gpio < lowest_gpio)
+			lowest_gpio = gpio;
+		if (gpio > highest_gpio)
+			highest_gpio = gpio;
+	}
+
+	if (highest_gpio < lowest_gpio) {
+		dev_err(&spmi->dev, "%s: no device nodes specified in"
+					" topology\n", __func__);
+		ret = -EINVAL;
+		goto err_probe;
+	} else if (lowest_gpio == 0) {
+		dev_err(&spmi->dev, "%s: 0 is not a valid PMIC GPIO\n",
+								__func__);
+		ret = -EINVAL;
+		goto err_probe;
+	}
+
+	q_chip->pmic_gpio_lowest = lowest_gpio;
+	q_chip->pmic_gpio_highest = highest_gpio;
+
+	/* allocate gpio lookup tables */
+	q_chip->pmic_gpios = kzalloc(sizeof(struct qpnp_gpio_spec *) *
+						highest_gpio - lowest_gpio + 1,
+						GFP_KERNEL);
+	q_chip->chip_gpios = kzalloc(sizeof(struct qpnp_gpio_spec *) *
+						spmi->num_dev_node, GFP_KERNEL);
+	if (!q_chip->pmic_gpios || !q_chip->chip_gpios) {
+		dev_err(&spmi->dev, "%s: unable to allocate memory\n",
+								__func__);
+		ret = -ENOMEM;
+		goto err_probe;
+	}
+
+	/* get interrupt controller device_node */
+	q_chip->int_ctrl = of_irq_find_parent(spmi->dev.of_node);
+	if (!q_chip->int_ctrl) {
+		dev_err(&spmi->dev, "%s: Can't find interrupt parent\n",
+								__func__);
+		ret = -EINVAL;
+		goto err_probe;
+	}
+
+	/* now scan through again and populate the lookup table */
+	for (i = 0; i < spmi->num_dev_node; i++) {
+		res = qpnp_get_resource(spmi, i, IORESOURCE_MEM, 0);
+		if (!res) {
+			dev_err(&spmi->dev, "%s: node %s is missing has no"
+				" base address definition\n",
+				__func__, spmi->dev_node[i].of_node->full_name);
+		}
+
+		prop = of_get_property(spmi->dev_node[i].of_node,
+				"qcom,qpnp-gpio-num", &len);
+		if (!prop) {
+			dev_err(&spmi->dev, "%s: unable to get"
+				" qcom,qpnp-gpio-num property\n", __func__);
+			ret = -EINVAL;
+			goto err_probe;
+		} else if (len != sizeof(__be32)) {
+			dev_err(&spmi->dev, "%s: Invalid qcom,qpnp-gpio-num"
+				" property\n", __func__);
+			ret = -EINVAL;
+			goto err_probe;
+		}
+		gpio = be32_to_cpup(prop);
+
+		q_spec = kzalloc(sizeof(struct qpnp_gpio_spec),
+							GFP_KERNEL);
+		if (!q_spec) {
+			dev_err(&spmi->dev, "%s: unable to allocate"
+						" memory\n",
+					__func__);
+			ret = -ENOMEM;
+			goto err_probe;
+		}
+
+		q_spec->slave = spmi->sid;
+		q_spec->offset = res->start;
+		q_spec->gpio_chip_idx = i;
+
+		/* call into irq_domain to get irq mapping */
+		intspec[0] = q_chip->spmi->sid;
+		intspec[1] = (q_spec->offset >> 8) & 0xFF;
+		intspec[2] = 0;
+		q_spec->irq = irq_create_of_mapping(q_chip->int_ctrl,
+							intspec, 3);
+		if (!q_spec->irq) {
+			dev_err(&spmi->dev, "%s: invalid irq for gpio"
+					" %u\n", __func__, gpio);
+			ret = -EINVAL;
+			goto err_probe;
+		}
+		/* initialize lookup table entries */
+		qpnp_pmic_gpio_set_spec(q_chip, gpio, q_spec);
+		qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
+	}
+
+	q_chip->gpio_chip.base = -1;
+	q_chip->gpio_chip.ngpio = spmi->num_dev_node;
+	q_chip->gpio_chip.label = "qpnp-gpio";
+	q_chip->gpio_chip.direction_input = qpnp_gpio_direction_input;
+	q_chip->gpio_chip.direction_output = qpnp_gpio_direction_output;
+	q_chip->gpio_chip.to_irq = qpnp_gpio_to_irq;
+	q_chip->gpio_chip.get = qpnp_gpio_get;
+	q_chip->gpio_chip.set = qpnp_gpio_set;
+	q_chip->gpio_chip.dev = &spmi->dev;
+	q_chip->gpio_chip.of_xlate = qpnp_gpio_of_gpio_xlate;
+	q_chip->gpio_chip.of_gpio_n_cells = 2;
+	q_chip->gpio_chip.can_sleep = 0;
+
+	rc = gpiochip_add(&q_chip->gpio_chip);
+	if (rc) {
+		dev_err(&spmi->dev, "%s: Can't add gpio chip, rc = %d\n",
+								__func__, rc);
+		ret = rc;
+		goto err_probe;
+	}
+
+	/* now configure gpio defaults if they exist */
+	for (i = 0; i < spmi->num_dev_node; i++) {
+		q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
+		if (WARN_ON(!q_spec))
+			return -ENODEV;
+
+		/* It's not an error to not config a default */
+		prop = of_get_property(spmi->dev_node[i].of_node,
+				"qcom,qpnp-gpio-cfg", &len);
+		/* 9 data values constitute one tuple */
+		if (prop && (len != (9 * sizeof(__be32)))) {
+			dev_err(&spmi->dev, "%s: invalid format for"
+				" qcom,qpnp-gpio-cfg property\n",
+							__func__);
+			ret = -EINVAL;
+			goto err_probe;
+		} else if (prop) {
+			rc = qpnp_gpio_config_default(spmi, prop,
+				     q_chip->gpio_chip.base + i);
+			if (rc) {
+				ret = rc;
+				goto err_probe;
+			}
+		} else {
+			/* initialize with hardware defaults */
+			rc = spmi_ext_register_readl(
+				q_chip->spmi->ctrl, q_spec->slave,
+				Q_REG_ADDR(q_spec, Q_REG_IO_CTL1),
+				&q_spec->regs[Q_REG_I_IO_CTL1],
+				Q_NUM_CTL_REGS);
+			q_spec->regs[Q_REG_I_EN_CTL1] |=
+				(1 << Q_REG_MASTER_EN_SHIFT);
+			rc = spmi_ext_register_writel(
+				q_chip->spmi->ctrl, q_spec->slave,
+				Q_REG_ADDR(q_spec, Q_REG_EN_CTL1),
+				&q_spec->regs[Q_REG_EN_CTL1], 1);
+			if (rc) {
+				dev_err(&spmi->dev, "%s: spmi write"
+						" failed\n", __func__);
+				ret = rc;
+				goto err_probe;
+			}
+		}
+	}
+
+	dev_dbg(&spmi->dev, "%s: gpio_chip registered between %d-%u\n",
+			__func__, q_chip->gpio_chip.base,
+			(q_chip->gpio_chip.base + q_chip->gpio_chip.ngpio) - 1);
+	return 0;
+
+err_probe:
+	qpnp_gpio_free_chip(q_chip);
+	return ret;
+}
+
+static int qpnp_gpio_remove(struct spmi_device *spmi)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(&spmi->dev);
+
+	return qpnp_gpio_free_chip(q_chip);
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{	.compatible = "qcom,qpnp-gpio",
+	},
+	{}
+};
+
+static const struct spmi_device_id qpnp_gpio_id[] = {
+	{ "qcom,qpnp-gpio", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_gpio_id);
+
+static struct spmi_driver qpnp_gpio_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-gpio",
+		.of_match_table = spmi_match_table,
+	},
+	.probe		= qpnp_gpio_probe,
+	.remove		= qpnp_gpio_remove,
+	.id_table	= qpnp_gpio_id,
+};
+
+static int __init qpnp_gpio_init(void)
+{
+	return spmi_driver_register(&qpnp_gpio_driver);
+}
+
+static void __exit qpnp_gpio_exit(void)
+{
+}
+
+MODULE_AUTHOR(
+	"Michael Bohan <mbohan@codeaurora.org>");
+MODULE_DESCRIPTION("QPNP PMIC gpio driver");
+MODULE_LICENSE("GPLv2");
+
+module_init(qpnp_gpio_init);
+module_exit(qpnp_gpio_exit);
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 3f46772..ba23790 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -101,7 +101,7 @@
  * Searches and unlinks the entry in drm_device::magiclist with the magic
  * number hash key, while holding the drm_device::struct_mutex lock.
  */
-static int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
+int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
 {
 	struct drm_magic_entry *pt;
 	struct drm_hash_item *hash;
@@ -136,6 +136,8 @@
  * If there is a magic number in drm_file::magic then use it, otherwise
  * searches an unique non-zero magic number and add it associating it with \p
  * file_priv.
+ * This ioctl needs protection by the drm_global_mutex, which protects
+ * struct drm_file::magic and struct drm_magic_entry::priv.
  */
 int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
@@ -173,6 +175,8 @@
  * \return zero if authentication successed, or a negative number otherwise.
  *
  * Checks if \p file_priv is associated with the magic number passed in \arg.
+ * This ioctl needs protection by the drm_global_mutex, which protects
+ * struct drm_file::magic and struct drm_magic_entry::priv.
  */
 int drm_authmagic(struct drm_device *dev, void *data,
 		  struct drm_file *file_priv)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 82db185..1367ced 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1866,6 +1866,10 @@
 	}
 
 	if (num_clips && clips_ptr) {
+		if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
+			ret = -EINVAL;
+			goto out_err1;
+		}
 		clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
 		if (!clips) {
 			ret = -ENOMEM;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 2ec7d48..c42e12c 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -486,6 +486,11 @@
 		  (long)old_encode_dev(file_priv->minor->device),
 		  dev->open_count);
 
+	/* Release any auth tokens that might point to this file_priv,
+	   (do that under the drm_global_mutex) */
+	if (file_priv->magic)
+		(void) drm_remove_magic(file_priv->master, file_priv->magic);
+
 	/* if the master has gone away we can't do anything with the lock */
 	if (file_priv->minor->master)
 		drm_master_release(dev, filp);
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 0a893f7..e36efdc 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -865,7 +865,7 @@
 			   MEMSTAT_VID_SHIFT);
 		seq_printf(m, "Current P-state: %d\n",
 			   (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
-	} else if (IS_GEN6(dev)) {
+	} else if (IS_GEN6(dev) || IS_GEN7(dev)) {
 		u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
 		u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
 		u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 7eef6e1..ef16443 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1451,6 +1451,14 @@
 
 	diff1 = now - dev_priv->last_time1;
 
+	/* Prevent division-by-zero if we are asking too fast.
+	 * Also, we don't get interesting results if we are polling
+	 * faster than once in 10ms, so just return the saved value
+	 * in such cases.
+	 */
+	if (diff1 <= 10)
+		return dev_priv->chipset_power;
+
 	count1 = I915_READ(DMIEC);
 	count2 = I915_READ(DDREC);
 	count3 = I915_READ(CSIEC);
@@ -1481,6 +1489,8 @@
 	dev_priv->last_count1 = total_count;
 	dev_priv->last_time1 = now;
 
+	dev_priv->chipset_power = ret;
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index ce7914c..b570415 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -325,6 +325,8 @@
 	struct timer_list hangcheck_timer;
 	int hangcheck_count;
 	uint32_t last_acthd;
+	uint32_t last_acthd_bsd;
+	uint32_t last_acthd_blt;
 	uint32_t last_instdone;
 	uint32_t last_instdone1;
 
@@ -541,6 +543,7 @@
 	u32 savePIPEB_LINK_M1;
 	u32 savePIPEB_LINK_N1;
 	u32 saveMCHBAR_RENDER_STANDBY;
+	u32 savePCH_PORT_HOTPLUG;
 
 	struct {
 		/** Bridge to intel-gtt-ko */
@@ -701,6 +704,7 @@
 
 	u64 last_count1;
 	unsigned long last_time1;
+	unsigned long chipset_power;
 	u64 last_count2;
 	struct timespec last_time2;
 	unsigned long gfx_power;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index a087e1b..5548593 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1475,7 +1475,7 @@
 
 	if (obj->base.size > dev_priv->mm.gtt_mappable_end) {
 		ret = -E2BIG;
-		goto unlock;
+		goto out;
 	}
 
 	if (obj->madv != I915_MADV_WILLNEED) {
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 9b1d669..997db7f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -820,6 +820,7 @@
 
 	/* Fences */
 	switch (INTEL_INFO(dev)->gen) {
+	case 7:
 	case 6:
 		for (i = 0; i < 16; i++)
 			error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
@@ -1664,7 +1665,7 @@
 {
 	struct drm_device *dev = (struct drm_device *)data;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	uint32_t acthd, instdone, instdone1;
+	uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt;
 	bool err = false;
 
 	/* If all work is done then ACTHD clearly hasn't advanced. */
@@ -1678,16 +1679,21 @@
 	}
 
 	if (INTEL_INFO(dev)->gen < 4) {
-		acthd = I915_READ(ACTHD);
 		instdone = I915_READ(INSTDONE);
 		instdone1 = 0;
 	} else {
-		acthd = I915_READ(ACTHD_I965);
 		instdone = I915_READ(INSTDONE_I965);
 		instdone1 = I915_READ(INSTDONE1);
 	}
+	acthd = intel_ring_get_active_head(&dev_priv->ring[RCS]);
+	acthd_bsd = HAS_BSD(dev) ?
+		intel_ring_get_active_head(&dev_priv->ring[VCS]) : 0;
+	acthd_blt = HAS_BLT(dev) ?
+		intel_ring_get_active_head(&dev_priv->ring[BCS]) : 0;
 
 	if (dev_priv->last_acthd == acthd &&
+	    dev_priv->last_acthd_bsd == acthd_bsd &&
+	    dev_priv->last_acthd_blt == acthd_blt &&
 	    dev_priv->last_instdone == instdone &&
 	    dev_priv->last_instdone1 == instdone1) {
 		if (dev_priv->hangcheck_count++ > 1) {
@@ -1719,6 +1725,8 @@
 		dev_priv->hangcheck_count = 0;
 
 		dev_priv->last_acthd = acthd;
+		dev_priv->last_acthd_bsd = acthd_bsd;
+		dev_priv->last_acthd_blt = acthd_blt;
 		dev_priv->last_instdone = instdone;
 		dev_priv->last_instdone1 = instdone1;
 	}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 5d5def7..673f0d2 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2544,10 +2544,18 @@
 #define _CURBBASE		0x700c4
 #define _CURBPOS			0x700c8
 
+#define _CURBCNTR_IVB		0x71080
+#define _CURBBASE_IVB		0x71084
+#define _CURBPOS_IVB		0x71088
+
 #define CURCNTR(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR)
 #define CURBASE(pipe) _PIPE(pipe, _CURABASE, _CURBBASE)
 #define CURPOS(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS)
 
+#define CURCNTR_IVB(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR_IVB)
+#define CURBASE_IVB(pipe) _PIPE(pipe, _CURABASE, _CURBBASE_IVB)
+#define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB)
+
 /* Display A control */
 #define _DSPACNTR                0x70180
 #define   DISPLAY_PLANE_ENABLE			(1<<31)
@@ -3133,6 +3141,7 @@
 #define  FDI_LINK_TRAIN_NONE_IVB            (3<<8)
 
 /* both Tx and Rx */
+#define  FDI_COMPOSITE_SYNC		(1<<11)
 #define  FDI_LINK_TRAIN_AUTO		(1<<10)
 #define  FDI_SCRAMBLING_ENABLE          (0<<7)
 #define  FDI_SCRAMBLING_DISABLE         (1<<7)
@@ -3361,6 +3370,10 @@
 
 #define  GT_FIFO_FREE_ENTRIES			0x120008
 
+#define GEN6_UCGCTL2				0x9404
+# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE		(1 << 12)
+# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE		(1 << 11)
+
 #define GEN6_RPNSWREQ				0xA008
 #define   GEN6_TURBO_DISABLE			(1<<31)
 #define   GEN6_FREQUENCY(x)			((x)<<25)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 5257cfc..bc7dcaa 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -34,6 +34,10 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32	dpll_reg;
 
+	/* On IVB, 3rd pipe shares PLL with another one */
+	if (pipe > 1)
+		return false;
+
 	if (HAS_PCH_SPLIT(dev))
 		dpll_reg = (pipe == PIPE_A) ? _PCH_DPLL_A : _PCH_DPLL_B;
 	else
@@ -370,6 +374,7 @@
 
 	/* Fences */
 	switch (INTEL_INFO(dev)->gen) {
+	case 7:
 	case 6:
 		for (i = 0; i < 16; i++)
 			dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
@@ -404,6 +409,7 @@
 
 	/* Fences */
 	switch (INTEL_INFO(dev)->gen) {
+	case 7:
 	case 6:
 		for (i = 0; i < 16; i++)
 			I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]);
@@ -814,6 +820,7 @@
 		dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR);
 		dev_priv->saveMCHBAR_RENDER_STANDBY =
 			I915_READ(RSTDBYCTL);
+		dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG);
 	} else {
 		dev_priv->saveIER = I915_READ(IER);
 		dev_priv->saveIMR = I915_READ(IMR);
@@ -865,6 +872,7 @@
 		I915_WRITE(GTIMR, dev_priv->saveGTIMR);
 		I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR);
 		I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR);
+		I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG);
 	} else {
 		I915_WRITE(IER, dev_priv->saveIER);
 		I915_WRITE(IMR, dev_priv->saveIMR);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5609c06..fed87d6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2340,6 +2340,7 @@
 	temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
 	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 	temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+	temp |= FDI_COMPOSITE_SYNC;
 	I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
 	reg = FDI_RX_CTL(pipe);
@@ -2347,6 +2348,7 @@
 	temp &= ~FDI_LINK_TRAIN_AUTO;
 	temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
 	temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+	temp |= FDI_COMPOSITE_SYNC;
 	I915_WRITE(reg, temp | FDI_RX_ENABLE);
 
 	POSTING_READ(reg);
@@ -4970,7 +4972,7 @@
 	} else if (is_sdvo && is_tv)
 		factor = 20;
 
-	if (clock.m1 < factor * clock.n)
+	if (clock.m < factor * clock.n)
 		fp |= FP_CB_TUNE;
 
 	dpll = 0;
@@ -5334,6 +5336,31 @@
 	I915_WRITE(CURBASE(pipe), base);
 }
 
+static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	bool visible = base != 0;
+
+	if (intel_crtc->cursor_visible != visible) {
+		uint32_t cntl = I915_READ(CURCNTR_IVB(pipe));
+		if (base) {
+			cntl &= ~CURSOR_MODE;
+			cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+		} else {
+			cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
+			cntl |= CURSOR_MODE_DISABLE;
+		}
+		I915_WRITE(CURCNTR_IVB(pipe), cntl);
+
+		intel_crtc->cursor_visible = visible;
+	}
+	/* and commit changes on next vblank */
+	I915_WRITE(CURBASE_IVB(pipe), base);
+}
+
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
 static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 				     bool on)
@@ -5381,11 +5408,16 @@
 	if (!visible && !intel_crtc->cursor_visible)
 		return;
 
-	I915_WRITE(CURPOS(pipe), pos);
-	if (IS_845G(dev) || IS_I865G(dev))
-		i845_update_cursor(crtc, base);
-	else
-		i9xx_update_cursor(crtc, base);
+	if (IS_IVYBRIDGE(dev)) {
+		I915_WRITE(CURPOS_IVB(pipe), pos);
+		ivb_update_cursor(crtc, base);
+	} else {
+		I915_WRITE(CURPOS(pipe), pos);
+		if (IS_845G(dev) || IS_I865G(dev))
+			i845_update_cursor(crtc, base);
+		else
+			i9xx_update_cursor(crtc, base);
+	}
 
 	if (visible)
 		intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
@@ -7373,6 +7405,20 @@
 	I915_WRITE(WM2_LP_ILK, 0);
 	I915_WRITE(WM1_LP_ILK, 0);
 
+	/* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
+	 * gating disable must be set.  Failure to set it results in
+	 * flickering pixels due to Z write ordering failures after
+	 * some amount of runtime in the Mesa "fire" demo, and Unigine
+	 * Sanctuary and Tropics, and apparently anything else with
+	 * alpha test or pixel discard.
+	 *
+	 * According to the spec, bit 11 (RCCUNIT) must also be set,
+	 * but we didn't debug actual testcases to find it out.
+	 */
+	I915_WRITE(GEN6_UCGCTL2,
+		   GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
+		   GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
+
 	/*
 	 * According to the spec the following bits should be
 	 * set in order to enable memory self-refresh and fbc:
@@ -7943,7 +7989,7 @@
 		intel_init_emon(dev);
 	}
 
-	if (IS_GEN6(dev))
+	if (IS_GEN6(dev) || IS_GEN7(dev))
 		gen6_enable_rps(dev_priv);
 
 	INIT_WORK(&dev_priv->idle_work, intel_idle_update);
@@ -7985,7 +8031,7 @@
 
 	if (IS_IRONLAKE_M(dev))
 		ironlake_disable_drps(dev);
-	if (IS_GEN6(dev))
+	if (IS_GEN6(dev) || IS_GEN7(dev))
 		gen6_disable_rps(dev);
 
 	if (IS_IRONLAKE_M(dev))
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e2aced6..bf9fea9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1554,6 +1554,7 @@
 			intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
 	}
 
+	DP &= ~DP_AUDIO_OUTPUT_ENABLE;
 	I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
 	POSTING_READ(intel_dp->output_reg);
 }
@@ -1658,6 +1659,31 @@
 	return status;
 }
 
+static struct edid *
+intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
+{
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct edid	*edid;
+
+	ironlake_edp_panel_vdd_on(intel_dp);
+	edid = drm_get_edid(connector, adapter);
+	ironlake_edp_panel_vdd_off(intel_dp);
+	return edid;
+}
+
+static int
+intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter)
+{
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int	ret;
+
+	ironlake_edp_panel_vdd_on(intel_dp);
+	ret = intel_ddc_get_modes(connector, adapter);
+	ironlake_edp_panel_vdd_off(intel_dp);
+	return ret;
+}
+
+
 /**
  * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
  *
@@ -1684,7 +1710,7 @@
 	if (intel_dp->force_audio) {
 		intel_dp->has_audio = intel_dp->force_audio > 0;
 	} else {
-		edid = drm_get_edid(connector, &intel_dp->adapter);
+		edid = intel_dp_get_edid(connector, &intel_dp->adapter);
 		if (edid) {
 			intel_dp->has_audio = drm_detect_monitor_audio(edid);
 			connector->display_info.raw_edid = NULL;
@@ -1705,7 +1731,7 @@
 	/* We should parse the EDID data and find out if it has an audio sink
 	 */
 
-	ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
+	ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter);
 	if (ret) {
 		if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
 			struct drm_display_mode *newmode;
@@ -1741,7 +1767,7 @@
 	struct edid *edid;
 	bool has_audio = false;
 
-	edid = drm_get_edid(connector, &intel_dp->adapter);
+	edid = intel_dp_get_edid(connector, &intel_dp->adapter);
 	if (edid) {
 		has_audio = drm_detect_monitor_audio(edid);
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index aa0a8e8..236bbe0 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -158,6 +158,10 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 	u32 temp;
+	u32 enable_bits = SDVO_ENABLE;
+
+	if (intel_hdmi->has_audio)
+		enable_bits |= SDVO_AUDIO_ENABLE;
 
 	temp = I915_READ(intel_hdmi->sdvox_reg);
 
@@ -170,9 +174,9 @@
 	}
 
 	if (mode != DRM_MODE_DPMS_ON) {
-		temp &= ~SDVO_ENABLE;
+		temp &= ~enable_bits;
 	} else {
-		temp |= SDVO_ENABLE;
+		temp |= enable_bits;
 	}
 
 	I915_WRITE(intel_hdmi->sdvox_reg, temp);
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 05f500c..f8aa821 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -226,7 +226,7 @@
 	I915_WRITE(BLC_PWM_CPU_CTL, val | level);
 }
 
-void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 tmp;
@@ -254,16 +254,21 @@
 	I915_WRITE(BLC_PWM_CTL, tmp | level);
 }
 
+void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	dev_priv->backlight_level = level;
+	if (dev_priv->backlight_enabled)
+		intel_panel_actually_set_backlight(dev, level);
+}
+
 void intel_panel_disable_backlight(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (dev_priv->backlight_enabled) {
-		dev_priv->backlight_level = intel_panel_get_backlight(dev);
-		dev_priv->backlight_enabled = false;
-	}
-
-	intel_panel_set_backlight(dev, 0);
+	dev_priv->backlight_enabled = false;
+	intel_panel_actually_set_backlight(dev, 0);
 }
 
 void intel_panel_enable_backlight(struct drm_device *dev)
@@ -273,8 +278,8 @@
 	if (dev_priv->backlight_level == 0)
 		dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
 
-	intel_panel_set_backlight(dev, dev_priv->backlight_level);
 	dev_priv->backlight_enabled = true;
+	intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
 }
 
 void intel_panel_setup_backlight(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 30fe554..bdda08e 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1059,15 +1059,13 @@
 
 	/* Set the SDVO control regs. */
 	if (INTEL_INFO(dev)->gen >= 4) {
-		sdvox = 0;
+		/* The real mode polarity is set by the SDVO commands, using
+		 * struct intel_sdvo_dtd. */
+		sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
 		if (intel_sdvo->is_hdmi)
 			sdvox |= intel_sdvo->color_range;
 		if (INTEL_INFO(dev)->gen < 5)
 			sdvox |= SDVO_BORDER_ENABLE;
-		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-			sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
-		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-			sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
 	} else {
 		sdvox = I915_READ(intel_sdvo->sdvo_reg);
 		switch (intel_sdvo->sdvo_reg) {
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 113e4e7..f57b08b 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -417,7 +417,7 @@
 	{
 		.name		= "NTSC-M",
 		.clock		= 108000,
-		.refresh	= 29970,
+		.refresh	= 59940,
 		.oversample	= TV_OVERSAMPLE_8X,
 		.component_only = 0,
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
@@ -460,7 +460,7 @@
 	{
 		.name		= "NTSC-443",
 		.clock		= 108000,
-		.refresh	= 29970,
+		.refresh	= 59940,
 		.oversample	= TV_OVERSAMPLE_8X,
 		.component_only = 0,
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
@@ -502,7 +502,7 @@
 	{
 		.name		= "NTSC-J",
 		.clock		= 108000,
-		.refresh	= 29970,
+		.refresh	= 59940,
 		.oversample	= TV_OVERSAMPLE_8X,
 		.component_only = 0,
 
@@ -545,7 +545,7 @@
 	{
 		.name		= "PAL-M",
 		.clock		= 108000,
-		.refresh	= 29970,
+		.refresh	= 59940,
 		.oversample	= TV_OVERSAMPLE_8X,
 		.component_only = 0,
 
@@ -589,7 +589,7 @@
 		/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
 		.name	    = "PAL-N",
 		.clock		= 108000,
-		.refresh	= 25000,
+		.refresh	= 50000,
 		.oversample	= TV_OVERSAMPLE_8X,
 		.component_only = 0,
 
@@ -634,7 +634,7 @@
 		/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
 		.name	    = "PAL",
 		.clock		= 108000,
-		.refresh	= 25000,
+		.refresh	= 50000,
 		.oversample	= TV_OVERSAMPLE_8X,
 		.component_only = 0,
 
@@ -821,7 +821,7 @@
 	{
 		.name       = "1080i@50Hz",
 		.clock		= 148800,
-		.refresh	= 25000,
+		.refresh	= 50000,
 		.oversample     = TV_OVERSAMPLE_2X,
 		.component_only = 1,
 
@@ -847,7 +847,7 @@
 	{
 		.name       = "1080i@60Hz",
 		.clock		= 148800,
-		.refresh	= 30000,
+		.refresh	= 60000,
 		.oversample     = TV_OVERSAMPLE_2X,
 		.component_only = 1,
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index a7583a8..d31d355 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -159,6 +159,7 @@
 	INIT_LIST_HEAD(&chan->nvsw.vbl_wait);
 	INIT_LIST_HEAD(&chan->nvsw.flip);
 	INIT_LIST_HEAD(&chan->fence.pending);
+	spin_lock_init(&chan->fence.lock);
 
 	/* Allocate DMA push buffer */
 	chan->pushbuf_bo = nouveau_channel_user_pushbuf_alloc(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 7347075..56f06b0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -542,8 +542,6 @@
 			return ret;
 	}
 
-	INIT_LIST_HEAD(&chan->fence.pending);
-	spin_lock_init(&chan->fence.lock);
 	atomic_set(&chan->fence.last_sequence_irq, 0);
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index b52e460..cee78b2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -315,6 +315,25 @@
 }
 
 static int
+validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo)
+{
+	struct nouveau_fence *fence = NULL;
+	int ret = 0;
+
+	spin_lock(&nvbo->bo.bdev->fence_lock);
+	if (nvbo->bo.sync_obj)
+		fence = nouveau_fence_ref(nvbo->bo.sync_obj);
+	spin_unlock(&nvbo->bo.bdev->fence_lock);
+
+	if (fence) {
+		ret = nouveau_fence_sync(fence, chan);
+		nouveau_fence_unref(&fence);
+	}
+
+	return ret;
+}
+
+static int
 validate_list(struct nouveau_channel *chan, struct list_head *list,
 	      struct drm_nouveau_gem_pushbuf_bo *pbbo, uint64_t user_pbbo_ptr)
 {
@@ -327,7 +346,7 @@
 	list_for_each_entry(nvbo, list, entry) {
 		struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
 
-		ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
+		ret = validate_sync(chan, nvbo);
 		if (unlikely(ret)) {
 			NV_ERROR(dev, "fail pre-validate sync\n");
 			return ret;
@@ -350,7 +369,7 @@
 			return ret;
 		}
 
-		ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
+		ret = validate_sync(chan, nvbo);
 		if (unlikely(ret)) {
 			NV_ERROR(dev, "fail post-validate sync\n");
 			return ret;
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 9541995..071ded1 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1173,7 +1173,7 @@
 	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
 	WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
-	       crtc->mode.vdisplay);
+	       target_fb->height);
 	x &= ~3;
 	y &= ~1;
 	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
@@ -1342,7 +1342,7 @@
 	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
 	WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
-	       crtc->mode.vdisplay);
+	       target_fb->height);
 	x &= ~3;
 	y &= ~1;
 	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 79e8ebc..3b77ad6 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -283,7 +283,7 @@
 		}
 	}
 
-	DRM_ERROR("aux i2c too many retries, giving up\n");
+	DRM_DEBUG_KMS("aux i2c too many retries, giving up\n");
 	return -EREMOTEIO;
 }
 
@@ -553,6 +553,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 	int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
 
 	if (!ASIC_IS_DCE4(rdev))
@@ -560,10 +561,20 @@
 
 	if (radeon_connector_encoder_is_dp_bridge(connector))
 		panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
+	else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP);
+		if (tmp & 1)
+			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
+	}
 
 	atombios_dig_encoder_setup(encoder,
 				   ATOM_ENCODER_CMD_SETUP_PANEL_MODE,
 				   panel_mode);
+
+	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) &&
+	    (panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) {
+		radeon_write_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_SET, 1);
+	}
 }
 
 void radeon_dp_set_link_config(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index ea7a24e..fe052c6 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -82,6 +82,7 @@
 {
 	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
 	u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset);
+	int i;
 
 	/* Lock the graphics update lock */
 	tmp |= EVERGREEN_GRPH_UPDATE_LOCK;
@@ -99,7 +100,11 @@
 	       (u32)crtc_base);
 
 	/* Wait for update_pending to go high. */
-	while (!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING));
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING)
+			break;
+		udelay(1);
+	}
 	DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
 
 	/* Unlock the lock, so double-buffering can take place inside vblank */
@@ -353,6 +358,7 @@
 		default:
 			break;
 		}
+		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
 		evergreen_irq_set(rdev);
@@ -3251,6 +3257,18 @@
 			rdev->accel_working = false;
 		}
 	}
+
+	/* Don't start up if the MC ucode is missing on BTC parts.
+	 * The default clocks and voltages before the MC ucode
+	 * is loaded are not suffient for advanced operations.
+	 */
+	if (ASIC_IS_DCE5(rdev)) {
+		if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
+			DRM_ERROR("radeon: MC ucode required for NI+.\n");
+			return -EINVAL;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 7fcdbbb..7642495 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -84,13 +84,18 @@
 {
 	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
 	u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK;
+	int i;
 
 	/* Lock the graphics update lock */
 	/* update the scanout addresses */
 	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);
 
 	/* Wait for update_pending to go high. */
-	while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET));
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)
+			break;
+		udelay(1);
+	}
 	DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
 
 	/* Unlock the lock, so double-buffering can take place inside vblank */
@@ -434,6 +439,7 @@
 		default:
 			break;
 		}
+		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
 		r100_irq_set(rdev);
@@ -2063,6 +2069,7 @@
 void r100_bm_disable(struct radeon_device *rdev)
 {
 	u32 tmp;
+	u16 tmp16;
 
 	/* disable bus mastering */
 	tmp = RREG32(R_000030_BUS_CNTL);
@@ -2073,8 +2080,8 @@
 	WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040);
 	tmp = RREG32(RADEON_BUS_CNTL);
 	mdelay(1);
-	pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
-	pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
+	pci_read_config_word(rdev->pdev, 0x4, &tmp16);
+	pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB);
 	mdelay(1);
 }
 
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 1dea9d6..1a4ed43 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -762,13 +762,14 @@
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
 
-	if (ASIC_IS_DCE3(rdev)) {
-		u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa);
-		if (ASIC_IS_DCE32(rdev))
-			tmp |= DC_HPDx_EN;
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
-		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-			struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+		if (ASIC_IS_DCE3(rdev)) {
+			u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa);
+			if (ASIC_IS_DCE32(rdev))
+				tmp |= DC_HPDx_EN;
+
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HPD1_CONTROL, tmp);
@@ -798,10 +799,7 @@
 			default:
 				break;
 			}
-		}
-	} else {
-		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-			struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+		} else {
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN);
@@ -819,6 +817,7 @@
 				break;
 			}
 		}
+		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
 		r600_irq_set(rdev);
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index f5ac7e7..c45d921 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -196,6 +196,13 @@
 	frame[0xD] = (right_bar >> 8);
 
 	r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame);
+	/* Our header values (type, version, length) should be alright, Intel
+	 * is using the same. Checksum function also seems to be OK, it works
+	 * fine for audio infoframe. However calculated value is always lower
+	 * by 2 in comparison to fglrx. It breaks displaying anything in case
+	 * of TVs that strictly check the checksum. Hack it manually here to
+	 * workaround this issue. */
+	frame[0x0] += 2;
 
 	WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0,
 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 0bb4ddf..59d72d0 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -93,6 +93,7 @@
 extern int radeon_disp_priority;
 extern int radeon_hw_i2c;
 extern int radeon_pcie_gen2;
+extern int radeon_msi;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index bf2b615..a098edc 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -85,6 +85,18 @@
 		for (i = 0; i < num_indices; i++) {
 			gpio = &i2c_info->asGPIO_Info[i];
 
+			/* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */
+			if ((rdev->family == CHIP_R420) ||
+			    (rdev->family == CHIP_R423) ||
+			    (rdev->family == CHIP_RV410)) {
+				if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) ||
+				    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) ||
+				    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) {
+					gpio->ucClkMaskShift = 0x19;
+					gpio->ucDataMaskShift = 0x18;
+				}
+			}
+
 			/* some evergreen boards have bad data for this entry */
 			if (ASIC_IS_DCE4(rdev)) {
 				if ((i == 7) &&
@@ -169,6 +181,18 @@
 			gpio = &i2c_info->asGPIO_Info[i];
 			i2c.valid = false;
 
+			/* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */
+			if ((rdev->family == CHIP_R420) ||
+			    (rdev->family == CHIP_R423) ||
+			    (rdev->family == CHIP_RV410)) {
+				if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) ||
+				    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) ||
+				    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) {
+					gpio->ucClkMaskShift = 0x19;
+					gpio->ucDataMaskShift = 0x18;
+				}
+			}
+
 			/* some evergreen boards have bad data for this entry */
 			if (ASIC_IS_DCE4(rdev)) {
 				if ((i == 7) &&
@@ -2544,7 +2568,11 @@
 
 	rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
 	rdev->pm.current_clock_mode_index = 0;
-	rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
+	if (rdev->pm.default_power_state_index >= 0)
+		rdev->pm.current_vddc =
+			rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
+	else
+		rdev->pm.current_vddc = 0;
 }
 
 void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index cd3c86c..859df6b 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -620,8 +620,8 @@
 		i2c.y_data_mask = 0x80;
 	} else {
 		/* default masks for ddc pads */
-		i2c.mask_clk_mask = RADEON_GPIO_EN_1;
-		i2c.mask_data_mask = RADEON_GPIO_EN_0;
+		i2c.mask_clk_mask = RADEON_GPIO_MASK_1;
+		i2c.mask_data_mask = RADEON_GPIO_MASK_0;
 		i2c.a_clk_mask = RADEON_GPIO_A_1;
 		i2c.a_data_mask = RADEON_GPIO_A_0;
 		i2c.en_clk_mask = RADEON_GPIO_EN_1;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 05b8b2c..2109c17 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -715,6 +715,7 @@
 		dret = radeon_ddc_probe(radeon_connector,
 					radeon_connector->requires_extended_probe);
 	if (dret) {
+		radeon_connector->detected_by_load = false;
 		if (radeon_connector->edid) {
 			kfree(radeon_connector->edid);
 			radeon_connector->edid = NULL;
@@ -741,12 +742,21 @@
 	} else {
 
 		/* if we aren't forcing don't do destructive polling */
-		if (!force)
-			return connector->status;
+		if (!force) {
+			/* only return the previous status if we last
+			 * detected a monitor via load.
+			 */
+			if (radeon_connector->detected_by_load)
+				return connector->status;
+			else
+				return ret;
+		}
 
 		if (radeon_connector->dac_load_detect && encoder) {
 			encoder_funcs = encoder->helper_private;
 			ret = encoder_funcs->detect(encoder, connector);
+			if (ret != connector_status_disconnected)
+				radeon_connector->detected_by_load = true;
 		}
 	}
 
@@ -888,6 +898,7 @@
 		dret = radeon_ddc_probe(radeon_connector,
 					radeon_connector->requires_extended_probe);
 	if (dret) {
+		radeon_connector->detected_by_load = false;
 		if (radeon_connector->edid) {
 			kfree(radeon_connector->edid);
 			radeon_connector->edid = NULL;
@@ -950,8 +961,18 @@
 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
 		goto out;
 
+	/* DVI-D and HDMI-A are digital only */
+	if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
+	    (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
+		goto out;
+
+	/* if we aren't forcing don't do destructive polling */
 	if (!force) {
-		ret = connector->status;
+		/* only return the previous status if we last
+		 * detected a monitor via load.
+		 */
+		if (radeon_connector->detected_by_load)
+			ret = connector->status;
 		goto out;
 	}
 
@@ -976,6 +997,8 @@
 					if (ret == connector_status_connected) {
 						radeon_connector->use_digital = false;
 					}
+					if (ret != connector_status_disconnected)
+						radeon_connector->detected_by_load = true;
 				}
 				break;
 			}
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 440e6ec..e87893c 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -223,8 +223,11 @@
 	if (radeon_no_wb == 1)
 		rdev->wb.enabled = false;
 	else {
-		/* often unreliable on AGP */
 		if (rdev->flags & RADEON_IS_AGP) {
+			/* often unreliable on AGP */
+			rdev->wb.enabled = false;
+		} else if (rdev->family < CHIP_R300) {
+			/* often unreliable on pre-r300 */
 			rdev->wb.enabled = false;
 		} else {
 			rdev->wb.enabled = true;
@@ -854,6 +857,8 @@
 	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
 		return 0;
 
+	drm_kms_helper_poll_disable(dev);
+
 	/* turn off display hw */
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
@@ -940,6 +945,8 @@
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
 	}
+
+	drm_kms_helper_poll_enable(dev);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 73dfbe8..60e1605 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -117,6 +117,7 @@
 int radeon_disp_priority = 0;
 int radeon_hw_i2c = 0;
 int radeon_pcie_gen2 = 0;
+int radeon_msi = -1;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -163,6 +164,9 @@
 MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)");
 module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
 
+MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(msi, radeon_msi, int, 0444);
+
 static int radeon_suspend(struct drm_device *dev, pm_message_t state)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 9ec830c..5feb6e9 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -108,6 +108,52 @@
 	radeon_irq_set(rdev);
 }
 
+static bool radeon_msi_ok(struct radeon_device *rdev)
+{
+	/* RV370/RV380 was first asic with MSI support */
+	if (rdev->family < CHIP_RV380)
+		return false;
+
+	/* MSIs don't work on AGP */
+	if (rdev->flags & RADEON_IS_AGP)
+		return false;
+
+	/* force MSI on */
+	if (radeon_msi == 1)
+		return true;
+	else if (radeon_msi == 0)
+		return false;
+
+	/* Quirks */
+	/* HP RS690 only seems to work with MSIs. */
+	if ((rdev->pdev->device == 0x791f) &&
+	    (rdev->pdev->subsystem_vendor == 0x103c) &&
+	    (rdev->pdev->subsystem_device == 0x30c2))
+		return true;
+
+	/* Dell RS690 only seems to work with MSIs. */
+	if ((rdev->pdev->device == 0x791f) &&
+	    (rdev->pdev->subsystem_vendor == 0x1028) &&
+	    (rdev->pdev->subsystem_device == 0x01fc))
+		return true;
+
+	/* Dell RS690 only seems to work with MSIs. */
+	if ((rdev->pdev->device == 0x791f) &&
+	    (rdev->pdev->subsystem_vendor == 0x1028) &&
+	    (rdev->pdev->subsystem_device == 0x01fd))
+		return true;
+
+	if (rdev->flags & RADEON_IS_IGP) {
+		/* APUs work fine with MSIs */
+		if (rdev->family >= CHIP_PALM)
+			return true;
+		/* lots of IGPs have problems with MSIs */
+		return false;
+	}
+
+	return true;
+}
+
 int radeon_irq_kms_init(struct radeon_device *rdev)
 {
 	int i;
@@ -124,12 +170,8 @@
 	}
 	/* enable msi */
 	rdev->msi_enabled = 0;
-	/* MSIs don't seem to work reliably on all IGP
-	 * chips.  Disable MSI on them for now.
-	 */
-	if ((rdev->family >= CHIP_RV380) &&
-	    ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) &&
-	    (!(rdev->flags & RADEON_IS_AGP))) {
+
+	if (radeon_msi_ok(rdev)) {
 		int ret = pci_enable_msi(rdev->pdev);
 		if (!ret) {
 			rdev->msi_enabled = 1;
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 68820f5..ed0178f 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -447,6 +447,7 @@
 	struct edid *edid;
 	void *con_priv;
 	bool dac_load_detect;
+	bool detected_by_load; /* if the connection status was determined by load */
 	uint16_t connector_object_id;
 	struct radeon_hpd hpd;
 	struct radeon_router router;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 1f5850e..21acfb5 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -62,6 +62,7 @@
 {
 	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
 	u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset);
+	int i;
 
 	/* Lock the graphics update lock */
 	tmp |= AVIVO_D1GRPH_UPDATE_LOCK;
@@ -74,7 +75,11 @@
 	       (u32)crtc_base);
 
 	/* Wait for update_pending to go high. */
-	while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING));
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)
+			break;
+		udelay(1);
+	}
 	DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
 
 	/* Unlock the lock, so double-buffering can take place inside vblank */
@@ -287,6 +292,7 @@
 		default:
 			break;
 		}
+		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
 		rs600_irq_set(rdev);
@@ -318,10 +324,10 @@
 
 void rs600_bm_disable(struct radeon_device *rdev)
 {
-	u32 tmp;
+	u16 tmp;
 
 	/* disable bus mastering */
-	pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
+	pci_read_config_word(rdev->pdev, 0x4, &tmp);
 	pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
 	mdelay(1);
 }
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index f2516e6..84cf82f 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -47,6 +47,7 @@
 {
 	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
 	u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset);
+	int i;
 
 	/* Lock the graphics update lock */
 	tmp |= AVIVO_D1GRPH_UPDATE_LOCK;
@@ -66,7 +67,11 @@
 	       (u32)crtc_base);
 
 	/* Wait for update_pending to go high. */
-	while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING));
+	for (i = 0; i < rdev->usec_timeout; i++) {
+		if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)
+			break;
+		udelay(1);
+	}
 	DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
 
 	/* Unlock the lock, so double-buffering can take place inside vblank */
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index e2b2d78..81b6850 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -394,7 +394,8 @@
 
 	if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
 		if (bo->ttm == NULL) {
-			ret = ttm_bo_add_ttm(bo, false);
+			bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED);
+			ret = ttm_bo_add_ttm(bo, zero);
 			if (ret)
 				goto out_err;
 		}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index dfe32e6..8a38c91 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -313,7 +313,7 @@
 				  unsigned int *handle)
 {
 	if (handle)
-		handle = 0;
+		*handle = 0;
 
 	return 0;
 }
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index a6c36c8..0cec423 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -107,6 +107,8 @@
 	unsigned int iommu_map_cnt;
 };
 
+static void ion_iommu_release(struct kref *kref);
+
 static int ion_validate_buffer_flags(struct ion_buffer *buffer,
 					unsigned long flags)
 {
@@ -235,11 +237,44 @@
 	return buffer;
 }
 
+/**
+ * Check for delayed IOMMU unmapping. Also unmap any outstanding
+ * mappings which would otherwise have been leaked.
+ */
+static void ion_iommu_delayed_unmap(struct ion_buffer *buffer)
+{
+	struct ion_iommu_map *iommu_map;
+	struct rb_node *node;
+	const struct rb_root *rb = &(buffer->iommu_maps);
+	unsigned long ref_count;
+	unsigned int delayed_unmap;
+
+	mutex_lock(&buffer->lock);
+
+	while ((node = rb_first(rb)) != 0) {
+		iommu_map = rb_entry(node, struct ion_iommu_map, node);
+		ref_count = atomic_read(&iommu_map->ref.refcount);
+		delayed_unmap = iommu_map->flags & ION_IOMMU_UNMAP_DELAYED;
+
+		if ((delayed_unmap && ref_count > 1) || !delayed_unmap) {
+			pr_err("%s: Virtual memory address leak in domain %u, partition %u\n",
+				__func__, iommu_map->domain_info[DI_DOMAIN_NUM],
+				iommu_map->domain_info[DI_PARTITION_NUM]);
+		}
+		/* set ref count to 1 to force release */
+		kref_init(&iommu_map->ref);
+		kref_put(&iommu_map->ref, ion_iommu_release);
+	}
+
+	mutex_unlock(&buffer->lock);
+}
+
 static void ion_buffer_destroy(struct kref *kref)
 {
 	struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
 	struct ion_device *dev = buffer->dev;
 
+	ion_iommu_delayed_unmap(buffer);
 	buffer->heap->ops->free(buffer);
 	mutex_lock(&dev->lock);
 	rb_erase(&buffer->node, &dev->buffers);
@@ -562,7 +597,7 @@
 }
 EXPORT_SYMBOL(ion_map_kernel);
 
-static int __ion_iommu_map(struct ion_buffer *buffer,
+static struct ion_iommu_map *__ion_iommu_map(struct ion_buffer *buffer,
 		int domain_num, int partition_num, unsigned long align,
 		unsigned long iova_length, unsigned long flags,
 		unsigned long *iova)
@@ -573,7 +608,7 @@
 	data = kmalloc(sizeof(*data), GFP_ATOMIC);
 
 	if (!data)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	data->buffer = buffer;
 	iommu_map_domain(data) = domain_num;
@@ -594,25 +629,30 @@
 
 	ion_iommu_add(buffer, data);
 
-	return 0;
+	return data;
 
 out:
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				buffer->size);
 	kfree(data);
-	return ret;
+	return ERR_PTR(ret);
 }
 
 int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
 			int domain_num, int partition_num, unsigned long align,
 			unsigned long iova_length, unsigned long *iova,
 			unsigned long *buffer_size,
-			unsigned long flags)
+			unsigned long flags, unsigned long iommu_flags)
 {
 	struct ion_buffer *buffer;
 	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 +671,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
@@ -665,17 +700,30 @@
 	}
 
 	iommu_map = ion_iommu_lookup(buffer, domain_num, partition_num);
-	if (_ion_map(&buffer->iommu_map_cnt, &handle->iommu_map_cnt) ||
-		!iommu_map) {
-		ret = __ion_iommu_map(buffer, domain_num, partition_num, align,
-					iova_length, flags, iova);
-		if (ret < 0)
+	_ion_map(&buffer->iommu_map_cnt, &handle->iommu_map_cnt);
+	if (!iommu_map) {
+		iommu_map = __ion_iommu_map(buffer, domain_num, partition_num,
+					    align, iova_length, flags, iova);
+		if (IS_ERR_OR_NULL(iommu_map)) {
 			_ion_unmap(&buffer->iommu_map_cnt,
 				   &handle->iommu_map_cnt);
+		} else {
+			iommu_map->flags = iommu_flags;
+
+			if (iommu_map->flags & ION_IOMMU_UNMAP_DELAYED)
+				kref_get(&iommu_map->ref);
+		}
 	} else {
-		if (iommu_map->mapped_size != iova_length) {
+		if (iommu_map->flags != iommu_flags) {
+			pr_err("%s: handle %p is already mapped with iommu flags %lx, trying to map with flags %lx\n",
+				__func__, handle,
+				iommu_map->flags, iommu_flags);
+			_ion_unmap(&buffer->iommu_map_cnt,
+				   &handle->iommu_map_cnt);
+			ret = -EINVAL;
+		} else if (iommu_map->mapped_size != iova_length) {
 			pr_err("%s: handle %p is already mapped with length"
-				" %x, trying to map with length %lx\n",
+					" %x, trying to map with length %lx\n",
 				__func__, handle, iommu_map->mapped_size,
 				iova_length);
 			_ion_unmap(&buffer->iommu_map_cnt,
@@ -882,7 +930,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_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index ad0c7b1..de9e2c4 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -110,17 +110,15 @@
 					      struct ion_buffer *buffer)
 {
 	struct scatterlist *sglist;
-	struct page *page = phys_to_page(buffer->priv_phys);
-
-	if (page == NULL)
-		return NULL;
 
 	sglist = vmalloc(sizeof(struct scatterlist));
 	if (!sglist)
 		return ERR_PTR(-ENOMEM);
 
 	sg_init_table(sglist, 1);
-	sg_set_page(sglist, page, buffer->size, 0);
+	sglist->length = buffer->size;
+	sglist->offset = 0;
+	sglist->dma_address = buffer->priv_phys;
 
 	return sglist;
 }
@@ -206,16 +204,13 @@
 	if (ion_carveout_request_region(carveout_heap))
 		return -EINVAL;
 
-	if (ION_IS_CACHED(flags))
-		ret_value = remap_pfn_range(vma, vma->vm_start,
-			       __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
-			       vma->vm_end - vma->vm_start,
-			       vma->vm_page_prot);
-	else
-		ret_value = remap_pfn_range(vma, vma->vm_start,
-			       __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
-					vma->vm_end - vma->vm_start,
-					pgprot_noncached(vma->vm_page_prot));
+	if (!ION_IS_CACHED(flags))
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	ret_value =  remap_pfn_range(vma, vma->vm_start,
+			__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
+			vma->vm_end - vma->vm_start,
+			vma->vm_page_prot);
 
 	if (ret_value)
 		ion_carveout_release_region(carveout_heap);
@@ -276,10 +271,11 @@
 					unsigned long iova_length,
 					unsigned long flags)
 {
-	unsigned long temp_phys, temp_iova;
 	struct iommu_domain *domain;
-	int i, ret = 0;
+	int ret = 0;
 	unsigned long extra;
+	int prot = ION_IS_CACHED(flags) ? 1 : 0;
+	struct scatterlist *sglist = 0;
 
 	data->mapped_size = iova_length;
 
@@ -305,32 +301,36 @@
 		goto out1;
 	}
 
-	temp_iova = data->iova_addr;
-	temp_phys = buffer->priv_phys;
-	for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
-						  temp_phys += SZ_4K) {
-		ret = iommu_map(domain, temp_iova, temp_phys,
-				get_order(SZ_4K),
-				ION_IS_CACHED(flags) ? 1 : 0);
+	sglist = vmalloc(sizeof(*sglist));
+	if (!sglist)
+		goto out1;
 
-		if (ret) {
-			pr_err("%s: could not map %lx to %lx in domain %p\n",
-				__func__, temp_iova, temp_phys, domain);
-			goto out2;
-		}
+	sg_init_table(sglist, 1);
+	sglist->length = buffer->size;
+	sglist->offset = 0;
+	sglist->dma_address = buffer->priv_phys;
+
+	ret = iommu_map_range(domain, data->iova_addr, sglist,
+			      buffer->size, prot);
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
 	}
 
-	if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
-		goto out2;
-
-	return 0;
-
+	if (extra) {
+		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		if (ret)
+			goto out2;
+	}
+	vfree(sglist);
+	return ret;
 
 out2:
-	for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+	iommu_unmap_range(domain, data->iova_addr, buffer->size);
 out1:
+	vfree(sglist);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				data->mapped_size);
 
@@ -341,8 +341,6 @@
 
 void ion_carveout_heap_unmap_iommu(struct ion_iommu_map *data)
 {
-	int i;
-	unsigned long temp_iova;
 	unsigned int domain_num;
 	unsigned int partition_num;
 	struct iommu_domain *domain;
@@ -360,10 +358,7 @@
 		return;
 	}
 
-	temp_iova = data->iova_addr;
-	for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				data->mapped_size);
 
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index a6b0cf6..7d99482 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -295,25 +295,28 @@
 	buffer->priv_phys = ION_CP_ALLOCATE_FAIL;
 }
 
-struct scatterlist *ion_cp_heap_map_dma(struct ion_heap *heap,
-					      struct ion_buffer *buffer)
+struct scatterlist *ion_cp_heap_create_sglist(struct ion_buffer *buffer)
 {
 	struct scatterlist *sglist;
-	struct page *page = phys_to_page(buffer->priv_phys);
-
-	if (page == NULL)
-		return NULL;
 
 	sglist = vmalloc(sizeof(*sglist));
 	if (!sglist)
 		return ERR_PTR(-ENOMEM);
 
 	sg_init_table(sglist, 1);
-	sg_set_page(sglist, page, buffer->size, 0);
+	sglist->length = buffer->size;
+	sglist->offset = 0;
+	sglist->dma_address = buffer->priv_phys;
 
 	return sglist;
 }
 
+struct scatterlist *ion_cp_heap_map_dma(struct ion_heap *heap,
+					      struct ion_buffer *buffer)
+{
+	return ion_cp_heap_create_sglist(buffer);
+}
+
 void ion_cp_heap_unmap_dma(struct ion_heap *heap,
 				 struct ion_buffer *buffer)
 {
@@ -450,18 +453,14 @@
 			return -EINVAL;
 		}
 
-		 if (ION_IS_CACHED(flags))
-			ret_value =  remap_pfn_range(vma, vma->vm_start,
-				__phys_to_pfn(buffer->priv_phys) +
-				vma->vm_pgoff,
-				vma->vm_end - vma->vm_start,
-				vma->vm_page_prot);
-		else
-			ret_value = remap_pfn_range(vma, vma->vm_start,
-				__phys_to_pfn(buffer->priv_phys) +
-				vma->vm_pgoff,
-				vma->vm_end - vma->vm_start,
-				pgprot_noncached(vma->vm_page_prot));
+		if (!ION_IS_CACHED(flags))
+			vma->vm_page_prot = pgprot_writecombine(
+							vma->vm_page_prot);
+
+		ret_value =  remap_pfn_range(vma, vma->vm_start,
+			__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
+			vma->vm_end - vma->vm_start,
+			vma->vm_page_prot);
 
 		if (ret_value)
 			ion_cp_release_region(cp_heap);
@@ -576,10 +575,11 @@
 				unsigned long iova_length,
 				unsigned long flags)
 {
-	unsigned long temp_phys, temp_iova;
 	struct iommu_domain *domain;
-	int i, ret = 0;
+	int ret = 0;
 	unsigned long extra;
+	int prot = ION_IS_CACHED(flags) ? 1 : 0;
+	struct scatterlist *sglist = 0;
 
 	data->mapped_size = iova_length;
 
@@ -605,30 +605,33 @@
 		goto out1;
 	}
 
-	temp_iova = data->iova_addr;
-	temp_phys = buffer->priv_phys;
-	for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
-						  temp_phys += SZ_4K) {
-		ret = iommu_map(domain, temp_iova, temp_phys,
-				get_order(SZ_4K),
-				ION_IS_CACHED(flags) ? 1 : 0);
-
-		if (ret) {
-			pr_err("%s: could not map %lx to %lx in domain %p\n",
-				__func__, temp_iova, temp_phys, domain);
-			goto out2;
-		}
+	sglist = ion_cp_heap_create_sglist(buffer);
+	if (IS_ERR_OR_NULL(sglist)) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+	ret = iommu_map_range(domain, data->iova_addr, sglist,
+			      buffer->size, prot);
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
 	}
 
-	if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
-		goto out2;
-
-	return 0;
+	if (extra) {
+		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		if (ret)
+			goto out2;
+	}
+	vfree(sglist);
+	return ret;
 
 out2:
-	for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+	iommu_unmap_range(domain, data->iova_addr, buffer->size);
 out1:
+	if (!IS_ERR_OR_NULL(sglist))
+		vfree(sglist);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				data->mapped_size);
 out:
@@ -637,8 +640,6 @@
 
 static void ion_cp_heap_unmap_iommu(struct ion_iommu_map *data)
 {
-	int i;
-	unsigned long temp_iova;
 	unsigned int domain_num;
 	unsigned int partition_num;
 	struct iommu_domain *domain;
@@ -656,10 +657,7 @@
 		return;
 	}
 
-	temp_iova = data->iova_addr;
-	for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				data->mapped_size);
 
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index d37a811..baf0a66 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -33,6 +33,7 @@
 	struct page **pages;
 	int nrpages;
 	unsigned long size;
+	struct scatterlist *iommu_sglist;
 };
 
 static int ion_iommu_heap_allocate(struct ion_heap *heap,
@@ -56,11 +57,22 @@
 			ret = -ENOMEM;
 			goto err1;
 		}
+		data->iommu_sglist = vmalloc(sizeof(*data->iommu_sglist) *
+						data->nrpages);
+		if (!data->iommu_sglist) {
+			ret = -ENOMEM;
+			goto err1;
+		}
+
+		sg_init_table(data->iommu_sglist, data->nrpages);
 
 		for (i = 0; i < data->nrpages; i++) {
 			data->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
 			if (!data->pages[i])
 				goto err2;
+
+			sg_set_page(&data->iommu_sglist[i], data->pages[i],
+				    PAGE_SIZE, 0);
 		}
 
 
@@ -73,6 +85,9 @@
 
 
 err2:
+	vfree(data->iommu_sglist);
+	data->iommu_sglist = NULL;
+
 	for (i = 0; i < data->nrpages; i++) {
 		if (data->pages[i])
 			__free_page(data->pages[i]);
@@ -94,6 +109,9 @@
 	for (i = 0; i < data->nrpages; i++)
 		__free_page(data->pages[i]);
 
+	vfree(data->iommu_sglist);
+	data->iommu_sglist = NULL;
+
 	kfree(data->pages);
 	kfree(data);
 }
@@ -131,22 +149,24 @@
 {
 	struct ion_iommu_priv_data *data = buffer->priv_virt;
 	int i;
-
+	unsigned long curr_addr;
 	if (!data)
 		return -EINVAL;
 
 	if (!ION_IS_CACHED(flags))
-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
-	for (i = 0; i < data->nrpages; i++)
-		if (vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
-			data->pages[i]))
+	curr_addr = vma->vm_start;
+	for (i = 0; i < data->nrpages && curr_addr < vma->vm_end; i++) {
+		if (vm_insert_page(vma, curr_addr, data->pages[i])) {
 			/*
 			 * This will fail the mmap which will
 			 * clean up the vma space properly.
 			 */
 			return -EINVAL;
-
+		}
+		curr_addr += PAGE_SIZE;
+	}
 	return 0;
 }
 
@@ -158,11 +178,11 @@
 					unsigned long iova_length,
 					unsigned long flags)
 {
-	unsigned long temp_iova;
 	struct iommu_domain *domain;
-	struct ion_iommu_priv_data *buffer_data = buffer->priv_virt;
-	int i, j, ret = 0;
+	int ret = 0;
 	unsigned long extra;
+	int prot = ION_IS_CACHED(flags) ? 1 : 0;
+	struct ion_iommu_priv_data *buffer_data = buffer->priv_virt;
 
 	BUG_ON(!msm_use_iommu());
 
@@ -184,36 +204,24 @@
 		goto out1;
 	}
 
-	temp_iova = data->iova_addr;
-	for (i = buffer->size, j = 0; i > 0; j++, i -= SZ_4K,
-						temp_iova += SZ_4K) {
-		ret = iommu_map(domain, temp_iova,
-				page_to_phys(buffer_data->pages[j]),
-				get_order(SZ_4K),
-				ION_IS_CACHED(flags) ? 1 : 0);
-
-		if (ret) {
-			pr_err("%s: could not map %lx to %x in domain %p\n",
-				__func__, temp_iova,
-				page_to_phys(buffer_data->pages[j]),
-				domain);
-			goto out2;
-		}
+	ret = iommu_map_range(domain, data->iova_addr,
+			      buffer_data->iommu_sglist, buffer->size, prot);
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
 	}
 
-
-	if (extra &&
-		msm_iommu_map_extra
-			(domain, temp_iova, extra, flags) < 0)
-		goto out2;
-
-	return 0;
-
+	if (extra) {
+		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		if (ret)
+			goto out2;
+	}
+	return ret;
 
 out2:
-	for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+	iommu_unmap_range(domain, data->iova_addr, buffer->size);
 out1:
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				buffer->size);
@@ -225,8 +233,6 @@
 
 void ion_iommu_heap_unmap_iommu(struct ion_iommu_map *data)
 {
-	int i;
-	unsigned long temp_iova;
 	unsigned int domain_num;
 	unsigned int partition_num;
 	struct iommu_domain *domain;
@@ -243,16 +249,59 @@
 		return;
 	}
 
-	temp_iova = data->iova_addr;
-	for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				data->mapped_size);
 
 	return;
 }
 
+static int ion_iommu_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
+			void *vaddr, unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	unsigned long vstart, pstart;
+	void (*op)(unsigned long, unsigned long, unsigned long);
+	unsigned int i;
+	struct ion_iommu_priv_data *data = buffer->priv_virt;
+
+	if (!data)
+		return -ENOMEM;
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		op = clean_caches;
+		break;
+	case ION_IOC_INV_CACHES:
+		op = invalidate_caches;
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		op = clean_and_invalidate_caches;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	vstart = (unsigned long) vaddr;
+	for (i = 0; i < data->nrpages; ++i, vstart += PAGE_SIZE) {
+		pstart = page_to_phys(data->pages[i]);
+		op(vstart, PAGE_SIZE, pstart);
+	}
+
+	return 0;
+}
+
+static struct scatterlist *ion_iommu_heap_map_dma(struct ion_heap *heap,
+					      struct ion_buffer *buffer)
+{
+	struct ion_iommu_priv_data *data = buffer->priv_virt;
+	return data->iommu_sglist;
+}
+
+static void ion_iommu_heap_unmap_dma(struct ion_heap *heap,
+				 struct ion_buffer *buffer)
+{
+}
 
 static struct ion_heap_ops iommu_heap_ops = {
 	.allocate = ion_iommu_heap_allocate,
@@ -262,6 +311,9 @@
 	.unmap_kernel = ion_iommu_heap_unmap_kernel,
 	.map_iommu = ion_iommu_heap_map_iommu,
 	.unmap_iommu = ion_iommu_heap_unmap_iommu,
+	.cache_op = ion_iommu_cache_ops,
+	.map_dma = ion_iommu_heap_map_dma,
+	.unmap_dma = ion_iommu_heap_unmap_dma,
 };
 
 struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *heap_data)
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 1d40aef..98e11cf 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -37,6 +37,12 @@
 	void *vaddr;
 };
 
+enum {
+	DI_PARTITION_NUM = 0,
+	DI_DOMAIN_NUM = 1,
+	DI_MAX,
+};
+
 /**
  * struct ion_iommu_map - represents a mapping of an ion buffer to an iommu
  * @iova_addr - iommu virtual address
@@ -47,6 +53,7 @@
  * @ref - for reference counting this mapping
  * @mapped_size - size of the iova space mapped
  *		(may not be the same as the buffer size)
+ * @flags - iommu domain/partition specific flags.
  *
  * Represents a mapping of one ion buffer to a particular iommu domain
  * and address range. There may exist other mappings of this buffer in
@@ -57,12 +64,13 @@
 	unsigned long iova_addr;
 	struct rb_node node;
 	union {
-		int domain_info[2];
+		int domain_info[DI_MAX];
 		uint64_t key;
 	};
 	struct ion_buffer *buffer;
 	struct kref ref;
 	int mapped_size;
+	unsigned long flags;
 };
 
 struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
@@ -271,4 +279,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/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 316740e..bc288e7 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -104,8 +104,6 @@
 
 void ion_system_heap_unmap_iommu(struct ion_iommu_map *data)
 {
-	int i;
-	unsigned long temp_iova;
 	unsigned int domain_num;
 	unsigned int partition_num;
 	struct iommu_domain *domain;
@@ -123,10 +121,7 @@
 		return;
 	}
 
-	temp_iova = data->iova_addr;
-	for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 				data->mapped_size);
 
@@ -206,11 +201,15 @@
 				unsigned long iova_length,
 				unsigned long flags)
 {
-	int ret, i;
-	unsigned long temp_iova;
+	int ret = 0, i;
 	struct iommu_domain *domain;
-	void *temp_phys;
 	unsigned long extra;
+	unsigned long extra_iova_addr;
+	struct page *page;
+	int npages = buffer->size >> PAGE_SHIFT;
+	void *vaddr = buffer->priv_virt;
+	struct scatterlist *sglist = 0;
+	int prot = ION_IS_CACHED(flags) ? 1 : 0;
 
 	if (!ION_IS_CACHED(flags))
 		return -EINVAL;
@@ -236,35 +235,46 @@
 		goto out1;
 	}
 
-	temp_iova = data->iova_addr;
-	temp_phys = buffer->vaddr;
-	for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
-						  temp_phys += SZ_4K) {
-		ret = iommu_map(domain, temp_iova,
-			page_to_phys(vmalloc_to_page(temp_phys)),
-			get_order(SZ_4K), ION_IS_CACHED(flags) ? 1 : 0);
 
-		if (ret) {
-			pr_err("%s: could not map %lx to %x in domain %p\n",
-				__func__, temp_iova,
-				page_to_phys(vmalloc_to_page(temp_phys)),
-				domain);
-			goto out2;
-		}
+	sglist = vmalloc(sizeof(*sglist) * npages);
+	if (!sglist) {
+		ret = -ENOMEM;
+		goto out1;
 	}
 
-	if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
-		goto out2;
+	sg_init_table(sglist, npages);
+	for (i = 0; i < npages; i++) {
+		page = vmalloc_to_page(vaddr);
+		if (!page)
+			goto out1;
+		sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
+		vaddr += PAGE_SIZE;
+	}
 
-	return 0;
+	ret = iommu_map_range(domain, data->iova_addr, sglist,
+			      buffer->size, prot);
+
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
+	}
+
+	extra_iova_addr = data->iova_addr + buffer->size;
+	if (extra) {
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		if (ret)
+			goto out2;
+	}
+	vfree(sglist);
+	return ret;
 
 out2:
-	for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+	iommu_unmap_range(domain, data->iova_addr, buffer->size);
 out1:
+	vfree(sglist);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-						data->mapped_size);
+				data->mapped_size);
 out:
 	return ret;
 }
@@ -408,10 +418,12 @@
 				unsigned long iova_length,
 				unsigned long flags)
 {
-	int ret, i;
+	int ret = 0;
 	struct iommu_domain *domain;
-	unsigned long temp_phys, temp_iova;
 	unsigned long extra;
+	int prot = ION_IS_CACHED(flags) ? 1 : 0;
+	struct scatterlist *sglist = 0;
+	struct page *page = 0;
 
 	if (!ION_IS_CACHED(flags))
 		return -EINVAL;
@@ -438,30 +450,36 @@
 		ret = -ENOMEM;
 		goto out1;
 	}
-	temp_iova = data->iova_addr;
-	temp_phys = virt_to_phys(buffer->vaddr);
-	for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
-						  temp_phys += SZ_4K) {
-		ret = iommu_map(domain, temp_iova,
-			temp_phys,
-			get_order(SZ_4K), ION_IS_CACHED(flags) ? 1 : 0);
+	page = virt_to_page(buffer->vaddr);
 
-		if (ret) {
-			pr_err("%s: could not map %lx to %lx in domain %p\n",
-				__func__, temp_iova, temp_phys, domain);
-			goto out2;
-		}
+	sglist = vmalloc(sizeof(*sglist));
+	if (!sglist)
+		goto out1;
+
+	sg_init_table(sglist, 1);
+	sg_set_page(sglist, page, buffer->size, 0);
+
+	ret = iommu_map_range(domain, data->iova_addr, sglist,
+			      buffer->size, prot);
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
 	}
 
-	if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
-		goto out2;
-
-	return 0;
+	if (extra) {
+		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		if (ret)
+			goto out2;
+	}
+	vfree(sglist);
+	return ret;
 out2:
-	for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
-		iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+	iommu_unmap_range(domain, data->iova_addr, buffer->size);
 
 out1:
+	vfree(sglist);
 	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
 						data->mapped_size);
 out:
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/Makefile b/drivers/gpu/msm/Makefile
index 5189388..c3367b5 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -16,6 +16,7 @@
 msm_kgsl_core-$(CONFIG_MSM_KGSL_DRM) += kgsl_drm.o
 msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o
 msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += kgsl_pwrscale_idlestats.o
+msm_kgsl_core-$(CONFIG_MSM_DCVS) += kgsl_pwrscale_msm.o
 
 msm_adreno-y += \
 	adreno_ringbuffer.o \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 1806886..4f5c783 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -197,8 +197,10 @@
 #define A3XX_HLSQ_CL_WG_OFFSET_REG 0x221A
 #define A3XX_VFD_CONTROL_0 0x2240
 #define A3XX_VFD_INDEX_MIN 0x2242
+#define A3XX_VFD_INDEX_MAX 0x2243
 #define A3XX_VFD_FETCH_INSTR_0_0 0x2246
 #define A3XX_VFD_FETCH_INSTR_0_4 0x224E
+#define A3XX_VFD_FETCH_INSTR_1_F 0x2265
 #define A3XX_VFD_DECODE_INSTR_0 0x2266
 #define A3XX_VFD_VS_THREADING_THRESHOLD 0x227E
 #define A3XX_VPC_ATTR 0x2280
@@ -210,11 +212,13 @@
 #define A3XX_SP_VS_OUT_REG_7 0x22CE
 #define A3XX_SP_VS_VPC_DST_REG_0 0x22D0
 #define A3XX_SP_VS_OBJ_OFFSET_REG 0x22D4
+#define A3XX_SP_VS_PVT_MEM_ADDR_REG 0x22D7
 #define A3XX_SP_VS_PVT_MEM_SIZE_REG 0x22D8
 #define A3XX_SP_VS_LENGTH_REG 0x22DF
 #define A3XX_SP_FS_CTRL_REG0 0x22E0
 #define A3XX_SP_FS_CTRL_REG1 0x22E1
 #define A3XX_SP_FS_OBJ_OFFSET_REG 0x22E2
+#define A3XX_SP_FS_PVT_MEM_ADDR_REG 0x22E5
 #define A3XX_SP_FS_PVT_MEM_SIZE_REG 0x22E6
 #define A3XX_SP_FS_FLAT_SHAD_MODE_REG_0 0x22E8
 #define A3XX_SP_FS_FLAT_SHAD_MODE_REG_1 0x22E9
@@ -229,10 +233,23 @@
 #define A3XX_VBIF_FIXED_SORT_EN 0x300C
 #define A3XX_VBIF_FIXED_SORT_SEL0 0x300D
 #define A3XX_VBIF_FIXED_SORT_SEL1 0x300E
+#define A3XX_VBIF_ABIT_SORT 0x301C
+#define A3XX_VBIF_ABIT_SORT_CONF 0x301D
+#define A3XX_VBIF_GATE_OFF_WRREQ_EN 0x302A
+#define A3XX_VBIF_IN_RD_LIM_CONF0 0x302C
+#define A3XX_VBIF_IN_RD_LIM_CONF1 0x302D
+#define A3XX_VBIF_IN_WR_LIM_CONF0 0x3030
+#define A3XX_VBIF_IN_WR_LIM_CONF1 0x3031
+#define A3XX_VBIF_OUT_RD_LIM_CONF0 0x3034
+#define A3XX_VBIF_OUT_WR_LIM_CONF0 0x3035
+#define A3XX_VBIF_DDR_OUT_MAX_BURST 0x3036
+#define A3XX_VBIF_ARB_CTL 0x303C
+#define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
+#define A3XX_VBIF_OUT_AXI_AOOO 0x305F
 
 /* Bit flags for RBBM_CTL */
 #define RBBM_RBBM_CTL_RESET_PWR_CTR1  (1 << 1)
-#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1  (17 << 1)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1  (1 << 17)
 
 /* Various flags used by the context switch code */
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 79a0e0b..fb672e4 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -113,6 +113,7 @@
 	.pfp_fw = NULL,
 	.pm4_fw = NULL,
 	.wait_timeout = 10000, /* in milliseconds */
+	.ib_check_level = 0,
 };
 
 
@@ -132,33 +133,41 @@
 	unsigned int istore_size;
 	unsigned int pix_shader_start;
 	unsigned int instruction_size; /* Size of an instruction in dwords */
+	unsigned int gmem_size; /* size of gmem for gpu*/
 } adreno_gpulist[] = {
 	{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
-		512, 384, 3},
+		512, 384, 3, SZ_256K },
+	{ ADRENO_REV_A203, 0, 1, 1, ANY_ID,
+		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
+		512, 384, 3, SZ_256K },
 	{ ADRENO_REV_A205, 0, 1, 0, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
-		512, 384, 3},
+		512, 384, 3, SZ_256K },
 	{ ADRENO_REV_A220, 2, 1, ANY_ID, ANY_ID,
 		"leia_pm4_470.fw", "leia_pfp_470.fw", &adreno_a2xx_gpudev,
-		512, 384, 3},
+		512, 384, 3, SZ_512K },
 	/*
 	 * patchlevel 5 (8960v2) needs special pm4 firmware to work around
 	 * a hardware problem.
 	 */
 	{ ADRENO_REV_A225, 2, 2, 0, 5,
 		"a225p5_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
-		1536, 768, 3 },
+		1536, 768, 3, SZ_512K },
 	{ ADRENO_REV_A225, 2, 2, 0, 6,
 		"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
-		1536, 768, 3 },
+		1536, 768, 3, SZ_512K },
 	{ ADRENO_REV_A225, 2, 2, ANY_ID, ANY_ID,
 		"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
-		1536, 768, 3 },
+		1536, 768, 3, SZ_512K },
 	/* A3XX doesn't use the pix_shader_start */
-	{ ADRENO_REV_A320, 3, 1, ANY_ID, ANY_ID,
+	{ ADRENO_REV_A305, 3, 0, 5, 0,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
-		512, 0, 2 },
+		512, 0, 2, SZ_256K },
+	/* A3XX doesn't use the pix_shader_start */
+	{ ADRENO_REV_A320, 3, 2, 0, 0,
+		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
+		512, 0, 2, SZ_512K },
 
 };
 
@@ -350,26 +359,29 @@
 static unsigned int
 a3xx_getchipid(struct kgsl_device *device)
 {
-	unsigned int chipid = 0;
-	unsigned int coreid, majorid, minorid, patchid;
-	unsigned int version;
+	unsigned int majorid, minorid, patchid;
 
-	adreno_regread(device, A3XX_RBBM_HW_VERSION, &version);
+	/*
+	 * We could detect the chipID from the hardware but it takes multiple
+	 * registers to find the right combination. Since we traffic exclusively
+	 * in system on chips, we can be (mostly) confident that a SOC version
+	 * will match a GPU (at this juncture at least).  So do the lazy/quick
+	 * thing and set the chip_id based on the SoC
+	 */
 
-	coreid = 0x03;
+	if (cpu_is_apq8064()) {
+		/* A320 */
+		majorid = 2;
+		minorid = 0;
+		patchid = 0;
+	} else if (cpu_is_msm8930()) {
+		/* A305 */
+		majorid = 0;
+		minorid = 5;
+		patchid = 0;
+	}
 
-	/* Version might not be set - if it isn't, assume this is 320 */
-	if (version)
-		majorid = version & 0x0F;
-	else
-		majorid = 1;
-
-	minorid = (version >> 4) & 0xFFF;
-	patchid = 0;
-
-	chipid = (coreid << 24) | (majorid << 16) | (minorid << 8) | patchid;
-
-	return chipid;
+	return (0x03 << 24) | (majorid << 16) | (minorid << 8) | patchid;
 }
 
 static unsigned int
@@ -387,7 +399,7 @@
 	* adreno 22x gpus are indicated by coreid 2,
 	* but REG_RBBM_PERIPHID1 always contains 0 for this field
 	*/
-	if (cpu_is_msm8960() || cpu_is_msm8x60() || cpu_is_msm8930())
+	if (cpu_is_msm8960() || cpu_is_msm8x60())
 		chipid = 2 << 24;
 	else
 		chipid = (coreid & 0xF) << 24;
@@ -400,11 +412,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;
 
@@ -414,7 +429,7 @@
 static unsigned int
 adreno_getchipid(struct kgsl_device *device)
 {
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_msm8930())
 		return a3xx_getchipid(device);
 	else
 		return a2xx_getchipid(device);
@@ -457,6 +472,7 @@
 	adreno_dev->istore_size = adreno_gpulist[i].istore_size;
 	adreno_dev->pix_shader_start = adreno_gpulist[i].pix_shader_start;
 	adreno_dev->instruction_size = adreno_gpulist[i].instruction_size;
+	adreno_dev->gmemspace.sizebytes = adreno_gpulist[i].gmem_size;
 }
 
 static int __devinit
@@ -581,6 +597,7 @@
 
 	device->ftbl->irqctrl(device, 0);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+	del_timer_sync(&device->idle_timer);
 
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
@@ -603,6 +620,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);
@@ -671,6 +690,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;
@@ -939,14 +976,13 @@
 	return status;
 }
 
-const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
 						unsigned int pt_base,
 						unsigned int gpuaddr,
 						unsigned int size)
 {
 	struct kgsl_memdesc *result = NULL;
 	struct kgsl_mem_entry *entry;
-	struct kgsl_process_private *priv;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *ringbuffer = &adreno_dev->ringbuffer;
 	struct kgsl_context *context;
@@ -961,22 +997,10 @@
 	if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
 		return &device->memstore;
 
-	mutex_lock(&kgsl_driver.process_mutex);
-	list_for_each_entry(priv, &kgsl_driver.process_list, list) {
-		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));
-		if (entry) {
-			result = &entry->memdesc;
-			spin_unlock(&priv->mem_lock);
-			mutex_unlock(&kgsl_driver.process_mutex);
-			return result;
-		}
-		spin_unlock(&priv->mem_lock);
-	}
-	mutex_unlock(&kgsl_driver.process_mutex);
+	entry = kgsl_get_mem_entry(pt_base, gpuaddr, size);
+
+	if (entry)
+		return &entry->memdesc;
 
 	while (1) {
 		struct adreno_context *adreno_context = NULL;
@@ -1011,7 +1035,7 @@
 uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
 			    unsigned int gpuaddr, unsigned int size)
 {
-	const struct kgsl_memdesc *memdesc;
+	struct kgsl_memdesc *memdesc;
 
 	memdesc = adreno_find_region(device, pt_base, gpuaddr, size);
 
@@ -1247,7 +1271,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..4885312 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -30,11 +30,15 @@
 #define KGSL_CMD_FLAGS_NOT_KERNEL_CMD	0x00000004
 
 /* Command identifiers */
-#define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0xDEADBEEF
-#define KGSL_CMD_IDENTIFIER		0xFEEDFACE
+#define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0x2EADBEEF
+#define KGSL_CMD_IDENTIFIER		0x2EEDFACE
+#define KGSL_START_OF_IB_IDENTIFIER	0x2EADEABE
+#define KGSL_END_OF_IB_IDENTIFIER	0x2ABEDEAD
 
 #ifdef CONFIG_MSM_SCM
 #define ADRENO_DEFAULT_PWRSCALE_POLICY  (&kgsl_pwrscale_policy_tz)
+#elif defined CONFIG_MSM_SLEEP_STATS_DEVICE
+#define ADRENO_DEFAULT_PWRSCALE_POLICY  (&kgsl_pwrscale_policy_idlestats)
 #else
 #define ADRENO_DEFAULT_PWRSCALE_POLICY  NULL
 #endif
@@ -44,9 +48,11 @@
 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,
+	ADRENO_REV_A305 = 305,
 	ADRENO_REV_A320 = 320,
 };
 
@@ -71,6 +77,7 @@
 	unsigned int istore_size;
 	unsigned int pix_shader_start;
 	unsigned int instruction_size;
+	unsigned int ib_check_level;
 };
 
 struct adreno_gpudev {
@@ -113,7 +120,7 @@
 void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
 				unsigned int value);
 
-const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
 						unsigned int pt_base,
 						unsigned int gpuaddr,
 						unsigned int size);
@@ -129,15 +136,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)
@@ -166,6 +177,12 @@
 	return (adreno_dev->gpurev >= 300);
 }
 
+static inline int adreno_rb_ctxtswitch(unsigned int *cmd)
+{
+	return (cmd[0] == cp_nop_packet(1) &&
+		cmd[1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER);
+}
+
 /**
  * adreno_encode_istore_size - encode istore size in CP format
  * @adreno_dev - The 3D device.
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index f2b1278..52c2ab1 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1907,7 +1907,7 @@
 	adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
 	adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
 
-	if (cpu_is_msm8960() || cpu_is_msm8930())
+	if (cpu_is_msm8960())
 		adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0x200);
 	else
 		adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0);
@@ -1930,11 +1930,6 @@
 	adreno_regwrite(device, REG_CP_INT_CNTL, 0);
 	adreno_regwrite(device, REG_SQ_INT_CNTL, 0);
 
-	if (adreno_is_a22x(adreno_dev))
-		adreno_dev->gmemspace.sizebytes = SZ_512K;
-	else
-		adreno_dev->gmemspace.sizebytes = SZ_256K;
-
 	a2xx_gmeminit(adreno_dev);
 }
 
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index f68bc41..c01e676 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/delay.h>
+#include <mach/socinfo.h>
 
 #include "kgsl.h"
 #include "adreno.h"
@@ -59,7 +60,9 @@
 	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
 	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
 	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
-	0x2750, 0x2756, 0x2760, 0x2760,
+	0x2750, 0x2756, 0x2760, 0x2760, 0x300C, 0x300E, 0x301C, 0x301D,
+	0x302A, 0x302A, 0x302C, 0x302D, 0x3030, 0x3031, 0x3034, 0x3036,
+	0x303C, 0x303C, 0x305E, 0x305F,
 };
 
 const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
@@ -130,7 +133,7 @@
 /* Use shadow RAM */
 #define HLSQ_SHADOW_BASE		(0x10000+SSIZE*2)
 
-#define REG_TO_MEM_LOOP_COUNT_SHIFT	15
+#define REG_TO_MEM_LOOP_COUNT_SHIFT	18
 
 #define BUILD_PC_DRAW_INITIATOR(prim_type, source_select, index_size, \
 	vis_cull_mode) \
@@ -1109,11 +1112,13 @@
 
 	/* Constant save */
 	cmd = rmw_regtomem(cmd, A3XX_SP_VS_CTRL_REG1, 0x000003ff,
-			   17, (HLSQ_SHADOW_BASE + 0x2000) / 4,
+			   2 + REG_TO_MEM_LOOP_COUNT_SHIFT,
+			   (HLSQ_SHADOW_BASE + 0x2000) / 4,
 			   drawctxt->constant_save_commands[1].gpuaddr);
 
 	cmd = rmw_regtomem(cmd, A3XX_SP_FS_CTRL_REG1, 0x000003ff,
-			   17, (HLSQ_SHADOW_BASE + 0x2000 + SSIZE) / 4,
+			   2 + REG_TO_MEM_LOOP_COUNT_SHIFT,
+			   (HLSQ_SHADOW_BASE + 0x2000 + SSIZE) / 4,
 			   drawctxt->constant_save_commands[2].gpuaddr);
 
 	cmd = rmw_regtomem(cmd, A3XX_SP_FS_OBJ_OFFSET_REG, 0x00ff0000,
@@ -2538,23 +2543,36 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	/* GMEM size on A320 is 512K */
-	adreno_dev->gmemspace.sizebytes = SZ_512K;
-
 	/* Reset the core */
 	adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD,
 		0x00000001);
 	msleep(20);
 
-	/*
-	 * enable fixed master AXI port of 0x0 for all clients to keep
-	 * traffic from going to random places
-	 */
+	/* Set up 16 deep read/write request queues */
 
-	adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_EN, 0x0001003F);
-	adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_SEL0, 0x00000000);
-	adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_SEL1, 0x00000000);
+	adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000303);
+	adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
 
+	/* Enable WR-REQ */
+	adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x000000FF);
+
+	/* Set up round robin arbitration between both AXI ports */
+	adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
+
+	/* Set up AOOO */
+	adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
+	adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+
+	if (cpu_is_apq8064()) {
+		/* Enable 1K sort */
+		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x000000FF);
+		adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
+	}
 	/* Make all blocks contribute to the GPU BUSY perf counter */
 	adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
 
@@ -2564,7 +2582,7 @@
 	adreno_regwrite(device, A3XX_RBBM_AHB_CTL0, 0x00000001);
 
 	/* Enable AHB error reporting */
-	adreno_regwrite(device, A3XX_RBBM_AHB_CTL1, 0x86FFFFFF);
+	adreno_regwrite(device, A3XX_RBBM_AHB_CTL1, 0xA6FFFFFF);
 
 	/* Turn on the power counters */
 	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00003000);
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index b53ca8f..9e022b9 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)
 {
@@ -80,252 +98,9 @@
 DEFINE_SIMPLE_ATTRIBUTE(kgsl_cff_dump_enable_fops, kgsl_cff_dump_enable_get,
 			kgsl_cff_dump_enable_set, "%llu\n");
 
-static int kgsl_dbgfs_open(struct inode *inode, struct file *file)
-{
-	file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static int kgsl_dbgfs_release(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int kgsl_hex_dump(const char *prefix, int c, uint8_t *data,
-	int rowc, int linec, char __user *buff)
-{
-	int ss;
-	/* Prefix of 20 chars max, 32 bytes per row, in groups of four - that's
-	 * 8 groups at 8 chars per group plus a space, plus new-line, plus
-	 * ending character */
-	char linebuf[20 + 64 + 1 + 1];
-
-	ss = snprintf(linebuf, sizeof(linebuf), prefix, c);
-	hex_dump_to_buffer(data, linec, rowc, 4, linebuf+ss,
-		sizeof(linebuf)-ss, 0);
-	strlcat(linebuf, "\n", sizeof(linebuf));
-	linebuf[sizeof(linebuf)-1] = 0;
-	ss = strlen(linebuf);
-	if (copy_to_user(buff, linebuf, ss+1))
-		return -EFAULT;
-	return ss;
-}
-
-static int kgsl_regread_nolock(struct kgsl_device *device,
-	unsigned int offsetwords, unsigned int *value)
-{
-	unsigned int *reg;
-
-	if (offsetwords*sizeof(uint32_t) >= device->regspace.sizebytes) {
-		KGSL_DRV_ERR(device, "invalid offset %d\n", offsetwords);
-		return -ERANGE;
-	}
-
-	reg = (unsigned int *)(device->regspace.mmio_virt_base
-				+ (offsetwords << 2));
-	*value = __raw_readl(reg);
-	return 0;
-}
-
-static ssize_t kgsl_istore_read(
-	struct file *file,
-	char __user *buff,
-	size_t buff_count,
-	loff_t *ppos)
-{
-	int i, count, remaining, pos = 0, tot = 0;
-	struct kgsl_device *device = file->private_data;
-	const int rowc = 8;
-	struct adreno_device *adreno_dev;
-
-	if (!ppos || !device)
-		return 0;
-
-	adreno_dev = ADRENO_DEVICE(device);
-	count = adreno_dev->istore_size * adreno_dev->instruction_size;
-
-	remaining = count;
-	for (i = 0; i < count; i += rowc) {
-		unsigned int vals[rowc];
-		int j, ss;
-		int linec = min(remaining, rowc);
-		remaining -= rowc;
-
-		if (pos >= *ppos) {
-			for (j = 0; j < linec; ++j)
-				kgsl_regread_nolock(device,
-						    ADRENO_ISTORE_START + i + j,
-						    vals + j);
-		} else
-			memset(vals, 0, sizeof(vals));
-
-		ss = kgsl_hex_dump("IS: %04x: ", i, (uint8_t *)vals, rowc*4,
-			linec*4, buff);
-		if (ss < 0)
-			return ss;
-
-		if (pos >= *ppos) {
-			if (tot+ss >= buff_count)
-				return tot;
-			tot += ss;
-			buff += ss;
-			*ppos += ss;
-		}
-		pos += ss;
-	}
-
-	return tot;
-}
-
-static const struct file_operations kgsl_istore_fops = {
-	.open = kgsl_dbgfs_open,
-	.release = kgsl_dbgfs_release,
-	.read = kgsl_istore_read,
-	.llseek = default_llseek,
-};
-
 typedef void (*reg_read_init_t)(struct kgsl_device *device);
 typedef void (*reg_read_fill_t)(struct kgsl_device *device, int i,
 	unsigned int *vals, int linec);
-static ssize_t kgsl_reg_read(struct kgsl_device *device, int count,
-	reg_read_init_t reg_read_init,
-	reg_read_fill_t reg_read_fill, const char *prefix, char __user *buff,
-	loff_t *ppos)
-{
-	int i, remaining;
-	const int rowc = 8;
-
-	if (!ppos || *ppos || !device)
-		return 0;
-
-	mutex_lock(&device->mutex);
-	reg_read_init(device);
-	remaining = count;
-	for (i = 0; i < count; i += rowc) {
-		unsigned int vals[rowc];
-		int ss;
-		int linec = min(remaining, rowc);
-		remaining -= rowc;
-
-		reg_read_fill(device, i, vals, linec);
-		ss = kgsl_hex_dump(prefix, i, (uint8_t *)vals, rowc*4, linec*4,
-			buff);
-		if (ss < 0) {
-			mutex_unlock(&device->mutex);
-			return ss;
-		}
-		buff += ss;
-		*ppos += ss;
-	}
-	mutex_unlock(&device->mutex);
-
-	return *ppos;
-}
-
-
-static void kgsl_sx_reg_read_init(struct kgsl_device *device)
-{
-	kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
-	kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
-}
-
-static void kgsl_sx_reg_read_fill(struct kgsl_device *device, int i,
-	unsigned int *vals, int linec)
-{
-	int j;
-
-	for (j = 0; j < linec; ++j) {
-		kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
-		kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
-	}
-}
-
-static ssize_t kgsl_sx_debug_read(
-	struct file *file,
-	char __user *buff,
-	size_t buff_count,
-	loff_t *ppos)
-{
-	struct kgsl_device *device = file->private_data;
-	return kgsl_reg_read(device, 0x1B, kgsl_sx_reg_read_init,
-			     kgsl_sx_reg_read_fill, "SX: %02x: ", buff, ppos);
-}
-
-static const struct file_operations kgsl_sx_debug_fops = {
-	.open = kgsl_dbgfs_open,
-	.release = kgsl_dbgfs_release,
-	.read = kgsl_sx_debug_read,
-};
-
-static void kgsl_cp_reg_read_init(struct kgsl_device *device)
-{
-	kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
-}
-
-static void kgsl_cp_reg_read_fill(struct kgsl_device *device, int i,
-	unsigned int *vals, int linec)
-{
-	int j;
-
-	for (j = 0; j < linec; ++j) {
-		kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
-		kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
-		msleep(100);
-	}
-}
-
-static ssize_t kgsl_cp_debug_read(
-	struct file *file,
-	char __user *buff,
-	size_t buff_count,
-	loff_t *ppos)
-{
-	struct kgsl_device *device = file->private_data;
-	return kgsl_reg_read(device, 20, kgsl_cp_reg_read_init,
-		kgsl_cp_reg_read_fill,
-		"CP: %02x: ", buff, ppos);
-}
-
-static const struct file_operations kgsl_cp_debug_fops = {
-	.open = kgsl_dbgfs_open,
-	.release = kgsl_dbgfs_release,
-	.read = kgsl_cp_debug_read,
-};
-
-static void kgsl_mh_reg_read_init(struct kgsl_device *device)
-{
-	kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
-}
-
-static void kgsl_mh_reg_read_fill(struct kgsl_device *device, int i,
-	unsigned int *vals, int linec)
-{
-	int j;
-
-	for (j = 0; j < linec; ++j) {
-		kgsl_regwrite(device, MH_DEBUG_CTRL, i+j);
-		kgsl_regread(device, MH_DEBUG_DATA, vals+j);
-	}
-}
-
-static ssize_t kgsl_mh_debug_read(
-	struct file *file,
-	char __user *buff,
-	size_t buff_count,
-	loff_t *ppos)
-{
-	struct kgsl_device *device = file->private_data;
-	return kgsl_reg_read(device, 0x40, kgsl_mh_reg_read_init,
-		kgsl_mh_reg_read_fill,
-		"MH: %02x: ", buff, ppos);
-}
-
-static const struct file_operations kgsl_mh_debug_fops = {
-	.open = kgsl_dbgfs_open,
-	.release = kgsl_dbgfs_release,
-	.read = kgsl_mh_debug_read,
-};
 
 void adreno_debugfs_init(struct kgsl_device *device)
 {
@@ -334,18 +109,12 @@
 	if (!device->d_debugfs || IS_ERR(device->d_debugfs))
 		return;
 
-	debugfs_create_file("istore",   0400, device->d_debugfs, device,
-			    &kgsl_istore_fops);
-	debugfs_create_file("sx_debug", 0400, device->d_debugfs, device,
-			    &kgsl_sx_debug_fops);
-	debugfs_create_file("cp_debug", 0400, device->d_debugfs, device,
-			    &kgsl_cp_debug_fops);
-	debugfs_create_file("mh_debug", 0400, device->d_debugfs, device,
-			    &kgsl_mh_debug_fops);
 	debugfs_create_file("cff_dump", 0644, device->d_debugfs, device,
 			    &kgsl_cff_dump_enable_fops);
 	debugfs_create_u32("wait_timeout", 0644, device->d_debugfs,
 		&adreno_dev->wait_timeout);
+	debugfs_create_u32("ib_check", 0644, device->d_debugfs,
+			   &adreno_dev->ib_check_level);
 
 	/* Create post mortem control files */
 
@@ -358,4 +127,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 0356ac6..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 1dffc32..fb44b25 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -29,11 +29,6 @@
 /* skip N 32-bit words to get to the next packet */
 #define CP_NOP			0x10
 
-/* indirect buffer dispatch.  prefetch parser uses this packet type to determine
-*  whether to pre-fetch the IB
-*/
-#define CP_INDIRECT_BUFFER	0x3f
-
 /* indirect buffer dispatch.  same as IB, but init is pipelined */
 #define CP_INDIRECT_BUFFER_PFD	0x37
 
@@ -58,6 +53,9 @@
 /* register read/modify/write */
 #define CP_REG_RMW		0x21
 
+/* Set binning configuration registers */
+#define CP_SET_BIN_DATA             0x2f
+
 /* reads register in chip and writes to memory */
 #define CP_REG_TO_MEM		0x3e
 
@@ -117,6 +115,9 @@
 /* load constants from a location in memory */
 #define CP_LOAD_CONSTANT_CONTEXT 0x2e
 
+/* (A2x) sets binning configuration registers */
+#define CP_SET_BIN_DATA             0x2f
+
 /* selective invalidation of state pointers */
 #define CP_INVALIDATE_STATE	0x3b
 
@@ -163,6 +164,13 @@
 
 #define CP_LOAD_STATE 0x30 /* load high level sequencer command */
 
+/* Conditionally load a IB based on a flag */
+#define CP_COND_INDIRECT_BUFFER_PFE 0x3A /* prefetch enabled */
+#define CP_COND_INDIRECT_BUFFER_PFD 0x32 /* prefetch disabled */
+
+/* Load a buffer with pre-fetch enabled */
+#define CP_INDIRECT_BUFFER_PFE 0x3F
+
 #define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
 #define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
 #define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
@@ -190,11 +198,20 @@
 #define cp_nop_packet(cnt) \
 	 (CP_TYPE3_PKT | (((cnt)-1) << 16) | (CP_NOP << 8))
 
+#define pkt_is_type0(pkt) (((pkt) & 0XC0000000) == CP_TYPE0_PKT)
+
+#define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
+#define type0_pkt_offset(pkt) ((pkt) & 0x7FFF)
+
+#define pkt_is_type3(pkt) (((pkt) & 0xC0000000) == CP_TYPE3_PKT)
+
+#define cp_type3_opcode(pkt) (((pkt) >> 8) & 0xFF)
+#define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
 
 /* packet headers */
 #define CP_HDR_ME_INIT	cp_type3_packet(CP_ME_INIT, 18)
 #define CP_HDR_INDIRECT_BUFFER_PFD cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)
-#define CP_HDR_INDIRECT_BUFFER	cp_type3_packet(CP_INDIRECT_BUFFER, 2)
+#define CP_HDR_INDIRECT_BUFFER_PFE cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2)
 
 /* dword base address of the GFX decode space */
 #define SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000)))
@@ -202,4 +219,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 98e3810..d97659c 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -54,7 +54,7 @@
 	{CP_IM_LOAD,			"IN__LOAD"},
 	{CP_IM_LOAD_IMMEDIATE,		"IM_LOADI"},
 	{CP_IM_STORE,			"IM_STORE"},
-	{CP_INDIRECT_BUFFER,		"IND_BUF_"},
+	{CP_INDIRECT_BUFFER_PFE,	"IND_BUF_"},
 	{CP_INDIRECT_BUFFER_PFD,	"IND_BUFP"},
 	{CP_INTERRUPT,			"PM4_INTR"},
 	{CP_INVALIDATE_STATE,		"INV_STAT"},
@@ -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;
@@ -674,7 +665,8 @@
 		"        MPU_END    = %08X | VA_RANGE = %08X | PT_BASE  ="
 		" %08X\n", r1, r2, r3);
 
-	KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ", KGSL_PAGETABLE_SIZE);
+	KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ",
+		kgsl_mmu_get_ptsize());
 
 	kgsl_regread(device, MH_MMU_TRAN_ERROR, &r1);
 	KGSL_LOG_DUMP(device, "        TRAN_ERROR = %08X\n", r1);
@@ -778,7 +770,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 +809,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 +840,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);
@@ -876,6 +868,7 @@
 
 int adreno_postmortem_dump(struct kgsl_device *device, int manual)
 {
+	bool saved_nap;
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 
 	BUG_ON(device == NULL);
@@ -907,17 +900,28 @@
 	KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
 		kgsl_get_clkrate(pwr->ebi1_clk));
 
-	/*
-	 * Disable the irq, idle timer, and workqueue so we don't
-	 * get interrupted
-	 */
-	kgsl_pwrctrl_stop_work(device);
+	/* Disable the idle timer so we don't get interrupted */
+	del_timer_sync(&device->idle_timer);
+	mutex_unlock(&device->mutex);
+	flush_workqueue(device->work_queue);
+	mutex_lock(&device->mutex);
+
+	/* Turn off napping to make sure we have the clocks full
+	   attention through the following process */
+	saved_nap = device->pwrctrl.nap_allowed;
+	device->pwrctrl.nap_allowed = false;
 
 	/* Force on the clocks */
-	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+	kgsl_pwrctrl_wake(device);
+
+	/* Disable the irq */
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 
 	adreno_dump(device);
 
+	/* Restore nap mode */
+	device->pwrctrl.nap_allowed = saved_nap;
+
 	/* On a manual trigger, turn on the interrupts and put
 	   the clocks to sleep.  They will recover themselves
 	   on the next event.  For a hang, leave things as they
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a5c20dc..b9c0a28 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -22,6 +22,7 @@
 #include "adreno.h"
 #include "adreno_pm4types.h"
 #include "adreno_ringbuffer.h"
+#include "adreno_debugfs.h"
 
 #include "a2xx_reg.h"
 #include "a3xx_reg.h"
@@ -545,6 +546,198 @@
 	adreno_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
 }
 
+static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
+			   int sizedwords);
+
+static bool
+_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
+{
+	unsigned int opcode = cp_type3_opcode(*hostaddr);
+	switch (opcode) {
+	case CP_INDIRECT_BUFFER_PFD:
+	case CP_INDIRECT_BUFFER_PFE:
+	case CP_COND_INDIRECT_BUFFER_PFE:
+	case CP_COND_INDIRECT_BUFFER_PFD:
+		return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
+	case CP_NOP:
+	case CP_WAIT_FOR_IDLE:
+	case CP_WAIT_REG_MEM:
+	case CP_WAIT_REG_EQ:
+	case CP_WAT_REG_GTE:
+	case CP_WAIT_UNTIL_READ:
+	case CP_WAIT_IB_PFD_COMPLETE:
+	case CP_REG_RMW:
+	case CP_REG_TO_MEM:
+	case CP_MEM_WRITE:
+	case CP_MEM_WRITE_CNTR:
+	case CP_COND_EXEC:
+	case CP_COND_WRITE:
+	case CP_EVENT_WRITE:
+	case CP_EVENT_WRITE_SHD:
+	case CP_EVENT_WRITE_CFL:
+	case CP_EVENT_WRITE_ZPD:
+	case CP_DRAW_INDX:
+	case CP_DRAW_INDX_2:
+	case CP_DRAW_INDX_BIN:
+	case CP_DRAW_INDX_2_BIN:
+	case CP_VIZ_QUERY:
+	case CP_SET_STATE:
+	case CP_SET_CONSTANT:
+	case CP_IM_LOAD:
+	case CP_IM_LOAD_IMMEDIATE:
+	case CP_LOAD_CONSTANT_CONTEXT:
+	case CP_INVALIDATE_STATE:
+	case CP_SET_SHADER_BASES:
+	case CP_SET_BIN_MASK:
+	case CP_SET_BIN_SELECT:
+	case CP_SET_BIN_BASE_OFFSET:
+	case CP_SET_BIN_DATA:
+	case CP_CONTEXT_UPDATE:
+	case CP_INTERRUPT:
+	case CP_IM_STORE:
+	case CP_LOAD_STATE:
+		break;
+	/* these shouldn't come from userspace */
+	case CP_ME_INIT:
+	case CP_SET_PROTECTED_MODE:
+	default:
+		KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
+		return false;
+		break;
+	}
+
+	return true;
+}
+
+static bool
+_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
+{
+	unsigned int reg = type0_pkt_offset(*hostaddr);
+	unsigned int cnt = type0_pkt_size(*hostaddr);
+	if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
+		KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
+			     reg, cnt);
+		return false;
+	}
+	return true;
+}
+
+/*
+ * Traverse IBs and dump them to test vector. Detect swap by inspecting
+ * register writes, keeping note of the current state, and dump
+ * framebuffer config to test vector
+ */
+static bool _parse_ibs(struct kgsl_device_private *dev_priv,
+			   uint gpuaddr, int sizedwords)
+{
+	static uint level; /* recursion level */
+	bool ret = false;
+	uint *hostaddr, *hoststart;
+	int dwords_left = sizedwords; /* dwords left in the current command
+					 buffer */
+	struct kgsl_mem_entry *entry;
+
+	spin_lock(&dev_priv->process_priv->mem_lock);
+	entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
+					   gpuaddr, sizedwords * sizeof(uint));
+	spin_unlock(&dev_priv->process_priv->mem_lock);
+	if (entry == NULL) {
+		KGSL_CMD_ERR(dev_priv->device,
+			     "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
+		return false;
+	}
+
+	hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
+	if (hostaddr == NULL) {
+		KGSL_CMD_ERR(dev_priv->device,
+			     "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
+		return false;
+	}
+
+	hoststart = hostaddr;
+
+	level++;
+
+	KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
+		gpuaddr, sizedwords, hostaddr);
+
+	mb();
+	while (dwords_left > 0) {
+		bool cur_ret = true;
+		int count = 0; /* dword count including packet header */
+
+		switch (*hostaddr >> 30) {
+		case 0x0: /* type-0 */
+			count = (*hostaddr >> 16)+2;
+			cur_ret = _handle_type0(dev_priv, hostaddr);
+			break;
+		case 0x1: /* type-1 */
+			count = 2;
+			break;
+		case 0x3: /* type-3 */
+			count = ((*hostaddr >> 16) & 0x3fff) + 2;
+			cur_ret = _handle_type3(dev_priv, hostaddr);
+			break;
+		default:
+			KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
+				"type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
+				*hostaddr >> 30, *hostaddr, hostaddr,
+				gpuaddr+4*(sizedwords-dwords_left));
+			cur_ret = false;
+			count = dwords_left;
+			break;
+		}
+
+		if (!cur_ret) {
+			KGSL_CMD_ERR(dev_priv->device,
+				"bad sub-type: #:%d/%d, v:0x%08x"
+				" @ 0x%p[gb:0x%08x], level:%d\n",
+				sizedwords-dwords_left, sizedwords, *hostaddr,
+				hostaddr, gpuaddr+4*(sizedwords-dwords_left),
+				level);
+
+			if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
+				>= 2)
+				print_hex_dump(KERN_ERR,
+					level == 1 ? "IB1:" : "IB2:",
+					DUMP_PREFIX_OFFSET, 32, 4, hoststart,
+					sizedwords*4, 0);
+			goto done;
+		}
+
+		/* jump to next packet */
+		dwords_left -= count;
+		hostaddr += count;
+		if (dwords_left < 0) {
+			KGSL_CMD_ERR(dev_priv->device,
+				"bad count: c:%d, #:%d/%d, "
+				"v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
+				count, sizedwords-(dwords_left+count),
+				sizedwords, *(hostaddr-count), hostaddr-count,
+				gpuaddr+4*(sizedwords-(dwords_left+count)),
+				level);
+			if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
+				>= 2)
+				print_hex_dump(KERN_ERR,
+					level == 1 ? "IB1:" : "IB2:",
+					DUMP_PREFIX_OFFSET, 32, 4, hoststart,
+					sizedwords*4, 0);
+			goto done;
+		}
+	}
+
+	ret = true;
+done:
+	if (!ret)
+		KGSL_DRV_ERR(dev_priv->device,
+			"parsing failed: gpuaddr:0x%08x, "
+			"host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
+
+	level--;
+
+	return ret;
+}
+
 int
 adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
 				struct kgsl_context *context,
@@ -575,11 +768,12 @@
 			drawctxt);
 		return -EDEADLK;
 	}
-	link = kzalloc(sizeof(unsigned int) * numibs * 3, GFP_KERNEL);
-	cmds = link;
+
+	cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
+				GFP_KERNEL);
 	if (!link) {
-		KGSL_MEM_ERR(device, "Failed to allocate memory for for command"
-			" submission, size %x\n", numibs * 3);
+		KGSL_CORE_ERR("kzalloc(%d) failed\n",
+			sizeof(unsigned int) * (numibs * 3 + 4));
 		return -ENOMEM;
 	}
 
@@ -591,15 +785,31 @@
 		adreno_dev->drawctxt_active == drawctxt)
 		start_index = 1;
 
+	if (!start_index) {
+		*cmds++ = cp_nop_packet(1);
+		*cmds++ = KGSL_START_OF_IB_IDENTIFIER;
+	} else {
+		*cmds++ = cp_nop_packet(4);
+		*cmds++ = KGSL_START_OF_IB_IDENTIFIER;
+		*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
+		*cmds++ = ibdesc[0].gpuaddr;
+		*cmds++ = ibdesc[0].sizedwords;
+	}
 	for (i = start_index; i < numibs; i++) {
-		(void)kgsl_cffdump_parse_ibs(dev_priv, NULL,
-			ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false);
-
+		if (unlikely(adreno_dev->ib_check_level >= 1 &&
+		    !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
+				ibdesc[i].sizedwords))) {
+			kfree(link);
+			return -EINVAL;
+		}
 		*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
 		*cmds++ = ibdesc[i].gpuaddr;
 		*cmds++ = ibdesc[i].sizedwords;
 	}
 
+	*cmds++ = cp_nop_packet(1);
+	*cmds++ = KGSL_END_OF_IB_IDENTIFIER;
+
 	kgsl_setstate(device,
 		      kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
 					device->id));
@@ -641,7 +851,6 @@
 	unsigned int val3;
 	unsigned int copy_rb_contents = 0;
 	unsigned int cur_context;
-	unsigned int j;
 
 	GSL_RB_GET_READPTR(rb, &rb->rptr);
 
@@ -748,8 +957,20 @@
 			kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
 			rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
 							rb->buffer_desc.size);
-			BUG_ON((copy_rb_contents == 0) &&
-				(value == cur_context));
+
+			/*
+			 * If other context switches were already lost and
+			 * and the current context is the one that is hanging,
+			 * then we cannot recover.  Print an error message
+			 * and leave.
+			 */
+
+			if ((copy_rb_contents == 0) && (value == cur_context)) {
+				KGSL_DRV_ERR(device, "GPU recovery could not "
+					"find the previous context\n");
+				return -EINVAL;
+			}
+
 			/*
 			 * If we were copying the commands and got to this point
 			 * then we need to remove the 3 commands that appear
@@ -780,19 +1001,6 @@
 	}
 
 	*rb_size = temp_idx;
-	KGSL_DRV_ERR(device, "Extracted rb contents, size: %x\n", *rb_size);
-	for (temp_idx = 0; temp_idx < *rb_size;) {
-		char str[80];
-		int idx = 0;
-		if ((temp_idx + 8) <= *rb_size)
-			j = 8;
-		else
-			j = *rb_size - temp_idx;
-		for (; j != 0; j--)
-			idx += scnprintf(str + idx, 80 - idx,
-				"%8.8X ", temp_rb_buffer[temp_idx++]);
-		printk(KERN_ALERT "%s", str);
-	}
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 0361387..d0110b9 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -13,10 +13,6 @@
 #ifndef __ADRENO_RINGBUFFER_H
 #define __ADRENO_RINGBUFFER_H
 
-#define GSL_RB_USE_MEM_RPTR
-#define GSL_RB_USE_MEM_TIMESTAMP
-#define GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
-
 /*
  * Adreno ringbuffer sizes in bytes - these are converted to
  * the appropriate log2 values in the code
@@ -71,37 +67,16 @@
 		gpuaddr += sizeof(uint); \
 	} while (0)
 
-/* timestamp */
-#ifdef GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
-#define GSL_RB_USE_MEM_TIMESTAMP
-#endif /* GSL_DEVICE_SHADOW_MEMSTORE_TO_USER */
-
-#ifdef GSL_RB_USE_MEM_TIMESTAMP
 /* enable timestamp (...scratch0) memory shadowing */
 #define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1
 #define GSL_RB_INIT_TIMESTAMP(rb)
 
-#else
-#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x0
-#define GSL_RB_INIT_TIMESTAMP(rb) \
-		adreno_regwrite((rb)->device->id, REG_CP_TIMESTAMP, 0)
-
-#endif /* GSL_RB_USE_MEMTIMESTAMP */
-
 /* mem rptr */
-#ifdef GSL_RB_USE_MEM_RPTR
 #define GSL_RB_CNTL_NO_UPDATE 0x0 /* enable */
 #define GSL_RB_GET_READPTR(rb, data) \
 	do { \
 		*(data) = rb->memptrs->rptr; \
 	} while (0)
-#else
-#define GSL_RB_CNTL_NO_UPDATE 0x1 /* disable */
-#define GSL_RB_GET_READPTR(rb, data) \
-	do { \
-		adreno_regread((rb)->device->id, REG_CP_RB_RPTR, (data)); \
-	} while (0)
-#endif /* GSL_RB_USE_MEMRPTR */
 
 #define GSL_RB_CNTL_POLL_EN 0x0 /* disable */
 
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index cc3f3e7..bca7040 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -17,6 +17,7 @@
 #include "adreno.h"
 #include "adreno_pm4types.h"
 #include "a2xx_reg.h"
+#include "a3xx_reg.h"
 
 /* Number of dwords of ringbuffer history to record */
 #define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100
@@ -27,6 +28,9 @@
 
 #define SNAPSHOT_OBJ_TYPE_IB 0
 
+/* Keep track of how many bytes are frozen after a snapshot and tell the user */
+static int snapshot_frozen_objsize;
+
 static struct kgsl_snapshot_obj {
 	int type;
 	uint32_t gpuaddr;
@@ -45,11 +49,19 @@
 	int index;
 	void *ptr;
 
-	/* Go through the list and see that object has already been seen */
+	/*
+	 * Sometimes IBs can be reused in the same dump.  Because we parse from
+	 * oldest to newest, if we come across an IB that has already been used,
+	 * assume that it has been reused and update the list with the newest
+	 * size.
+	 */
+
 	for (index = 0; index < objbufptr; index++) {
 		if (objbuf[index].gpuaddr == gpuaddr &&
-			objbuf[index].ptbase == ptbase)
-			return;
+			objbuf[index].ptbase == ptbase) {
+				objbuf[index].dwords = dwords;
+				return;
+			}
 	}
 
 	if (objbufptr == SNAPSHOT_OBJ_BUFSIZE) {
@@ -77,6 +89,406 @@
 	objbuf[objbufptr++].ptr = ptr;
 }
 
+/*
+ * Return a 1 if the specified object is already on the list of buffers
+ * to be dumped
+ */
+
+static int find_object(int type, unsigned int gpuaddr, unsigned int ptbase)
+{
+	int index;
+
+	for (index = 0; index < objbufptr; index++) {
+		if (objbuf[index].gpuaddr == gpuaddr &&
+			objbuf[index].ptbase == ptbase &&
+			objbuf[index].type == type)
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * This structure keeps track of type0 writes to VSC_PIPE_DATA_ADDRESS_x and
+ * VSC_PIPE_DATA_LENGTH_x. When a draw initator is called these registers
+ * point to buffers that we need to freeze for a snapshot
+ */
+
+static struct {
+	unsigned int base;
+	unsigned int size;
+} vsc_pipe[8];
+
+/*
+ * This is the cached value of type0 writes to the VSC_SIZE_ADDRESS which
+ * contains the buffer address of the visiblity stream size buffer during a
+ * binning pass
+ */
+
+static unsigned int vsc_size_address;
+
+/*
+ * This struct keeps track of type0 writes to VFD_FETCH_INSTR_0_X and
+ * VFD_FETCH_INSTR_1_X registers. When a draw initator is called the addresses
+ * and sizes in these registers point to VBOs that we need to freeze for a
+ * snapshot
+ */
+
+static struct {
+	unsigned int base;
+	unsigned int stride;
+} vbo[16];
+
+/*
+ * This is the cached value of type0 writes to VFD_INDEX_MAX.  This will be used
+ * to calculate the size of the VBOs when the draw initator is called
+ */
+
+static unsigned int vfd_index_max;
+
+/*
+ * This is the cached value of type0 writes to VFD_CONTROL_0 which tells us how
+ * many VBOs are active when the draw initator is called
+ */
+
+static unsigned int vfd_control_0;
+
+/*
+ * Cached value of type0 writes to SP_VS_PVT_MEM_ADDR and SP_FS_PVT_MEM_ADDR.
+ * This is a buffer that contains private stack information for the shader
+ */
+
+static unsigned int sp_vs_pvt_mem_addr;
+static unsigned int sp_fs_pvt_mem_addr;
+
+static void ib_parse_load_state(struct kgsl_device *device, unsigned int *pkt,
+	unsigned int ptbase)
+{
+	unsigned int block, source, type;
+
+	/*
+	 * The object here is to find indirect shaders i.e - shaders loaded from
+	 * GPU memory instead of directly in the command.  These should be added
+	 * to the list of memory objects to dump. So look at the load state
+	 * call and see if 1) the shader block is a shader (block = 4, 5 or 6)
+	 * 2) that the block is indirect (source = 4). If these all match then
+	 * add the memory address to the list.  The size of the object will
+	 * differ depending on the type.  Type 0 (instructions) are 8 dwords per
+	 * unit and type 1 (constants) are 2 dwords per unit.
+	 */
+
+	if (type3_pkt_size(pkt[0]) < 2)
+		return;
+
+	/*
+	 * pkt[1] 18:16 - source
+	 * pkt[1] 21:19 - state block
+	 * pkt[1] 31:22 - size in units
+	 * pkt[2] 0:1 - type
+	 * pkt[2] 31:2 - GPU memory address
+	 */
+
+	block = (pkt[1] >> 19) & 0x07;
+	source = (pkt[1] >> 16) & 0x07;
+	type = pkt[2] & 0x03;
+
+	if ((block == 4 || block == 5 || block == 6) && source == 4) {
+		int unitsize = (type == 0) ? 8 : 2;
+		int ret;
+
+		/* Freeze the GPU buffer containing the shader */
+
+		ret = kgsl_snapshot_get_object(device, ptbase,
+				pkt[2] & 0xFFFFFFFC,
+				(((pkt[1] >> 22) & 0x03FF) * unitsize) << 2,
+				SNAPSHOT_GPU_OBJECT_SHADER);
+		snapshot_frozen_objsize += ret;
+	}
+}
+
+/*
+ * This opcode sets the base addresses for the visibilty stream buffer and the
+ * visiblity stream size buffer.
+ */
+
+static void ib_parse_set_bin_data(struct kgsl_device *device, unsigned int *pkt,
+	unsigned int ptbase)
+{
+	int ret;
+
+	if (type3_pkt_size(pkt[0]) < 2)
+		return;
+
+	/* Visiblity stream buffer */
+	ret = kgsl_snapshot_get_object(device, ptbase, pkt[1], 0,
+			SNAPSHOT_GPU_OBJECT_GENERIC);
+	snapshot_frozen_objsize += ret;
+
+	/* visiblity stream size buffer (fixed size 8 dwords) */
+	ret = kgsl_snapshot_get_object(device, ptbase, pkt[2], 32,
+			SNAPSHOT_GPU_OBJECT_GENERIC);
+	snapshot_frozen_objsize += ret;
+}
+
+/*
+ * This opcode writes to GPU memory - if the buffer is written to, there is a
+ * good chance that it would be valuable to capture in the snapshot, so mark all
+ * buffers that are written to as frozen
+ */
+
+static void ib_parse_mem_write(struct kgsl_device *device, unsigned int *pkt,
+	unsigned int ptbase)
+{
+	int ret;
+
+	if (type3_pkt_size(pkt[0]) < 1)
+		return;
+
+	/*
+	 * The address is where the data in the rest of this packet is written
+	 * to, but since that might be an offset into the larger buffer we need
+	 * to get the whole thing. Pass a size of 0 kgsl_snapshot_get_object to
+	 * capture the entire buffer.
+	 */
+
+	ret = kgsl_snapshot_get_object(device, ptbase, pkt[1] & 0xFFFFFFFC, 0,
+		SNAPSHOT_GPU_OBJECT_GENERIC);
+
+	snapshot_frozen_objsize += ret;
+}
+
+/*
+ * The DRAW_INDX opcode sends a draw initator which starts a draw operation in
+ * the GPU, so this is the point where all the registers and buffers become
+ * "valid".  The DRAW_INDX may also have an index buffer pointer that should be
+ * frozen with the others
+ */
+
+static void ib_parse_draw_indx(struct kgsl_device *device, unsigned int *pkt,
+	unsigned int ptbase)
+{
+	int ret, i;
+
+	if (type3_pkt_size(pkt[0]) < 3)
+		return;
+
+	/*  DRAW_IDX may have a index buffer pointer */
+
+	if (type3_pkt_size(pkt[0]) > 3) {
+		ret = kgsl_snapshot_get_object(device, ptbase, pkt[4], pkt[5],
+			SNAPSHOT_GPU_OBJECT_GENERIC);
+		snapshot_frozen_objsize += ret;
+	}
+
+	/*
+	 * All of the type0 writes are valid at a draw initiator, so freeze
+	 * the various buffers that we are tracking
+	 */
+
+	/* First up the visiblity stream buffer */
+
+	for (i = 0; i < ARRAY_SIZE(vsc_pipe); i++) {
+		if (vsc_pipe[i].base != 0 && vsc_pipe[i].size != 0) {
+			ret = kgsl_snapshot_get_object(device, ptbase,
+				vsc_pipe[i].base, vsc_pipe[i].size,
+				SNAPSHOT_GPU_OBJECT_GENERIC);
+			snapshot_frozen_objsize += ret;
+		}
+	}
+
+	/* Next the visibility stream size buffer */
+
+	if (vsc_size_address) {
+		ret = kgsl_snapshot_get_object(device, ptbase,
+				vsc_size_address, 32,
+				SNAPSHOT_GPU_OBJECT_GENERIC);
+		snapshot_frozen_objsize += ret;
+	}
+
+	/* Next private shader buffer memory */
+	if (sp_vs_pvt_mem_addr) {
+		ret = kgsl_snapshot_get_object(device, ptbase,
+				sp_vs_pvt_mem_addr, 8192,
+				SNAPSHOT_GPU_OBJECT_GENERIC);
+
+		snapshot_frozen_objsize += ret;
+	}
+
+	if (sp_fs_pvt_mem_addr) {
+		ret = kgsl_snapshot_get_object(device, ptbase,
+				sp_fs_pvt_mem_addr, 8192,
+				SNAPSHOT_GPU_OBJECT_GENERIC);
+		snapshot_frozen_objsize += ret;
+	}
+
+	/* Finally: VBOs */
+
+	/* The number of active VBOs is stored in VFD_CONTROL_O[31:27] */
+	for (i = 0; i < (vfd_control_0) >> 27; i++) {
+		int size;
+
+		/*
+		 * The size of the VBO is the stride stored in
+		 * VFD_FETCH_INSTR_0_X.BUFSTRIDE * VFD_INDEX_MAX. The base
+		 * is stored in VFD_FETCH_INSTR_1_X
+		 */
+
+		if (vbo[i].base != 0) {
+			size = vbo[i].stride * vfd_index_max;
+
+			ret = kgsl_snapshot_get_object(device, ptbase,
+				vbo[i].base,
+				0, SNAPSHOT_GPU_OBJECT_GENERIC);
+			snapshot_frozen_objsize += ret;
+		}
+	}
+}
+
+/*
+ * Parse all the type3 opcode packets that may contain important information,
+ * such as additional GPU buffers to grab or a draw initator
+ */
+
+static void ib_parse_type3(struct kgsl_device *device, unsigned int *ptr,
+	unsigned int ptbase)
+{
+	switch (cp_type3_opcode(*ptr)) {
+	case CP_LOAD_STATE:
+		ib_parse_load_state(device, ptr, ptbase);
+		break;
+	case CP_SET_BIN_DATA:
+		ib_parse_set_bin_data(device, ptr, ptbase);
+		break;
+	case CP_MEM_WRITE:
+		ib_parse_mem_write(device, ptr, ptbase);
+		break;
+	case CP_DRAW_INDX:
+		ib_parse_draw_indx(device, ptr, ptbase);
+		break;
+	}
+}
+
+/*
+ * Parse type0 packets found in the stream.  Some of the registers that are
+ * written are clues for GPU buffers that we need to freeze.  Register writes
+ * are considred valid when a draw initator is called, so just cache the values
+ * here and freeze them when a CP_DRAW_INDX is seen.  This protects against
+ * needlessly caching buffers that won't be used during a draw call
+ */
+
+static void ib_parse_type0(struct kgsl_device *device, unsigned int *ptr,
+	unsigned int ptbase)
+{
+	int size = type0_pkt_size(*ptr);
+	int offset = type0_pkt_offset(*ptr);
+	int i;
+
+	for (i = 0; i < size; i++, offset++) {
+
+		/* Visiblity stream buffer */
+
+		if (offset >= A3XX_VSC_PIPE_DATA_ADDRESS_0 &&
+			offset <= A3XX_VSC_PIPE_DATA_LENGTH_7) {
+			int index = offset - A3XX_VSC_PIPE_DATA_ADDRESS_0;
+
+			/* Each bank of address and length registers are
+			 * interleaved with an empty register:
+			 *
+			 * address 0
+			 * length 0
+			 * empty
+			 * address 1
+			 * length 1
+			 * empty
+			 * ...
+			 */
+
+			if ((index % 3) == 0)
+				vsc_pipe[index / 3].base = ptr[i + 1];
+			else if ((index % 3) == 1)
+				vsc_pipe[index / 3].size = ptr[i + 1];
+		} else if ((offset >= A3XX_VFD_FETCH_INSTR_0_0) &&
+			(offset <= A3XX_VFD_FETCH_INSTR_1_F)) {
+			int index = offset - A3XX_VFD_FETCH_INSTR_0_0;
+
+			/*
+			 * FETCH_INSTR_0_X and FETCH_INSTR_1_X banks are
+			 * interleaved as above but without the empty register
+			 * in between
+			 */
+
+			if ((index % 2) == 0)
+				vbo[index >> 1].stride =
+					(ptr[i + 1] >> 7) & 0x1FF;
+			else
+				vbo[index >> 1].base = ptr[i + 1];
+		} else {
+			/*
+			 * Cache various support registers for calculating
+			 * buffer sizes
+			 */
+
+			switch (offset) {
+			case A3XX_VFD_CONTROL_0:
+				vfd_control_0 = ptr[i + 1];
+				break;
+			case A3XX_VFD_INDEX_MAX:
+				vfd_index_max = ptr[i + 1];
+				break;
+			case A3XX_VSC_SIZE_ADDRESS:
+				vsc_size_address = ptr[i + 1];
+				break;
+			case A3XX_SP_VS_PVT_MEM_ADDR_REG:
+				sp_vs_pvt_mem_addr = ptr[i + 1];
+				break;
+			case A3XX_SP_FS_PVT_MEM_ADDR_REG:
+				sp_fs_pvt_mem_addr = ptr[i + 1];
+				break;
+			}
+		}
+	}
+}
+
+/* Add an IB as a GPU object, but first, parse it to find more goodies within */
+
+static void ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase,
+		unsigned int gpuaddr, unsigned int dwords)
+{
+	int i = 0, ret;
+	unsigned int *src = (unsigned int *) adreno_convertaddr(device, ptbase,
+		gpuaddr, dwords << 2);
+
+	if (src == NULL)
+		return;
+
+	while (i < dwords) {
+
+		if (pkt_is_type3(src[i])) {
+			if ((dwords - i) < type3_pkt_size(src[i]) + 1)
+				goto skip;
+
+			if (adreno_cmd_is_ib(src[i]))
+				ib_add_gpu_object(device, ptbase,
+					src[i + 1], src[i + 2]);
+			else
+				ib_parse_type3(device, &src[i], ptbase);
+
+			i += type3_pkt_size(src[i]);
+		} else if (pkt_is_type0(src[i])) {
+			ib_parse_type0(device, &src[i], ptbase);
+			i += type0_pkt_size(src[i]);
+		}
+
+skip:
+		i++;
+	}
+
+	ret = kgsl_snapshot_get_object(device, ptbase, gpuaddr, dwords << 2,
+		SNAPSHOT_GPU_OBJECT_IB);
+
+	snapshot_frozen_objsize += ret;
+}
+
 /* Snapshot the istore memory */
 static int snapshot_istore(struct kgsl_device *device, void *snapshot,
 	int remain, void *priv)
@@ -110,12 +522,10 @@
 	unsigned int *data = snapshot + sizeof(*header);
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
-	unsigned int rbbase, ptbase, rptr, *rbptr;
-	int start, stop, index;
-	int numitems, size;
-
-	/* Get the GPU address of the ringbuffer */
-	kgsl_regread(device, REG_CP_RB_BASE, &rbbase);
+	unsigned int ptbase, rptr, *rbptr, ibbase;
+	int index, size, i;
+	int parse_ibs = 0, ib_parse_start;
+	int skip_pktsize = 1;
 
 	/* Get the physical address of the MMU pagetable */
 	ptbase = kgsl_mmu_get_current_ptbase(device);
@@ -123,27 +533,77 @@
 	/* Get the current read pointers for the RB */
 	kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
 
-	/* start the dump at the rptr minus some history */
-	start = (int) rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY;
-	if (start < 0)
-		start += rb->sizedwords;
+	/* Address of the last processed IB */
+	kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
 
 	/*
-	 * Stop the dump at the point where the software last wrote.  Don't use
-	 * the hardware value here on the chance that it didn't get properly
-	 * updated
+	 * Figure out the window of ringbuffer data to dump.  First we need to
+	 * find where the last processed IB ws submitted
 	 */
 
-	stop = (int) rb->wptr + 16;
-	if (stop > rb->sizedwords)
-		stop -= rb->sizedwords;
+	index = rptr;
+	rbptr = rb->buffer_desc.hostptr;
 
-	/* Set up the header for the section */
+	while (index != rb->wptr) {
+		index--;
 
-	numitems = (stop > start) ? stop - start :
-		(rb->sizedwords - start) + stop;
+		if (index < 0) {
+			index = rb->sizedwords - 3;
 
-	size = (numitems << 2);
+			/* We wrapped without finding what we wanted */
+			if (index < rb->wptr) {
+				index = rb->wptr;
+				break;
+			}
+		}
+
+		if (adreno_cmd_is_ib(rbptr[index]) &&
+			rbptr[index + 1] == ibbase)
+			break;
+	}
+
+	/*
+	 * index points at the last submitted IB. We can only trust that the
+	 * memory between the context switch and the hanging IB is valid, so
+	 * the next step is to find the context switch before the submission
+	 */
+
+	while (index != rb->wptr) {
+		index--;
+
+		if (index  < 0) {
+			index = rb->sizedwords - 2;
+
+			/*
+			 * Wrapped without finding the context switch. This is
+			 * harmless - we should still have enough data to dump a
+			 * valid state
+			 */
+
+			if (index < rb->wptr) {
+				index = rb->wptr;
+				break;
+			}
+		}
+
+		/* Break if the current packet is a context switch identifier */
+		if (adreno_rb_ctxtswitch(&rbptr[index]))
+			break;
+	}
+
+	/*
+	 * Index represents the start of the window of interest.  We will try
+	 * to dump all buffers between here and the rptr
+	 */
+
+	ib_parse_start = index;
+
+	/*
+	 * Dump the entire ringbuffer - the parser can choose how much of it to
+	 * process
+	 */
+
+	size = (rb->sizedwords << 2);
 
 	if (remain < size + sizeof(*header)) {
 		KGSL_DRV_ERR(device,
@@ -152,44 +612,64 @@
 	}
 
 	/* Write the sub-header for the section */
-	header->start = start;
-	header->end = stop;
+	header->start = rb->wptr;
+	header->end = rb->wptr;
 	header->wptr = rb->wptr;
 	header->rbsize = rb->sizedwords;
-	header->count = numitems;
-
-	index = start;
-	rbptr = rb->buffer_desc.hostptr;
+	header->count = rb->sizedwords;
 
 	/*
 	 * Loop through the RB, copying the data and looking for indirect
 	 * buffers and MMU pagetable changes
 	 */
 
-	while (index != rb->wptr) {
+	index = rb->wptr;
+	for (i = 0; i < rb->sizedwords; i++) {
 		*data = rbptr[index];
 
-		if (rbptr[index] == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2))
-			push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
-				rbptr[index + 1], rbptr[index + 2]);
-
 		/*
-		 * FIXME: Handle upcoming MMU pagetable changes, but only
-		 * between the rptr and the wptr
+		 * Sometimes the rptr is located in the middle of a packet.
+		 * try to adust for that by modifying the rptr to match a
+		 * packet boundary. Unfortunately for us, it is hard to tell
+		 * which dwords are legitimate type0 header and which are just
+		 * random data so just walk over type0 packets until we get
+		 * to the first type3, and from that point on start checking the
+		 * size of the packet and adjusting accordingly
 		 */
 
-		index = index + 1;
+		if (skip_pktsize && pkt_is_type3(rbptr[index]))
+			skip_pktsize = 0;
 
-		if (index == rb->sizedwords)
-			index = 0;
+		if (skip_pktsize == 0) {
+			unsigned int pktsize = type3_pkt_size(rbptr[index]);
+			if (index +  pktsize > rptr)
+				rptr = (index + pktsize) % rb->sizedwords;
+		}
 
-		data++;
-	}
+		/*
+		 * Only parse IBs between the start and the rptr or the next
+		 * context switch, whichever comes first
+		 */
 
-	/* Dump 16 dwords past the wptr, but don't  bother interpeting it */
+		if (index == ib_parse_start)
+			parse_ibs = 1;
+		else if (index == rptr || adreno_rb_ctxtswitch(&rbptr[index]))
+			parse_ibs = 0;
 
-	while (index != stop) {
-		*data = rbptr[index];
+		if (parse_ibs && adreno_cmd_is_ib(rbptr[index])) {
+			/*
+			 * The IB from CP_IB1_BASE goes into the snapshot, all
+			 * others get marked at GPU objects
+			 */
+			if (rbptr[index + 1] == ibbase)
+				push_object(device, SNAPSHOT_OBJ_TYPE_IB,
+					ptbase, rbptr[index + 1],
+					rbptr[index + 2]);
+			else
+				ib_add_gpu_object(device, ptbase,
+					rbptr[index + 1], rbptr[index + 2]);
+		}
+
 		index = index + 1;
 
 		if (index == rb->sizedwords)
@@ -224,17 +704,19 @@
 	header->size = obj->dwords;
 
 	/* Write the contents of the ib */
-	for (i = 0; i < obj->dwords; i++) {
+	for (i = 0; i < obj->dwords; i++, src++, dst++) {
 		*dst = *src;
-		/* If another IB is discovered, then push it on the list too */
 
-		if (*src == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
-			push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
-				*(src + 1), *(src + 2));
+		if (pkt_is_type3(*src)) {
+			if ((obj->dwords - i) < type3_pkt_size(*src) + 1)
+				continue;
+
+			if (adreno_cmd_is_ib(*src))
+				push_object(device, SNAPSHOT_OBJ_TYPE_IB,
+					obj->ptbase, src[1], src[2]);
+			else
+				ib_parse_type3(device, src, obj->ptbase);
 		}
-
-		src++;
-		dst++;
 	}
 
 	return (obj->dwords << 2) + sizeof(*header);
@@ -280,6 +762,17 @@
 	/* Reset the list of objects */
 	objbufptr = 0;
 
+	snapshot_frozen_objsize = 0;
+
+	/* Clear the caches for the visibilty stream and VBO parsing */
+
+	vfd_control_0 = 0;
+	vfd_index_max = 0;
+	vsc_size_address = 0;
+
+	memset(vsc_pipe, 0, sizeof(vsc_pipe));
+	memset(vbo, 0, sizeof(vbo));
+
 	/* Get the physical address of the MMU pagetable */
 	ptbase = kgsl_mmu_get_current_ptbase(device);
 
@@ -288,22 +781,45 @@
 		snapshot, remain, snapshot_rb, NULL);
 
 	/*
-	 * Make sure that the IBs described in the CP registers are on the
-	 * list of objects
+	 * Make sure that the last IB1 that was being executed is dumped.
+	 * Since this was the last IB1 that was processed, we should have
+	 * already added it to the list during the ringbuffer parse but we
+	 * want to be double plus sure.
 	 */
+
 	kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
 	kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);
 
-	if (ibsize)
+	/*
+	 * The problem is that IB size from the register is the unprocessed size
+	 * of the buffer not the original size, so if we didn't catch this
+	 * buffer being directly used in the RB, then we might not be able to
+	 * dump the whle thing. Print a warning message so we can try to
+	 * figure how often this really happens.
+	 */
+
+	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
 		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
 			ibbase, ibsize);
+		KGSL_DRV_ERR(device, "CP_IB1_BASE not found in the ringbuffer. "
+			"Dumping %x dwords of the buffer.\n", ibsize);
+	}
 
 	kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
 	kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);
 
-	if (ibsize)
+	/*
+	 * Add the last parsed IB2 to the list. The IB2 should be found as we
+	 * parse the objects below, but we try to add it to the list first, so
+	 * it too can be parsed.  Don't print an error message in this case - if
+	 * the IB2 is found during parsing, the list will be updated with the
+	 * correct size.
+	 */
+
+	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
 		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
 			ibbase, ibsize);
+	}
 
 	/*
 	 * Go through the list of found objects and dump each one.  As the IBs
@@ -328,5 +844,9 @@
 		snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot,
 			remain, hang);
 
+	if (snapshot_frozen_objsize)
+		KGSL_DRV_ERR(device, "GPU snapshot froze %dKb of GPU buffers\n",
+			snapshot_frozen_objsize / 1024);
+
 	return snapshot;
 }
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 120b129..45bcf69 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -21,11 +21,10 @@
 #include <linux/vmalloc.h>
 #include <linux/pm_runtime.h>
 #include <linux/genlock.h>
-
+#include <linux/rbtree.h>
 #include <linux/ashmem.h>
 #include <linux/major.h>
 #include <linux/ion.h>
-#include <mach/socinfo.h>
 
 #include "kgsl.h"
 #include "kgsl_debugfs.h"
@@ -137,6 +136,39 @@
 	}
 }
 
+/* kgsl_get_mem_entry - get the mem_entry structure for the specified object
+ * @ptbase - the pagetable base of the object
+ * @gpuaddr - the GPU address of the object
+ * @size - Size of the region to search
+ */
+
+struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
+	unsigned int gpuaddr, unsigned int size)
+{
+	struct kgsl_process_private *priv;
+	struct kgsl_mem_entry *entry;
+
+	mutex_lock(&kgsl_driver.process_mutex);
+
+	list_for_each_entry(priv, &kgsl_driver.process_list, list) {
+		if (!kgsl_mmu_pt_equal(priv->pagetable, ptbase))
+			continue;
+		spin_lock(&priv->mem_lock);
+		entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
+
+		if (entry) {
+			spin_unlock(&priv->mem_lock);
+			mutex_unlock(&kgsl_driver.process_mutex);
+			return entry;
+		}
+		spin_unlock(&priv->mem_lock);
+	}
+	mutex_unlock(&kgsl_driver.process_mutex);
+
+	return NULL;
+}
+EXPORT_SYMBOL(kgsl_get_mem_entry);
+
 static inline struct kgsl_mem_entry *
 kgsl_mem_entry_create(void)
 {
@@ -157,8 +189,6 @@
 						    struct kgsl_mem_entry,
 						    refcount);
 
-	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
-
 	if (entry->memtype != KGSL_MEM_ENTRY_KERNEL)
 		kgsl_driver.stats.mapped -= entry->memdesc.size;
 
@@ -194,13 +224,48 @@
 void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
 				   struct kgsl_process_private *process)
 {
+	struct rb_node **node;
+	struct rb_node *parent = NULL;
+
 	spin_lock(&process->mem_lock);
-	list_add(&entry->list, &process->mem_list);
+
+	node = &process->mem_rb.rb_node;
+
+	while (*node) {
+		struct kgsl_mem_entry *cur;
+
+		parent = *node;
+		cur = rb_entry(parent, struct kgsl_mem_entry, node);
+
+		if (entry->memdesc.gpuaddr < cur->memdesc.gpuaddr)
+			node = &parent->rb_left;
+		else
+			node = &parent->rb_right;
+	}
+
+	rb_link_node(&entry->node, parent, node);
+	rb_insert_color(&entry->node, &process->mem_rb);
+
 	spin_unlock(&process->mem_lock);
 
 	entry->priv = process;
 }
 
+/* Detach a memory entry from a process and unmap it from the MMU */
+
+static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
+{
+	if (entry == NULL)
+		return;
+
+	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
+	entry->priv = NULL;
+
+	kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
+
+	kgsl_mem_entry_put(entry);
+}
+
 /* Allocate a new context id */
 
 static struct kgsl_context *
@@ -391,6 +456,8 @@
 		wait_for_completion(&device->suspend_gate);
 		mutex_lock(&device->mutex);
 	}
+	/* Don't let the timer wake us during suspended sleep. */
+	del_timer_sync(&device->idle_timer);
 	switch (device->state) {
 		case KGSL_STATE_INIT:
 			break;
@@ -402,7 +469,6 @@
 			/* Get the completion ready to be waited upon. */
 			INIT_COMPLETION(device->hwaccess_gate);
 			device->ftbl->suspend_context(device);
-			kgsl_pwrctrl_stop_work(device);
 			device->ftbl->stop(device);
 			kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
 			break;
@@ -485,7 +551,6 @@
 					struct kgsl_device, display_off);
 	KGSL_PWR_WARN(device, "early suspend start\n");
 	mutex_lock(&device->mutex);
-	kgsl_pwrctrl_stop_work(device);
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
 	kgsl_pwrctrl_sleep(device);
 	mutex_unlock(&device->mutex);
@@ -514,8 +579,8 @@
 					struct kgsl_device, display_off);
 	KGSL_PWR_WARN(device, "late resume start\n");
 	mutex_lock(&device->mutex);
-	kgsl_pwrctrl_wake(device);
 	device->pwrctrl.restore_slumber = 0;
+	kgsl_pwrctrl_wake(device);
 	kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
 	mutex_unlock(&device->mutex);
 	kgsl_check_idle(device);
@@ -548,8 +613,7 @@
 	spin_lock_init(&private->mem_lock);
 	private->refcnt = 1;
 	private->pid = task_tgid_nr(current);
-
-	INIT_LIST_HEAD(&private->mem_list);
+	private->mem_rb = RB_ROOT;
 
 	if (kgsl_mmu_enabled())
 	{
@@ -578,7 +642,7 @@
 			 struct kgsl_process_private *private)
 {
 	struct kgsl_mem_entry *entry = NULL;
-	struct kgsl_mem_entry *entry_tmp = NULL;
+	struct rb_node *node;
 
 	if (!private)
 		return;
@@ -592,11 +656,13 @@
 
 	list_del(&private->list);
 
-	list_for_each_entry_safe(entry, entry_tmp, &private->mem_list, list) {
-		list_del(&entry->list);
-		kgsl_mem_entry_put(entry);
-	}
+	for (node = rb_first(&private->mem_rb); node; ) {
+		entry = rb_entry(node, struct kgsl_mem_entry, node);
+		node = rb_next(&entry->node);
 
+		rb_erase(&entry->node, &private->mem_rb);
+		kgsl_mem_entry_detach_process(entry);
+	}
 	kgsl_mmu_putpagetable(private->pagetable);
 	kfree(private);
 unlock:
@@ -632,7 +698,6 @@
 
 	device->open_count--;
 	if (device->open_count == 0) {
-		kgsl_pwrctrl_stop_work(device);
 		result = device->ftbl->stop(device);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 	}
@@ -723,47 +788,43 @@
 	return result;
 }
 
-
-/*call with private->mem_lock locked */
-static struct kgsl_mem_entry *
-kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
-{
-	struct kgsl_mem_entry *entry = NULL, *result = NULL;
-
-	BUG_ON(private == NULL);
-
-	gpuaddr &= PAGE_MASK;
-
-	list_for_each_entry(entry, &private->mem_list, list) {
-		if (entry->memdesc.gpuaddr == gpuaddr) {
-			result = entry;
-			break;
-		}
-	}
-	return result;
-}
-
 /*call with private->mem_lock locked */
 struct kgsl_mem_entry *
 kgsl_sharedmem_find_region(struct kgsl_process_private *private,
-				unsigned int gpuaddr,
-				size_t size)
+	unsigned int gpuaddr, size_t size)
 {
-	struct kgsl_mem_entry *entry = NULL, *result = NULL;
+	struct rb_node *node = private->mem_rb.rb_node;
 
-	BUG_ON(private == NULL);
+	while (node != NULL) {
+		struct kgsl_mem_entry *entry;
 
-	list_for_each_entry(entry, &private->mem_list, list) {
-		if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
-			result = entry;
-			break;
+		entry = rb_entry(node, struct kgsl_mem_entry, node);
+
+
+		if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
+			return entry;
+
+		if (gpuaddr < entry->memdesc.gpuaddr)
+			node = node->rb_left;
+		else if (gpuaddr >=
+			(entry->memdesc.gpuaddr + entry->memdesc.size))
+			node = node->rb_right;
+		else {
+			return NULL;
 		}
 	}
 
-	return result;
+	return NULL;
 }
 EXPORT_SYMBOL(kgsl_sharedmem_find_region);
 
+/*call with private->mem_lock locked */
+static inline struct kgsl_mem_entry *
+kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
+{
+	return kgsl_sharedmem_find_region(private, gpuaddr, 1);
+}
+
 /*call all ioctl sub functions with driver locked*/
 static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
 					  unsigned int cmd, void *data)
@@ -790,6 +851,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,
@@ -800,6 +895,21 @@
 	return result;
 }
 
+static long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv,
+					  unsigned int cmd, void *data)
+{
+	int result = 0;
+	/* The getproperty struct is reused for setproperty too */
+	struct kgsl_device_getproperty *param = data;
+
+	if (dev_priv->device->ftbl->setproperty)
+		result = dev_priv->device->ftbl->setproperty(
+			dev_priv->device, param->type,
+			param->value, param->sizebytes);
+
+	return result;
+}
+
 static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
 						*dev_priv, unsigned int cmd,
 						void *data)
@@ -828,40 +938,6 @@
 
 	return result;
 }
-static bool check_ibdesc(struct kgsl_device_private *dev_priv,
-			 struct kgsl_ibdesc *ibdesc, unsigned int numibs,
-			 bool parse)
-{
-	bool result = true;
-	unsigned int i;
-	for (i = 0; i < numibs; i++) {
-		struct kgsl_mem_entry *entry;
-		spin_lock(&dev_priv->process_priv->mem_lock);
-		entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
-			ibdesc[i].gpuaddr, ibdesc[i].sizedwords * sizeof(uint));
-		spin_unlock(&dev_priv->process_priv->mem_lock);
-		if (entry == NULL) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"invalid cmd buffer gpuaddr %08x " \
-				"sizedwords %d\n", ibdesc[i].gpuaddr,
-				ibdesc[i].sizedwords);
-			result = false;
-			break;
-		}
-
-		if (parse && !kgsl_cffdump_parse_ibs(dev_priv, &entry->memdesc,
-			ibdesc[i].gpuaddr, ibdesc[i].sizedwords, true)) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"invalid cmd buffer gpuaddr %08x " \
-				"sizedwords %d numibs %d/%d\n",
-				ibdesc[i].gpuaddr,
-				ibdesc[i].sizedwords, i+1, numibs);
-			result = false;
-			break;
-		}
-	}
-	return result;
-}
 
 static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
 				      unsigned int cmd, void *data)
@@ -871,10 +947,6 @@
 	struct kgsl_ibdesc *ibdesc;
 	struct kgsl_context *context;
 
-#ifdef CONFIG_MSM_KGSL_DRM
-	kgsl_gpu_mem_flush(DRM_KGSL_GEM_CACHE_OP_TO_DEV);
-#endif
-
 	context = kgsl_find_context(dev_priv, param->drawctxt_id);
 	if (context == NULL) {
 		result = -EINVAL;
@@ -931,12 +1003,6 @@
 		param->numibs = 1;
 	}
 
-	if (!check_ibdesc(dev_priv, ibdesc, param->numibs, true)) {
-		KGSL_DRV_ERR(dev_priv->device, "bad ibdesc");
-		result = -EINVAL;
-		goto free_ibdesc;
-	}
-
 	result = dev_priv->device->ftbl->issueibcmds(dev_priv,
 					     context,
 					     ibdesc,
@@ -946,26 +1012,10 @@
 
 	trace_kgsl_issueibcmds(dev_priv->device, param, result);
 
-	if (result != 0)
-		goto free_ibdesc;
-
-	/* this is a check to try to detect if a command buffer was freed
-	 * during issueibcmds().
-	 */
-	if (!check_ibdesc(dev_priv, ibdesc, param->numibs, false)) {
-		KGSL_DRV_ERR(dev_priv->device, "bad ibdesc AFTER issue");
-		result = -EINVAL;
-		goto free_ibdesc;
-	}
-
 free_ibdesc:
 	kfree(ibdesc);
 done:
 
-#ifdef CONFIG_MSM_KGSL_DRM
-	kgsl_gpu_mem_flush(DRM_KGSL_GEM_CACHE_OP_FROM_DEV);
-#endif
-
 	return result;
 }
 
@@ -989,9 +1039,10 @@
 {
 	struct kgsl_mem_entry *entry = priv;
 	spin_lock(&entry->priv->mem_lock);
-	list_del(&entry->list);
+	rb_erase(&entry->node, &entry->priv->mem_rb);
 	spin_unlock(&entry->priv->mem_lock);
-	kgsl_mem_entry_put(entry);
+	trace_kgsl_mem_timestamp_free(entry, timestamp);
+	kgsl_mem_entry_detach_process(entry);
 }
 
 static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private
@@ -1001,12 +1052,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 {
@@ -1081,11 +1138,13 @@
 	spin_lock(&private->mem_lock);
 	entry = kgsl_sharedmem_find(private, param->gpuaddr);
 	if (entry)
-		list_del(&entry->list);
+		rb_erase(&entry->node, &private->mem_rb);
+
 	spin_unlock(&private->mem_lock);
 
 	if (entry) {
-		kgsl_mem_entry_put(entry);
+		trace_kgsl_mem_free(entry);
+		kgsl_mem_entry_detach_process(entry);
 	} else {
 		KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
 		result = -EINVAL;
@@ -1117,6 +1176,8 @@
 	struct kgsl_mem_entry *entry = NULL;
 	struct vm_area_struct *vma;
 
+	KGSL_DEV_ERR_ONCE(dev_priv->device, "IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC"
+			" is deprecated\n");
 	if (!kgsl_mmu_enabled())
 		return -ENODEV;
 
@@ -1173,9 +1234,9 @@
 
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
-	result = remap_vmalloc_range(vma, (void *) entry->memdesc.hostptr, 0);
+	result = kgsl_sharedmem_map_vma(vma, &entry->memdesc);
 	if (result) {
-		KGSL_CORE_ERR("remap_vmalloc_range failed: %d\n", result);
+		KGSL_CORE_ERR("kgsl_sharedmem_map_vma failed: %d\n", result);
 		goto error_free_vmalloc;
 	}
 
@@ -1185,6 +1246,7 @@
 
 	kgsl_mem_entry_attach_process(entry, private);
 
+	trace_kgsl_mem_alloc(entry);
 	/* Process specific statistics */
 	kgsl_process_add_stats(private, entry->memtype, len);
 
@@ -1314,7 +1376,8 @@
 	int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
 	unsigned long paddr = (unsigned long) addr;
 
-	memdesc->sg = vmalloc(sglen * sizeof(struct scatterlist));
+	memdesc->sg = kgsl_sg_alloc(sglen);
+
 	if (memdesc->sg == NULL)
 		return -ENOMEM;
 
@@ -1354,7 +1417,7 @@
 
 err:
 	spin_unlock(&current->mm->page_table_lock);
-	vfree(memdesc->sg);
+	kgsl_sg_free(memdesc->sg,  sglen);
 	memdesc->sg = NULL;
 
 	return -EINVAL;
@@ -1558,6 +1621,8 @@
 		break;
 
 	case KGSL_USER_MEM_TYPE_ADDR:
+		KGSL_DEV_ERR_ONCE(dev_priv->device, "User mem type "
+				"KGSL_USER_MEM_TYPE_ADDR is deprecated\n");
 		if (!kgsl_mmu_enabled()) {
 			KGSL_DRV_ERR(dev_priv->device,
 				"Cannot map paged memory with the "
@@ -1619,6 +1684,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;
@@ -1685,6 +1751,7 @@
 		param->gpuaddr = entry->memdesc.gpuaddr;
 
 		kgsl_process_add_stats(private, entry->memtype, param->size);
+		trace_kgsl_mem_alloc(entry);
 	} else
 		kfree(entry);
 
@@ -1878,6 +1945,8 @@
 			kgsl_ioctl_cff_user_event, 0),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
 			kgsl_ioctl_timestamp_event, 1),
+	KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
+			kgsl_ioctl_device_setproperty, 1),
 };
 
 static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -1931,7 +2000,7 @@
 		if (!func) {
 			KGSL_DRV_INFO(dev_priv->device,
 				      "invalid ioctl code %08x\n", cmd);
-			ret = -EINVAL;
+			ret = -ENOIOCTLCMD;
 			goto done;
 		}
 		lock = 1;
@@ -2030,7 +2099,7 @@
 	unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
 	struct kgsl_device_private *dev_priv = file->private_data;
 	struct kgsl_process_private *private = dev_priv->process_priv;
-	struct kgsl_mem_entry *tmp, *entry = NULL;
+	struct kgsl_mem_entry *entry = NULL;
 	struct kgsl_device *device = dev_priv->device;
 
 	/* Handle leagacy behavior for memstore */
@@ -2041,13 +2110,11 @@
 	/* Find a chunk of GPU memory */
 
 	spin_lock(&private->mem_lock);
-	list_for_each_entry(tmp, &private->mem_list, list) {
-		if (vma_offset == tmp->memdesc.gpuaddr) {
-			kgsl_mem_entry_get(tmp);
-			entry = tmp;
-			break;
-		}
-	}
+	entry = kgsl_sharedmem_find(private, vma_offset);
+
+	if (entry)
+		kgsl_mem_entry_get(entry);
+
 	spin_unlock(&private->mem_lock);
 
 	if (entry == NULL)
@@ -2103,8 +2170,8 @@
 	kgsl_cffdump_close(device->id);
 	kgsl_pwrctrl_uninit_sysfs(device);
 
-	if (cpu_is_msm8x60())
-		wake_lock_destroy(&device->idle_wakelock);
+	wake_lock_destroy(&device->idle_wakelock);
+	pm_qos_remove_request(&device->pm_qos_req_dma);
 
 	idr_destroy(&device->context_idr);
 
@@ -2195,9 +2262,9 @@
 	if (ret != 0)
 		goto err_close_mmu;
 
-	if (cpu_is_msm8x60())
-		wake_lock_init(&device->idle_wakelock,
-					   WAKE_LOCK_IDLE, device->name);
+	wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
+	pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
 
 	idr_init(&device->context_idr);
 
@@ -2335,8 +2402,8 @@
 static int __devinit
 kgsl_ptdata_init(void)
 {
-	kgsl_driver.ptpool = kgsl_mmu_ptpool_init(KGSL_PAGETABLE_SIZE,
-						kgsl_pagetable_count);
+	kgsl_driver.ptpool = kgsl_mmu_ptpool_init(kgsl_pagetable_count);
+
 	if (!kgsl_driver.ptpool)
 		return -ENOMEM;
 	return 0;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 1135adb..87bba25 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.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
@@ -21,6 +21,7 @@
 #include <linux/mutex.h>
 #include <linux/cdev.h>
 #include <linux/regulator/consumer.h>
+#include <linux/mm.h>
 
 #define KGSL_NAME "kgsl"
 
@@ -40,10 +41,6 @@
 #define KGSL_PAGETABLE_ENTRIES(_sz) (((_sz) >> PAGE_SHIFT) + \
 				     KGSL_PT_EXTRA_ENTRIES)
 
-#define KGSL_PAGETABLE_SIZE \
-ALIGN(KGSL_PAGETABLE_ENTRIES(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE) * \
-KGSL_PAGETABLE_ENTRY_SIZE, PAGE_SIZE)
-
 #ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
 #define KGSL_PAGETABLE_COUNT (CONFIG_MSM_KGSL_PAGE_TABLE_COUNT)
 #else
@@ -102,7 +99,15 @@
 extern struct kgsl_driver kgsl_driver;
 
 struct kgsl_pagetable;
-struct kgsl_memdesc_ops;
+struct kgsl_memdesc;
+
+struct kgsl_memdesc_ops {
+	int (*vmflags)(struct kgsl_memdesc *);
+	int (*vmfault)(struct kgsl_memdesc *, struct vm_area_struct *,
+		       struct vm_fault *);
+	void (*free)(struct kgsl_memdesc *memdesc);
+	int (*map_kernel_mem)(struct kgsl_memdesc *);
+};
 
 /* shared memory allocation */
 struct kgsl_memdesc {
@@ -126,12 +131,17 @@
 #define KGSL_MEM_ENTRY_ION    4
 #define KGSL_MEM_ENTRY_MAX    5
 
+/* List of flags */
+
+#define KGSL_MEM_ENTRY_FROZEN (1 << 0)
+
 struct kgsl_mem_entry {
 	struct kref refcount;
 	struct kgsl_memdesc memdesc;
 	int memtype;
+	int flags;
 	void *priv_data;
-	struct list_head list;
+	struct rb_node node;
 	uint32_t free_timestamp;
 	/* back pointer to private structure under whose context this
 	* allocation is made */
@@ -145,6 +155,10 @@
 #endif
 
 void kgsl_mem_entry_destroy(struct kref *kref);
+
+struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
+		unsigned int gpuaddr, unsigned int size);
+
 struct kgsl_mem_entry *kgsl_sharedmem_find_region(
 	struct kgsl_process_private *private, unsigned int gpuaddr,
 	size_t size);
@@ -160,7 +174,6 @@
 #ifdef CONFIG_MSM_KGSL_DRM
 extern int kgsl_drm_init(struct platform_device *dev);
 extern void kgsl_drm_exit(void);
-extern void kgsl_gpu_mem_flush(int op);
 #else
 static inline int kgsl_drm_init(struct platform_device *dev)
 {
@@ -181,13 +194,15 @@
 	}
 	return 0;
 }
-static inline uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
+static inline uint8_t *kgsl_gpuaddr_to_vaddr(struct kgsl_memdesc *memdesc,
 					     unsigned int gpuaddr)
 {
-	if (memdesc->hostptr == NULL || memdesc->gpuaddr == 0 ||
-		(gpuaddr < memdesc->gpuaddr ||
-		gpuaddr >= memdesc->gpuaddr + memdesc->size))
-		return NULL;
+	if (memdesc->gpuaddr == 0 ||
+		gpuaddr < memdesc->gpuaddr ||
+		gpuaddr >= (memdesc->gpuaddr + memdesc->size) ||
+		(NULL == memdesc->hostptr && memdesc->ops->map_kernel_mem &&
+			memdesc->ops->map_kernel_mem(memdesc)))
+			return NULL;
 
 	return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
 }
@@ -199,7 +214,7 @@
 	if (ts_diff == 0)
 		return 0;
 
-	return ((ts_diff > 0) || (ts_diff < -20000)) ? 1 : -1;
+	return ((ts_diff > 0) || (ts_diff < -25000)) ? 1 : -1;
 }
 
 static inline void
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index e9455cb..4e354d0 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.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
@@ -359,7 +359,7 @@
 void kgsl_cffdump_open(enum kgsl_deviceid device_id)
 {
 	kgsl_cffdump_memory_base(device_id, KGSL_PAGETABLE_BASE,
-			CONFIG_MSM_KGSL_PAGE_TABLE_SIZE, SZ_256K);
+			kgsl_mmu_get_ptsize(), SZ_256K);
 }
 
 void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
@@ -497,190 +497,6 @@
 }
 EXPORT_SYMBOL(kgsl_cffdump_waitirq);
 
-#define ADDRESS_STACK_SIZE 256
-#define GET_PM4_TYPE3_OPCODE(x) ((*(x) >> 8) & 0xFF)
-static unsigned int kgsl_cffdump_addr_count;
-
-static bool kgsl_cffdump_handle_type3(struct kgsl_device_private *dev_priv,
-	uint *hostaddr, bool check_only)
-{
-	static uint addr_stack[ADDRESS_STACK_SIZE];
-	static uint size_stack[ADDRESS_STACK_SIZE];
-
-	switch (GET_PM4_TYPE3_OPCODE(hostaddr)) {
-	case CP_INDIRECT_BUFFER_PFD:
-	case CP_INDIRECT_BUFFER:
-	{
-		/* traverse indirect buffers */
-		int i;
-		uint ibaddr = hostaddr[1];
-		uint ibsize = hostaddr[2];
-
-		/* is this address already in encountered? */
-		for (i = 0;
-			i < kgsl_cffdump_addr_count && addr_stack[i] != ibaddr;
-			++i)
-			;
-
-		if (kgsl_cffdump_addr_count == i) {
-			addr_stack[kgsl_cffdump_addr_count] = ibaddr;
-			size_stack[kgsl_cffdump_addr_count++] = ibsize;
-
-			if (kgsl_cffdump_addr_count >= ADDRESS_STACK_SIZE) {
-				KGSL_CORE_ERR("stack overflow\n");
-				return false;
-			}
-
-			return kgsl_cffdump_parse_ibs(dev_priv, NULL,
-				ibaddr, ibsize, check_only);
-		} else if (size_stack[i] != ibsize) {
-			KGSL_CORE_ERR("gpuaddr: 0x%08x, "
-				"wc: %u, with size wc: %u already on the "
-				"stack\n", ibaddr, ibsize, size_stack[i]);
-			return false;
-		}
-	}
-	break;
-	}
-
-	return true;
-}
-
-/*
- * Traverse IBs and dump them to test vector. Detect swap by inspecting
- * register writes, keeping note of the current state, and dump
- * framebuffer config to test vector
- */
-bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv,
-	const struct kgsl_memdesc *memdesc, uint gpuaddr, int sizedwords,
-	bool check_only)
-{
-	static uint level; /* recursion level */
-	bool ret = true;
-	uint *hostaddr, *hoststart;
-	int dwords_left = sizedwords; /* dwords left in the current command
-					 buffer */
-
-	if (level == 0)
-		kgsl_cffdump_addr_count = 0;
-
-	if (memdesc == NULL) {
-		struct kgsl_mem_entry *entry;
-		spin_lock(&dev_priv->process_priv->mem_lock);
-		entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
-			gpuaddr, sizedwords * sizeof(uint));
-		spin_unlock(&dev_priv->process_priv->mem_lock);
-		if (entry == NULL) {
-			KGSL_CORE_ERR("did not find mapping "
-				"for gpuaddr: 0x%08x\n", gpuaddr);
-			return true;
-		}
-		memdesc = &entry->memdesc;
-	}
-	hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
-	if (hostaddr == NULL) {
-		KGSL_CORE_ERR("no kernel mapping for "
-			"gpuaddr: 0x%08x\n", gpuaddr);
-		return true;
-	}
-
-	hoststart = hostaddr;
-
-	level++;
-
-	mb();
-	kgsl_cache_range_op((struct kgsl_memdesc *)memdesc,
-				KGSL_CACHE_OP_INV);
-#ifdef DEBUG
-	pr_info("kgsl: cffdump: ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
-		gpuaddr, sizedwords, hostaddr);
-#endif
-
-	while (dwords_left > 0) {
-		int count = 0; /* dword count including packet header */
-		bool cur_ret = true;
-
-		switch (*hostaddr >> 30) {
-		case 0x0: /* type-0 */
-			count = (*hostaddr >> 16)+2;
-			break;
-		case 0x1: /* type-1 */
-			count = 2;
-			break;
-		case 0x3: /* type-3 */
-			count = ((*hostaddr >> 16) & 0x3fff) + 2;
-			cur_ret = kgsl_cffdump_handle_type3(dev_priv,
-				hostaddr, check_only);
-			break;
-		default:
-			pr_warn("kgsl: cffdump: parse-ib: unexpected type: "
-				"type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
-				*hostaddr >> 30, *hostaddr, hostaddr,
-				gpuaddr+4*(sizedwords-dwords_left));
-			cur_ret = false;
-			count = dwords_left;
-			break;
-		}
-
-#ifdef DEBUG
-		if (!cur_ret) {
-			pr_info("kgsl: cffdump: bad sub-type: #:%d/%d, v:0x%08x"
-				" @ 0x%p[gb:0x%08x], level:%d\n",
-				sizedwords-dwords_left, sizedwords, *hostaddr,
-				hostaddr, gpuaddr+4*(sizedwords-dwords_left),
-				level);
-
-			print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
-				DUMP_PREFIX_OFFSET, 32, 4, hoststart,
-				sizedwords*4, 0);
-		}
-#endif
-		ret = ret && cur_ret;
-
-		/* jump to next packet */
-		dwords_left -= count;
-		hostaddr += count;
-		cur_ret = dwords_left >= 0;
-
-#ifdef DEBUG
-		if (!cur_ret) {
-			pr_info("kgsl: cffdump: bad count: c:%d, #:%d/%d, "
-				"v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
-				count, sizedwords-(dwords_left+count),
-				sizedwords, *(hostaddr-count), hostaddr-count,
-				gpuaddr+4*(sizedwords-(dwords_left+count)),
-				level);
-
-			print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
-				DUMP_PREFIX_OFFSET, 32, 4, hoststart,
-				sizedwords*4, 0);
-		}
-#endif
-
-		ret = ret && cur_ret;
-	}
-
-	if (!ret)
-		pr_info("kgsl: cffdump: parsing failed: gpuaddr:0x%08x, "
-			"host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
-
-	if (!check_only) {
-#ifdef DEBUG
-		uint offset = gpuaddr - memdesc->gpuaddr;
-		pr_info("kgsl: cffdump: ib-dump: hostptr:%p, gpuaddr:%08x, "
-			"physaddr:%08x, offset:%d, size:%d", hoststart,
-			gpuaddr, memdesc->physaddr + offset, offset,
-			sizedwords*4);
-#endif
-		kgsl_cffdump_syncmem(dev_priv, memdesc, gpuaddr, sizedwords*4,
-			false);
-	}
-
-	level--;
-
-	return ret;
-}
-
 static int subbuf_start_handler(struct rchan_buf *buf,
 	void *subbuf, void *prev_subbuf, uint prev_padding)
 {
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2fb1e43..feaf652 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -15,6 +15,7 @@
 
 #include <linux/idr.h>
 #include <linux/wakelock.h>
+#include <linux/pm_qos_params.h>
 #include <linux/earlysuspend.h>
 
 #include "kgsl.h"
@@ -103,6 +104,9 @@
 		struct kgsl_context *context);
 	long (*ioctl) (struct kgsl_device_private *dev_priv,
 		unsigned int cmd, void *data);
+	int (*setproperty) (struct kgsl_device *device,
+		enum kgsl_property_type type, void *value,
+		unsigned int sizebytes);
 };
 
 struct kgsl_memregion {
@@ -175,6 +179,12 @@
 				   losing the output on multiple hangs  */
 	struct kobject snapshot_kobj;
 
+	/*
+	 * List of GPU buffers that have been frozen in memory until they can be
+	 * dumped
+	 */
+	struct list_head snapshot_obj_list;
+
 	/* Logging levels */
 	int cmd_log;
 	int ctxt_log;
@@ -184,6 +194,7 @@
 	struct wake_lock idle_wakelock;
 	struct kgsl_pwrscale pwrscale;
 	struct kobject pwrscale_kobj;
+	struct pm_qos_request_list pm_qos_req_dma;
 	struct work_struct ts_expired_ws;
 	struct list_head events;
 	s64 on_time;
@@ -197,13 +208,18 @@
 
 	/* 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 {
 	unsigned int refcnt;
 	pid_t pid;
 	spinlock_t mem_lock;
-	struct list_head mem_list;
+	struct rb_root mem_rb;
 	struct kgsl_pagetable *pagetable;
 	struct list_head list;
 	struct kobject kobj;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index e3f6f3b..d43b29b 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -156,22 +156,6 @@
 	kgsl_cache_range_op(memdesc, cacheop);
 }
 
-/* Flush all the memory mapped in the MMU */
-
-void kgsl_gpu_mem_flush(int op)
-{
-	struct drm_kgsl_gem_object *entry;
-
-	list_for_each_entry(entry, &kgsl_mem_list, list) {
-		kgsl_gem_mem_flush(&entry->memdesc, entry->type, op);
-	}
-
-	/* Takes care of WT/WC case.
-	 * More useful when we go barrierless
-	 */
-	dmb();
-}
-
 /* TODO:
  * Add vsync wait */
 
@@ -919,17 +903,18 @@
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct drm_device *dev = obj->dev;
 	struct drm_kgsl_gem_object *priv;
-	unsigned long offset, pg;
+	unsigned long offset;
 	struct page *page;
+	int i;
 
 	mutex_lock(&dev->struct_mutex);
 
 	priv = obj->driver_private;
 
 	offset = (unsigned long) vmf->virtual_address - vma->vm_start;
-	pg = (unsigned long) priv->memdesc.hostptr + offset;
+	i = offset >> PAGE_SHIFT;
+	page = sg_page(&(priv->memdesc.sg[i]));
 
-	page = vmalloc_to_page((void *) pg);
 	if (!page) {
 		mutex_unlock(&dev->struct_mutex);
 		return VM_FAULT_SIGBUS;
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index a16b954..bbb5d46 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.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
@@ -22,6 +22,10 @@
 #include "kgsl_device.h"
 #include "kgsl_sharedmem.h"
 
+#define KGSL_PAGETABLE_SIZE \
+	ALIGN(KGSL_PAGETABLE_ENTRIES(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE) * \
+	KGSL_PAGETABLE_ENTRY_SIZE, PAGE_SIZE)
+
 static ssize_t
 sysfs_show_ptpool_entries(struct kobject *kobj,
 			  struct kobj_attribute *attr,
@@ -310,16 +314,15 @@
 /**
  * kgsl_ptpool_init
  * @pool:  A pointer to a ptpool structure to initialize
- * @ptsize: The size of each pagetable entry
  * @entries:  The number of inital entries to add to the pool
  *
  * Initalize a pool and allocate an initial chunk of entries.
  */
-void *kgsl_gpummu_ptpool_init(int ptsize, int entries)
+void *kgsl_gpummu_ptpool_init(int entries)
 {
+	int ptsize = KGSL_PAGETABLE_SIZE;
 	struct kgsl_ptpool *pool;
 	int ret = 0;
-	BUG_ON(ptsize == 0);
 
 	pool = kzalloc(sizeof(struct kgsl_ptpool), GFP_KERNEL);
 	if (!pool) {
@@ -354,8 +357,8 @@
 int kgsl_gpummu_pt_equal(struct kgsl_pagetable *pt,
 					unsigned int pt_base)
 {
-	struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
-	return pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
+	struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
+	return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
 }
 
 void kgsl_gpummu_destroy_pagetable(void *mmu_specific_pt)
@@ -398,11 +401,11 @@
 				enum kgsl_deviceid id)
 {
 	unsigned int result = 0;
-	struct kgsl_gpummu_pt *gpummu_pt = (struct kgsl_gpummu_pt *)
-						pt->priv;
+	struct kgsl_gpummu_pt *gpummu_pt;
 
 	if (pt == NULL)
 		return 0;
+	gpummu_pt = pt->priv;
 
 	spin_lock(&pt->lock);
 	if (gpummu_pt->tlb_flags && (1<<id)) {
@@ -682,7 +685,7 @@
 		flushtlb = 1;
 
 	for_each_sg(memdesc->sg, s, memdesc->sglen, i) {
-		unsigned int paddr = sg_phys(s);
+		unsigned int paddr = kgsl_get_sg_pa(s);
 		unsigned int j;
 
 		/* Each sg entry might be multiple pages long */
diff --git a/drivers/gpu/msm/kgsl_gpummu.h b/drivers/gpu/msm/kgsl_gpummu.h
index 46466a8..cac6930 100644
--- a/drivers/gpu/msm/kgsl_gpummu.h
+++ b/drivers/gpu/msm/kgsl_gpummu.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
@@ -73,8 +73,7 @@
 	int chunks;
 };
 
-void *kgsl_gpummu_ptpool_init(int ptsize,
-			int entries);
+void *kgsl_gpummu_ptpool_init(int entries);
 void kgsl_gpummu_ptpool_destroy(void *ptpool);
 
 static inline unsigned int kgsl_pt_get_base_addr(struct kgsl_pagetable *pt)
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e4e561c..ea11068 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -24,18 +24,30 @@
 #include "kgsl_mmu.h"
 #include "kgsl_sharedmem.h"
 
+/*
+ * On APQ8064, KGSL can control a maximum of 4 IOMMU devices: 2 user and 2
+ * priv domains, 1 each for each of the AXI ports attached to the GPU.  8660
+ * and 8960 have only one AXI port, so maximum allowable IOMMU devices for those
+ * chips is 2.
+ */
+
+#define KGSL_IOMMU_MAX_DEV 4
+
+struct kgsl_iommu_device {
+	struct device *dev;
+	int attached;
+};
+
 struct kgsl_iommu {
-	struct device *iommu_user_dev;
-	int iommu_user_dev_attached;
-	struct device *iommu_priv_dev;
-	int iommu_priv_dev_attached;
+	struct kgsl_iommu_device dev[KGSL_IOMMU_MAX_DEV];
+	int dev_count;
 };
 
 static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
 					unsigned int pt_base)
 {
-	struct iommu_domain *domain = pt->priv;
-	return pt && pt_base && ((unsigned int)domain == pt_base);
+	struct iommu_domain *domain = pt ? pt->priv : NULL;
+	return domain && pt_base && ((unsigned int)domain == pt_base);
 }
 
 static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
@@ -58,89 +70,101 @@
 {
 	struct iommu_domain *domain;
 	struct kgsl_iommu *iommu = mmu->priv;
+	int i;
 
 	BUG_ON(mmu->hwpagetable == NULL);
 	BUG_ON(mmu->hwpagetable->priv == NULL);
 
 	domain = mmu->hwpagetable->priv;
 
-	if (iommu->iommu_user_dev_attached) {
-		iommu_detach_device(domain, iommu->iommu_user_dev);
-		iommu->iommu_user_dev_attached = 0;
+	for (i = 0; i < iommu->dev_count; i++) {
+		iommu_detach_device(domain, iommu->dev[i].dev);
+		iommu->dev[i].attached = 0;
 		KGSL_MEM_INFO(mmu->device,
-				"iommu %p detached from user dev of MMU: %p\n",
-				domain, mmu);
-	}
-	if (iommu->iommu_priv_dev_attached) {
-		iommu_detach_device(domain, iommu->iommu_priv_dev);
-		iommu->iommu_priv_dev_attached = 0;
-		KGSL_MEM_INFO(mmu->device,
-				"iommu %p detached from priv dev of MMU: %p\n",
-				domain, mmu);
+			"iommu %p detached from user dev of MMU: %p\n",
+			domain, mmu);
 	}
 }
 
 static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
 {
 	struct iommu_domain *domain;
-	int ret = 0;
 	struct kgsl_iommu *iommu = mmu->priv;
+	int i, ret = 0;
 
 	BUG_ON(mmu->hwpagetable == NULL);
 	BUG_ON(mmu->hwpagetable->priv == NULL);
 
 	domain = mmu->hwpagetable->priv;
 
-	if (iommu->iommu_user_dev && !iommu->iommu_user_dev_attached) {
-		ret = iommu_attach_device(domain, iommu->iommu_user_dev);
-		if (ret) {
-			KGSL_MEM_ERR(mmu->device,
-			"Failed to attach device, err %d\n", ret);
-			goto done;
-		}
-		iommu->iommu_user_dev_attached = 1;
-		KGSL_MEM_INFO(mmu->device,
-				"iommu %p attached to user dev of MMU: %p\n",
+	for (i = 0; i < iommu->dev_count; i++) {
+		if (iommu->dev[i].attached == 0) {
+			ret = iommu_attach_device(domain, iommu->dev[i].dev);
+			if (ret) {
+				KGSL_MEM_ERR(mmu->device,
+					"Failed to attach device, err %d\n",
+						ret);
+				goto done;
+			}
+
+			iommu->dev[i].attached = 1;
+			KGSL_MEM_INFO(mmu->device,
+				"iommu %p detached from user dev of MMU: %p\n",
 				domain, mmu);
-	}
-	if (iommu->iommu_priv_dev && !iommu->iommu_priv_dev_attached) {
-		ret = iommu_attach_device(domain, iommu->iommu_priv_dev);
-		if (ret) {
-			KGSL_MEM_ERR(mmu->device,
-				"Failed to attach device, err %d\n", ret);
-			iommu_detach_device(domain, iommu->iommu_user_dev);
-			iommu->iommu_user_dev_attached = 0;
-			goto done;
 		}
-		iommu->iommu_priv_dev_attached = 1;
-		KGSL_MEM_INFO(mmu->device,
-				"iommu %p attached to priv dev of MMU: %p\n",
-				domain, mmu);
 	}
+
 done:
 	return ret;
 }
 
+static int _get_iommu_ctxs(struct kgsl_iommu *iommu, struct kgsl_device *device,
+	struct kgsl_device_iommu_data *data)
+{
+	int i;
+
+	for (i = 0; i < data->iommu_ctx_count; i++) {
+		if (iommu->dev_count >= KGSL_IOMMU_MAX_DEV) {
+			KGSL_CORE_ERR("Tried to attach too many IOMMU "
+				"devices\n");
+			return -ENOMEM;
+		}
+
+		if (!data->iommu_ctx_names[i])
+			continue;
+
+		iommu->dev[iommu->dev_count].dev =
+			msm_iommu_get_ctx(data->iommu_ctx_names[i]);
+		if (iommu->dev[iommu->dev_count].dev == NULL) {
+			KGSL_CORE_ERR("Failed to iommu dev handle for "
+				"device %s\n", data->iommu_ctx_names[i]);
+			return -EINVAL;
+		}
+
+		iommu->dev_count++;
+	}
+
+	return 0;
+}
+
 static int kgsl_get_iommu_ctxt(struct kgsl_iommu *iommu,
 				struct kgsl_device *device)
 {
-	int status = 0;
 	struct platform_device *pdev =
 		container_of(device->parentdev, struct platform_device, dev);
 	struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
-	if (pdata_dev->iommu_user_ctx_name)
-		iommu->iommu_user_dev = msm_iommu_get_ctx(
-					pdata_dev->iommu_user_ctx_name);
-	if (pdata_dev->iommu_priv_ctx_name)
-		iommu->iommu_priv_dev = msm_iommu_get_ctx(
-					pdata_dev->iommu_priv_ctx_name);
-	if (!iommu->iommu_user_dev) {
-		KGSL_CORE_ERR("Failed to get user iommu dev handle for "
-				"device %s\n",
-				pdata_dev->iommu_user_ctx_name);
-		status = -EINVAL;
+	int i, ret = 0;
+
+	/* Go through the IOMMU data and attach all the domains */
+
+	for (i = 0; i < pdata_dev->iommu_count; i++) {
+		ret = _get_iommu_ctxs(iommu, device,
+			&pdata_dev->iommu_data[i]);
+		if (ret)
+			break;
 	}
-	return status;
+
+	return ret;
 }
 
 static void kgsl_iommu_setstate(struct kgsl_device *device,
@@ -182,8 +206,6 @@
 		return -ENOMEM;
 	}
 
-	iommu->iommu_priv_dev_attached = 0;
-	iommu->iommu_user_dev_attached = 0;
 	status = kgsl_get_iommu_ctxt(iommu, device);
 	if (status) {
 		kfree(iommu);
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index 9fafcf4..6fd28ab 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -48,6 +48,16 @@
 
 #define KGSL_LOG_DUMP(_dev, fmt, args...)	dev_err(_dev->dev, fmt, ##args)
 
+#define KGSL_DEV_ERR_ONCE(_dev, fmt, args...) \
+({ \
+	static bool kgsl_dev_err_once; \
+							\
+	if (!kgsl_dev_err_once) { \
+		kgsl_dev_err_once = true; \
+		dev_crit(_dev->dev, "|%s| " fmt, __func__, ##args); \
+	} \
+})
+
 #define KGSL_DRV_INFO(_dev, fmt, args...) \
 KGSL_LOG_INFO(_dev->dev, _dev->drv_log, fmt, ##args)
 #define KGSL_DRV_WARN(_dev, fmt, args...) \
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 671479e..7eb5ee9 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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,10 @@
 static int kgsl_cleanup_pt(struct kgsl_pagetable *pt)
 {
 	int i;
+	/* For IOMMU only unmap the global structures to global pt */
+	if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
+		(KGSL_MMU_GLOBAL_PT !=  pt->name))
+		return 0;
 	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
 		struct kgsl_device *device = kgsl_driver.devp[i];
 		if (device)
@@ -57,6 +61,8 @@
 
 	kgsl_cleanup_pt(pagetable);
 
+	if (pagetable->kgsl_pool)
+		gen_pool_destroy(pagetable->kgsl_pool);
 	if (pagetable->pool)
 		gen_pool_destroy(pagetable->pool);
 
@@ -148,9 +154,10 @@
 
 	pt = _get_pt_from_kobj(kobj);
 
-	if (pt)
+	if (pt) {
 		ret += snprintf(buf, PAGE_SIZE, "0x%x\n",
-			CONFIG_MSM_KGSL_PAGE_TABLE_SIZE);
+			kgsl_mmu_get_ptsize());
+	}
 
 	kgsl_put_pagetable(pt);
 	return ret;
@@ -268,6 +275,22 @@
 	return ret;
 }
 
+unsigned int kgsl_mmu_get_ptsize(void)
+{
+	/*
+	 * For IOMMU, we could do up to 4G virtual range if we wanted to, but
+	 * it makes more sense to return a smaller range and leave the rest of
+	 * the virtual range for future improvements
+	 */
+
+	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
+		return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
+	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
+		return SZ_2G;
+	else
+		return 0;
+}
+
 unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device)
 {
 	struct kgsl_mmu *mmu = &device->mmu;
@@ -367,6 +390,10 @@
 	int i = 0;
 	int status = 0;
 
+	/* For IOMMU only map the global structures to global pt */
+	if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
+		(KGSL_MMU_GLOBAL_PT !=  pt->name))
+		return 0;
 	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
 		struct kgsl_device *device = kgsl_driver.devp[i];
 		if (device) {
@@ -392,6 +419,7 @@
 	int status = 0;
 	struct kgsl_pagetable *pagetable = NULL;
 	unsigned long flags;
+	unsigned int ptsize;
 
 	pagetable = kzalloc(sizeof(struct kgsl_pagetable), GFP_KERNEL);
 	if (pagetable == NULL) {
@@ -403,18 +431,40 @@
 	kref_init(&pagetable->refcount);
 
 	spin_lock_init(&pagetable->lock);
+
+	ptsize = kgsl_mmu_get_ptsize();
+
 	pagetable->name = name;
-	pagetable->max_entries = KGSL_PAGETABLE_ENTRIES(
-					CONFIG_MSM_KGSL_PAGE_TABLE_SIZE);
+	pagetable->max_entries = KGSL_PAGETABLE_ENTRIES(ptsize);
+
+	/*
+	 * create a separate kgsl pool for IOMMU, global mappings can be mapped
+	 * just once from this pool of the defaultpagetable
+	 */
+	if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
+		(KGSL_MMU_GLOBAL_PT == name)) {
+		pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
+		if (pagetable->kgsl_pool == NULL) {
+			KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
+					PAGE_SHIFT);
+			goto err_alloc;
+		}
+		if (gen_pool_add(pagetable->kgsl_pool,
+			KGSL_IOMMU_GLOBAL_MEM_BASE,
+			KGSL_IOMMU_GLOBAL_MEM_SIZE, -1)) {
+			KGSL_CORE_ERR("gen_pool_add failed\n");
+			goto err_kgsl_pool;
+		}
+	}
 
 	pagetable->pool = gen_pool_create(PAGE_SHIFT, -1);
 	if (pagetable->pool == NULL) {
 		KGSL_CORE_ERR("gen_pool_create(%d) failed\n", PAGE_SHIFT);
-		goto err_alloc;
+		goto err_kgsl_pool;
 	}
 
 	if (gen_pool_add(pagetable->pool, KGSL_PAGETABLE_BASE,
-				CONFIG_MSM_KGSL_PAGE_TABLE_SIZE, -1)) {
+				ptsize, -1)) {
 		KGSL_CORE_ERR("gen_pool_add failed\n");
 		goto err_pool;
 	}
@@ -445,6 +495,9 @@
 	pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv);
 err_pool:
 	gen_pool_destroy(pagetable->pool);
+err_kgsl_pool:
+	if (pagetable->kgsl_pool)
+		gen_pool_destroy(pagetable->kgsl_pool);
 err_alloc:
 	kfree(pagetable);
 
@@ -545,19 +598,32 @@
 		}
 	}
 
-	memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->pool,
-		memdesc->size, KGSL_MMU_ALIGN_SHIFT);
+	/* Allocate from kgsl pool if it exists for global mappings */
+	if (pagetable->kgsl_pool &&
+		(KGSL_MEMFLAGS_GLOBAL & memdesc->priv))
+		memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->kgsl_pool,
+			memdesc->size, KGSL_MMU_ALIGN_SHIFT);
+	else
+		memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->pool,
+			memdesc->size, KGSL_MMU_ALIGN_SHIFT);
 
 	if (memdesc->gpuaddr == 0) {
-		KGSL_CORE_ERR("gen_pool_alloc(%d) failed\n", memdesc->size);
+		KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
+			memdesc->size,
+			((pagetable->kgsl_pool &&
+			(KGSL_MEMFLAGS_GLOBAL & memdesc->priv)) ?
+			"kgsl_pool" : "general_pool"));
 		KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
 				pagetable->name, pagetable->stats.mapped,
 				pagetable->stats.entries);
 		return -ENOMEM;
 	}
 
-	spin_lock(&pagetable->lock);
+	if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
+		spin_lock(&pagetable->lock);
 	ret = pagetable->pt_ops->mmu_map(pagetable->priv, memdesc, protflags);
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		spin_lock(&pagetable->lock);
 
 	if (ret)
 		goto err_free_gpuaddr;
@@ -593,18 +659,33 @@
 		memdesc->gpuaddr = 0;
 		return 0;
 	}
-	spin_lock(&pagetable->lock);
+	if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
+		spin_lock(&pagetable->lock);
 	pagetable->pt_ops->mmu_unmap(pagetable->priv, memdesc);
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		spin_lock(&pagetable->lock);
 	/* Remove the statistics */
 	pagetable->stats.entries--;
 	pagetable->stats.mapped -= memdesc->size;
 
 	spin_unlock(&pagetable->lock);
 
-	gen_pool_free(pagetable->pool,
+	if (pagetable->kgsl_pool &&
+		(KGSL_MEMFLAGS_GLOBAL & memdesc->priv))
+		gen_pool_free(pagetable->kgsl_pool,
+			memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK,
+			memdesc->size);
+	else
+		gen_pool_free(pagetable->pool,
 			memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK,
 			memdesc->size);
 
+	/*
+	 * Don't clear the gpuaddr on global mappings because they
+	 * may be in use by other pagetables
+	 */
+	if (!(memdesc->priv & KGSL_MEMFLAGS_GLOBAL))
+		memdesc->gpuaddr = 0;
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_mmu_unmap);
@@ -624,6 +705,7 @@
 		return 0;
 
 	gpuaddr = memdesc->gpuaddr;
+	memdesc->priv |= KGSL_MEMFLAGS_GLOBAL;
 
 	result = kgsl_mmu_map(pagetable, memdesc, protflags);
 	if (result)
@@ -684,10 +766,10 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_ptpool_destroy);
 
-void *kgsl_mmu_ptpool_init(int ptsize, int entries)
+void *kgsl_mmu_ptpool_init(int entries)
 {
 	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
-		return kgsl_gpummu_ptpool_init(ptsize, entries);
+		return kgsl_gpummu_ptpool_init(entries);
 	else
 		return (void *)(-1);
 }
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 1338d0d..bff41bf 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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,6 +13,14 @@
 #ifndef __KGSL_MMU_H
 #define __KGSL_MMU_H
 
+/*
+ * These defines control the split between ttbr1 and ttbr0 pagetables of IOMMU
+ * and what ranges of memory we map to them
+ */
+#define KGSL_IOMMU_GLOBAL_MEM_BASE	0xC0000000
+#define KGSL_IOMMU_GLOBAL_MEM_SIZE	SZ_4M
+#define KGSL_IOMMU_TTBR1_SPLIT		2
+
 #define KGSL_MMU_ALIGN_SHIFT    13
 #define KGSL_MMU_ALIGN_MASK     (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
 
@@ -92,6 +100,7 @@
 	struct kref refcount;
 	unsigned int   max_entries;
 	struct gen_pool *pool;
+	struct gen_pool *kgsl_pool;
 	struct list_head list;
 	unsigned int name;
 	struct kobject *kobj;
@@ -175,13 +184,13 @@
 int kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base);
 int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
 			enum kgsl_deviceid id);
-
 void kgsl_mmu_ptpool_destroy(void *ptpool);
-void *kgsl_mmu_ptpool_init(int ptsize, int entries);
+void *kgsl_mmu_ptpool_init(int entries);
 int kgsl_mmu_enabled(void);
 int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
 			unsigned int pt_base);
 void kgsl_mmu_set_mmutype(char *mmutype);
 unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device);
 enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
+unsigned int kgsl_mmu_get_ptsize(void);
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index ae50183..6f575ec 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -13,7 +13,6 @@
 #include <linux/interrupt.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_bus.h>
-#include <mach/socinfo.h>
 
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
@@ -25,6 +24,7 @@
 #define KGSL_PWRFLAGS_AXI_ON   2
 #define KGSL_PWRFLAGS_IRQ_ON   3
 
+#define GPU_SWFI_LATENCY	3
 #define UPDATE_BUSY_VAL		1000000
 #define UPDATE_BUSY		50
 
@@ -284,7 +284,7 @@
 DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
 DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
 	kgsl_pwrctrl_max_gpuclk_store);
-DEVICE_ATTR(pwrnap, 0666, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
+DEVICE_ATTR(pwrnap, 0664, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
 DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show,
 	kgsl_pwrctrl_idle_timer_store);
 DEVICE_ATTR(gpubusy, 0644, kgsl_pwrctrl_gpubusy_show,
@@ -371,7 +371,6 @@
 		}
 	}
 }
-EXPORT_SYMBOL(kgsl_pwrctrl_clk);
 
 void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
 {
@@ -602,9 +601,7 @@
 
 	mutex_lock(&device->mutex);
 	if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
-		if ((device->requested_state != KGSL_STATE_SLEEP) &&
-			(device->requested_state != KGSL_STATE_SLUMBER))
-			kgsl_pwrscale_idle(device);
+		kgsl_pwrscale_idle(device);
 
 		if (kgsl_pwrctrl_sleep(device) != 0) {
 			mod_timer(&device->idle_timer,
@@ -700,7 +697,7 @@
 		}
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
-		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
+		kgsl_pwrctrl_set_state(device, device->requested_state);
 		if (device->idle_wakelock.name)
 			wake_unlock(&device->idle_wakelock);
 	case KGSL_STATE_NAP:
@@ -744,8 +741,9 @@
 		_sleep_accounting(device);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
-		if (device->idle_wakelock.name)
-			wake_unlock(&device->idle_wakelock);
+		wake_unlock(&device->idle_wakelock);
+		pm_qos_update_request(&device->pm_qos_req_dma,
+					PM_QOS_DEFAULT_VALUE);
 		break;
 	case KGSL_STATE_SLEEP:
 	case KGSL_STATE_SLUMBER:
@@ -773,13 +771,15 @@
 	case KGSL_STATE_SLEEP:
 		del_timer_sync(&device->idle_timer);
 		kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
+		device->pwrctrl.restore_slumber = true;
 		device->ftbl->suspend_context(device);
 		device->ftbl->stop(device);
-		device->pwrctrl.restore_slumber = true;
 		_sleep_accounting(device);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
 		if (device->idle_wakelock.name)
 			wake_unlock(&device->idle_wakelock);
+		pm_qos_update_request(&device->pm_qos_req_dma,
+						PM_QOS_DEFAULT_VALUE);
 		break;
 	case KGSL_STATE_SLUMBER:
 		break;
@@ -848,9 +848,10 @@
 		/* Re-enable HW access */
 		mod_timer(&device->idle_timer,
 				jiffies + device->pwrctrl.interval_timeout);
-
-		if (device->idle_wakelock.name)
-			wake_lock(&device->idle_wakelock);
+		wake_lock(&device->idle_wakelock);
+		if (device->pwrctrl.restore_slumber == false)
+			pm_qos_update_request(&device->pm_qos_req_dma,
+						GPU_SWFI_LATENCY);
 	case KGSL_STATE_ACTIVE:
 		break;
 	default:
@@ -880,16 +881,6 @@
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_disable);
 
-void kgsl_pwrctrl_stop_work(struct kgsl_device *device)
-{
-	del_timer_sync(&device->idle_timer);
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-	mutex_unlock(&device->mutex);
-	flush_workqueue(device->work_queue);
-	mutex_lock(&device->mutex);
-}
-EXPORT_SYMBOL(kgsl_pwrctrl_stop_work);
-
 void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state)
 {
 	trace_kgsl_pwr_set_state(device, state);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 99dbae9..2222cdf 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -21,6 +21,7 @@
 
 #define KGSL_PWRLEVEL_TURBO 0
 #define KGSL_PWRLEVEL_NOMINAL 1
+#define KGSL_PWRLEVEL_LAST_OFFSET 2
 
 #define KGSL_MAX_CLKS 5
 
@@ -59,7 +60,6 @@
 };
 
 void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
-void kgsl_pwrctrl_clk(struct kgsl_device *device, int state);
 int kgsl_pwrctrl_init(struct kgsl_device *device);
 void kgsl_pwrctrl_close(struct kgsl_device *device);
 void kgsl_timer(unsigned long data);
@@ -74,7 +74,6 @@
 void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device);
 void kgsl_pwrctrl_enable(struct kgsl_device *device);
 void kgsl_pwrctrl_disable(struct kgsl_device *device);
-void kgsl_pwrctrl_stop_work(struct kgsl_device *device);
 static inline unsigned long kgsl_get_clkrate(struct clk *clk)
 {
 	return (clk != NULL) ? clk_get_rate(clk) : 0;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 4c9a239..1cecbc7 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -45,6 +45,9 @@
 #ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
 	&kgsl_pwrscale_policy_idlestats,
 #endif
+#ifdef CONFIG_MSM_DCVS
+	&kgsl_pwrscale_policy_msm,
+#endif
 	NULL
 };
 
@@ -90,7 +93,7 @@
 	return ret;
 }
 
-PWRSCALE_ATTR(policy, 0666, pwrscale_policy_show, pwrscale_policy_store);
+PWRSCALE_ATTR(policy, 0664, pwrscale_policy_show, pwrscale_policy_store);
 
 static ssize_t pwrscale_avail_policies_show(struct kgsl_device *device,
 					    char *buf)
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index b4f831e..6023476 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.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
@@ -54,6 +54,7 @@
 
 extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz;
 extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_idlestats;
+extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm;
 
 int kgsl_pwrscale_init(struct kgsl_device *device);
 void kgsl_pwrscale_close(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
index 2976b0b..71af893 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
@@ -153,6 +153,14 @@
 		MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED);
 }
 
+static void idlestats_wake(struct kgsl_device *device,
+			struct kgsl_pwrscale *pwrscale)
+{
+	/* Use highest perf level on wake-up from
+	   sleep for better performance */
+	kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
+}
+
 static int idlestats_init(struct kgsl_device *device,
 		     struct kgsl_pwrscale *pwrscale)
 {
@@ -218,5 +226,6 @@
 	.idle = idlestats_idle,
 	.busy = idlestats_busy,
 	.sleep = idlestats_sleep,
+	.wake = idlestats_wake,
 	.close = idlestats_close
 };
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
new file mode 100644
index 0000000..f77a02b
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.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/slab.h>
+#include <mach/msm_dcvs.h>
+#include "kgsl.h"
+#include "kgsl_pwrscale.h"
+#include "kgsl_device.h"
+
+struct msm_priv {
+	struct kgsl_device *device;
+	int enabled;
+	int handle;
+	unsigned int cur_freq;
+	struct msm_dcvs_idle idle_source;
+	struct msm_dcvs_freq freq_sink;
+	struct msm_dcvs_core_info *core_info;
+};
+
+static int msm_idle_enable(struct msm_dcvs_idle *self,
+					enum msm_core_control_event event)
+{
+	struct msm_priv *priv = container_of(self, struct msm_priv,
+								idle_source);
+
+	switch (event) {
+	case MSM_DCVS_ENABLE_IDLE_PULSE:
+		priv->enabled = true;
+		break;
+	case MSM_DCVS_DISABLE_IDLE_PULSE:
+		priv->enabled = false;
+		break;
+	case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
+	case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
+		break;
+	}
+	return 0;
+}
+
+/* Set the requested frequency if it is within 5MHz (delta) of a
+ * supported frequency.
+ */
+static int msm_set_freq(struct msm_dcvs_freq *self,
+						unsigned int freq)
+{
+	int i, delta = 5000000;
+	struct msm_priv *priv = container_of(self, struct msm_priv,
+								freq_sink);
+	struct kgsl_device *device = priv->device;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+	/* msm_dcvs manager uses frequencies in kHz */
+	freq *= 1000;
+	for (i = 0; i < pwr->num_pwrlevels; i++)
+		if (abs(pwr->pwrlevels[i].gpu_freq - freq) < delta)
+			break;
+	if (i == pwr->num_pwrlevels)
+		return 0;
+
+	mutex_lock(&device->mutex);
+	kgsl_pwrctrl_pwrlevel_change(device, i);
+	priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
+	mutex_unlock(&device->mutex);
+
+	/* return current frequency in kHz */
+	return priv->cur_freq / 1000;
+}
+
+static unsigned int msm_get_freq(struct msm_dcvs_freq *self)
+{
+	struct msm_priv *priv = container_of(self, struct msm_priv,
+								freq_sink);
+	/* return current frequency in kHz */
+	return priv->cur_freq / 1000;
+}
+
+static void msm_busy(struct kgsl_device *device,
+			struct kgsl_pwrscale *pwrscale)
+{
+	struct msm_priv *priv = pwrscale->priv;
+	if (priv->enabled)
+		msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_EXIT, 0);
+	return;
+}
+
+static void msm_idle(struct kgsl_device *device,
+			struct kgsl_pwrscale *pwrscale)
+{
+	struct msm_priv *priv = pwrscale->priv;
+	if (priv->enabled && pwrscale->gpu_busy)
+		msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+
+	return;
+}
+
+static void msm_sleep(struct kgsl_device *device,
+			struct kgsl_pwrscale *pwrscale)
+{
+	/* do we need to reset any parameters here? */
+}
+
+static int msm_init(struct kgsl_device *device,
+		     struct kgsl_pwrscale *pwrscale)
+{
+	struct msm_priv *priv;
+	struct msm_dcvs_freq_entry *tbl;
+	int i, ret, low_level;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	struct platform_device *pdev =
+		container_of(device->parentdev, struct platform_device, dev);
+	struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+
+	priv = pwrscale->priv = kzalloc(sizeof(struct msm_priv),
+		GFP_KERNEL);
+	if (pwrscale->priv == NULL)
+		return -ENOMEM;
+
+	priv->core_info = pdata->core_info;
+	tbl = priv->core_info->freq_tbl;
+	/* Fill in frequency table from low to high, reversing order. */
+	low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
+	for (i = 0; i <= low_level; i++)
+		tbl[i].freq =
+			pwr->pwrlevels[low_level - i].gpu_freq / 1000;
+	ret = msm_dcvs_register_core(device->name, 0, priv->core_info);
+	if (ret) {
+		KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
+		goto err;
+	}
+
+	priv->device = device;
+	priv->idle_source.enable = msm_idle_enable;
+	priv->idle_source.core_name = device->name;
+	priv->handle = msm_dcvs_idle_source_register(&priv->idle_source);
+	if (priv->handle < 0) {
+		ret = priv->handle;
+		KGSL_PWR_ERR(device, "msm_dcvs_idle_source_register failed\n");
+		goto err;
+	}
+
+	priv->freq_sink.core_name = device->name;
+	priv->freq_sink.set_frequency = msm_set_freq;
+	priv->freq_sink.get_frequency = msm_get_freq;
+	ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
+	if (ret >= 0) {
+		if (device->ftbl->isidle(device)) {
+			device->pwrscale.gpu_busy = 0;
+			msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+		} else {
+			device->pwrscale.gpu_busy = 1;
+		}
+		return 0;
+	}
+
+	KGSL_PWR_ERR(device, "msm_dcvs_freq_sink_register failed\n");
+	msm_dcvs_idle_source_unregister(&priv->idle_source);
+
+err:
+	kfree(pwrscale->priv);
+	pwrscale->priv = NULL;
+
+	return ret;
+}
+
+static void msm_close(struct kgsl_device *device,
+		      struct kgsl_pwrscale *pwrscale)
+{
+	struct msm_priv *priv = pwrscale->priv;
+
+	if (pwrscale->priv == NULL)
+		return;
+	msm_dcvs_idle_source_unregister(&priv->idle_source);
+	msm_dcvs_freq_sink_unregister(&priv->freq_sink);
+	kfree(pwrscale->priv);
+	pwrscale->priv = NULL;
+}
+
+struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm = {
+	.name = "msm",
+	.init = msm_init,
+	.idle = msm_idle,
+	.busy = msm_busy,
+	.sleep = msm_sleep,
+	.close = msm_close,
+};
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 931ef48..eef80d3 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -180,7 +180,7 @@
 	struct tz_priv *priv;
 
 	/* Trustzone is only valid for some SOCs */
-	if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_msm8930()))
+	if (!(cpu_is_msm8x60() || cpu_is_msm8960()))
 		return -EINVAL;
 
 	priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 389ed6d..1f142f8 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -13,6 +13,8 @@
 #include <linux/vmalloc.h>
 #include <linux/memory_alloc.h>
 #include <asm/cacheflush.h>
+#include <linux/slab.h>
+#include <linux/kmemleak.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
@@ -150,7 +152,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
 };
 
@@ -282,7 +284,7 @@
 	int i;
 
 	for_each_sg(sg, s, sglen, i) {
-		unsigned int paddr = sg_phys(s);
+		unsigned int paddr = kgsl_get_sg_pa(s);
 		_outer_cache_range_op(op, paddr, s->length);
 	}
 }
@@ -297,13 +299,14 @@
 				struct vm_area_struct *vma,
 				struct vm_fault *vmf)
 {
-	unsigned long offset, pg;
+	unsigned long offset;
 	struct page *page;
+	int i;
 
 	offset = (unsigned long) vmf->virtual_address - vma->vm_start;
-	pg = (unsigned long) memdesc->hostptr + offset;
 
-	page = vmalloc_to_page((void *) pg);
+	i = offset >> PAGE_SHIFT;
+	page = sg_page(&memdesc->sg[i]);
 	if (page == NULL)
 		return VM_FAULT_SIGBUS;
 
@@ -320,8 +323,14 @@
 
 static void kgsl_vmalloc_free(struct kgsl_memdesc *memdesc)
 {
+	int i = 0;
+	struct scatterlist *sg;
 	kgsl_driver.stats.vmalloc -= memdesc->size;
-	vfree(memdesc->hostptr);
+	if (memdesc->hostptr)
+		vunmap(memdesc->hostptr);
+	if (memdesc->sg)
+		for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+			__free_page(sg_page(sg));
 }
 
 static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc)
@@ -329,6 +338,39 @@
 	return VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
 }
 
+/*
+ * kgsl_vmalloc_map_kernel - Map the memory in memdesc to kernel address space
+ *
+ * @memdesc - The memory descriptor which contains information about the memory
+ *
+ * Return: 0 on success else error code
+ */
+static int kgsl_vmalloc_map_kernel(struct kgsl_memdesc *memdesc)
+{
+	if (!memdesc->hostptr) {
+		pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
+		struct page **pages = NULL;
+		struct scatterlist *sg;
+		int i;
+		/* create a list of pages to call vmap */
+		pages = vmalloc(memdesc->sglen * sizeof(struct page *));
+		if (!pages) {
+			KGSL_CORE_ERR("vmalloc(%d) failed\n",
+				memdesc->sglen * sizeof(struct page *));
+			return -ENOMEM;
+		}
+		for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+			pages[i] = sg_page(sg);
+		memdesc->hostptr = vmap(pages, memdesc->sglen,
+					VM_IOREMAP, page_prot);
+		vfree(pages);
+	}
+	if (!memdesc->hostptr)
+		return -ENOMEM;
+
+	return 0;
+}
+
 static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
 				struct vm_area_struct *vma,
 				struct vm_fault *vmf)
@@ -372,6 +414,7 @@
 	.free = kgsl_vmalloc_free,
 	.vmflags = kgsl_vmalloc_vmflags,
 	.vmfault = kgsl_vmalloc_vmfault,
+	.map_kernel_mem = kgsl_vmalloc_map_kernel,
 };
 EXPORT_SYMBOL(kgsl_vmalloc_ops);
 
@@ -409,7 +452,7 @@
 static int
 _kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
 			struct kgsl_pagetable *pagetable,
-			void *ptr, size_t size, unsigned int protflags)
+			size_t size, unsigned int protflags)
 {
 	int order, ret = 0;
 	int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
@@ -419,28 +462,31 @@
 	memdesc->pagetable = pagetable;
 	memdesc->priv = KGSL_MEMFLAGS_CACHED;
 	memdesc->ops = &kgsl_vmalloc_ops;
-	memdesc->hostptr = (void *) ptr;
 
-	memdesc->sg = vmalloc(sglen * sizeof(struct scatterlist));
+	memdesc->sg = kgsl_sg_alloc(sglen);
+
 	if (memdesc->sg == NULL) {
 		ret = -ENOMEM;
 		goto done;
 	}
 
+	kmemleak_not_leak(memdesc->sg);
+
 	memdesc->sglen = sglen;
 	sg_init_table(memdesc->sg, sglen);
 
-	for (i = 0; i < memdesc->sglen; i++, ptr += PAGE_SIZE) {
-		struct page *page = vmalloc_to_page(ptr);
+	for (i = 0; i < memdesc->sglen; i++) {
+		struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO |
+						__GFP_HIGHMEM);
 		if (!page) {
-			ret = -EINVAL;
+			ret = -ENOMEM;
+			memdesc->sglen = i;
 			goto done;
 		}
+		flush_dcache_page(page);
 		sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0);
 	}
 
-	kgsl_cache_range_op(memdesc, KGSL_CACHE_OP_INV);
-
 	ret = kgsl_mmu_map(pagetable, memdesc, protflags);
 
 	if (ret)
@@ -465,20 +511,18 @@
 kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
 		       struct kgsl_pagetable *pagetable, size_t size)
 {
-	void *ptr;
-
+	int ret = 0;
 	BUG_ON(size == 0);
 
 	size = ALIGN(size, PAGE_SIZE * 2);
-	ptr = vmalloc(size);
 
-	if (ptr  == NULL) {
-		KGSL_CORE_ERR("vmalloc(%d) failed\n", size);
-		return -ENOMEM;
-	}
-
-	return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
+	ret =  _kgsl_sharedmem_vmalloc(memdesc, pagetable, size,
 		GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	if (!ret)
+		ret = kgsl_vmalloc_map_kernel(memdesc);
+	if (ret)
+		kgsl_sharedmem_free(memdesc);
+	return ret;
 }
 EXPORT_SYMBOL(kgsl_sharedmem_vmalloc);
 
@@ -487,23 +531,15 @@
 			    struct kgsl_pagetable *pagetable,
 			    size_t size, int flags)
 {
-	void *ptr;
 	unsigned int protflags;
 
 	BUG_ON(size == 0);
-	ptr = vmalloc_user(size);
-
-	if (ptr == NULL) {
-		KGSL_CORE_ERR("vmalloc_user(%d) failed: allocated=%d\n",
-			      size, kgsl_driver.stats.vmalloc);
-		return -ENOMEM;
-	}
 
 	protflags = GSL_PT_PAGE_RV;
 	if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
 		protflags |= GSL_PT_PAGE_WV;
 
-	return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
+	return _kgsl_sharedmem_vmalloc(memdesc, pagetable, size,
 		protflags);
 }
 EXPORT_SYMBOL(kgsl_sharedmem_vmalloc_user);
@@ -554,7 +590,7 @@
 	if (memdesc->ops && memdesc->ops->free)
 		memdesc->ops->free(memdesc);
 
-	vfree(memdesc->sg);
+	kgsl_sg_free(memdesc->sg, memdesc->sglen);
 
 	memset(memdesc, 0, sizeof(*memdesc));
 }
@@ -686,3 +722,33 @@
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_sharedmem_set);
+
+/*
+ * kgsl_sharedmem_map_vma - Map a user vma to physical memory
+ *
+ * @vma - The user vma to map
+ * @memdesc - The memory descriptor which contains information about the
+ * physical memory
+ *
+ * Return: 0 on success else error code
+ */
+int
+kgsl_sharedmem_map_vma(struct vm_area_struct *vma,
+			const struct kgsl_memdesc *memdesc)
+{
+	unsigned long addr = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	int ret, i = 0;
+
+	if (!memdesc->sg || (size != memdesc->size) ||
+		(memdesc->sglen != (size / PAGE_SIZE)))
+		return -EINVAL;
+
+	for (; addr < vma->vm_end; addr += PAGE_SIZE, i++) {
+		ret = vm_insert_page(vma, addr, sg_page(&memdesc->sg[i]));
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(kgsl_sharedmem_map_vma);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 67a1c2d..def29b3 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -17,6 +17,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
 #include "kgsl_mmu.h"
+#include <linux/slab.h>
+#include <linux/kmemleak.h>
 
 struct kgsl_device;
 struct kgsl_process_private;
@@ -27,13 +29,8 @@
 
 /** Set if the memdesc describes cached memory */
 #define KGSL_MEMFLAGS_CACHED    0x00000001
-
-struct kgsl_memdesc_ops {
-	int (*vmflags)(struct kgsl_memdesc *);
-	int (*vmfault)(struct kgsl_memdesc *, struct vm_area_struct *,
-		       struct vm_fault *);
-	void (*free)(struct kgsl_memdesc *memdesc);
-};
+/** Set if the memdesc is mapped into all pagetables */
+#define KGSL_MEMFLAGS_GLOBAL    0x00000002
 
 extern struct kgsl_memdesc_ops kgsl_vmalloc_ops;
 
@@ -76,19 +73,58 @@
 int kgsl_sharedmem_init_sysfs(void);
 void kgsl_sharedmem_uninit_sysfs(void);
 
+static inline unsigned int kgsl_get_sg_pa(struct scatterlist *sg)
+{
+	/*
+	 * Try sg_dma_address first to support ion carveout
+	 * regions which do not work with sg_phys().
+	 */
+	unsigned int pa = sg_dma_address(sg);
+	if (pa == 0)
+		pa = sg_phys(sg);
+	return pa;
+}
+
+int
+kgsl_sharedmem_map_vma(struct vm_area_struct *vma,
+			const struct kgsl_memdesc *memdesc);
+
+/*
+ * For relatively small sglists, it is preferable to use kzalloc
+ * rather than going down the vmalloc rat hole.  If the size of
+ * the sglist is < PAGE_SIZE use kzalloc otherwise fallback to
+ * vmalloc
+ */
+
+static inline void *kgsl_sg_alloc(unsigned int sglen)
+{
+	if ((sglen * sizeof(struct scatterlist)) <  PAGE_SIZE)
+		return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL);
+	else
+		return vmalloc(sglen * sizeof(struct scatterlist));
+}
+
+static inline void kgsl_sg_free(void *ptr, unsigned int sglen)
+{
+	if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
+		kfree(ptr);
+	else
+		vfree(ptr);
+}
+
 static inline int
 memdesc_sg_phys(struct kgsl_memdesc *memdesc,
 		unsigned int physaddr, unsigned int size)
 {
-	struct page *page = phys_to_page(physaddr);
+	memdesc->sg = kgsl_sg_alloc(1);
 
-	memdesc->sg = vmalloc(sizeof(struct scatterlist) * 1);
-	if (memdesc->sg == NULL)
-		return -ENOMEM;
+	kmemleak_not_leak(memdesc->sg);
 
 	memdesc->sglen = 1;
 	sg_init_table(memdesc->sg, 1);
-	sg_set_page(&memdesc->sg[0], page, size, 0);
+	memdesc->sg[0].length = size;
+	memdesc->sg[0].offset = 0;
+	memdesc->sg[0].dma_address = physaddr;
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index de39ee4..cfcb2ea 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>
@@ -23,6 +22,17 @@
 #include "kgsl_sharedmem.h"
 #include "kgsl_snapshot.h"
 
+/* Placeholder for the list of memory objects frozen after a hang */
+
+struct kgsl_snapshot_object {
+	unsigned int gpuaddr;
+	unsigned int ptbase;
+	unsigned int size;
+	int type;
+	struct kgsl_mem_entry *entry;
+	struct list_head node;
+};
+
 /* idr_for_each function to count the number of contexts */
 
 static int snapshot_context_count(int id, void *ptr, void *data)
@@ -165,6 +175,199 @@
 	return (iregs->count * 4) + sizeof(*header);
 }
 
+#define GPU_OBJ_HEADER_SZ \
+	(sizeof(struct kgsl_snapshot_section_header) + \
+	 sizeof(struct kgsl_snapshot_gpu_object))
+
+#define GPU_OBJ_SECTION_SIZE(_o) \
+	(GPU_OBJ_HEADER_SZ + ((_o)->size))
+
+static int kgsl_snapshot_dump_object(struct kgsl_device *device,
+		struct kgsl_snapshot_object *obj, void *buf,
+		unsigned int off, unsigned int count)
+{
+	unsigned char headers[GPU_OBJ_HEADER_SZ];
+	struct kgsl_snapshot_section_header *sect =
+		(struct kgsl_snapshot_section_header *) headers;
+	struct kgsl_snapshot_gpu_object *header =
+		(struct kgsl_snapshot_gpu_object *) (headers + sizeof(*sect));
+	int ret = 0;
+
+	/* Construct a local copy of the headers */
+
+	sect->magic = SNAPSHOT_SECTION_MAGIC;
+	sect->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
+	sect->size = GPU_OBJ_SECTION_SIZE(obj);
+
+	header->type = obj->type;
+
+	/* Header size is in dwords, object size is in bytes */
+	header->size = obj->size >> 2;
+	header->gpuaddr = obj->gpuaddr;
+	header->ptbase = obj->ptbase;
+
+	/* Copy out any part of the header block that is needed */
+
+	if (off < GPU_OBJ_HEADER_SZ) {
+		int size = count < GPU_OBJ_HEADER_SZ - off ?
+			count : GPU_OBJ_HEADER_SZ - off;
+
+		memcpy(buf, headers + off, size);
+
+		count -= size;
+		ret += size;
+	}
+
+	/* Now copy whatever part of the data is needed */
+
+	if (off < (GPU_OBJ_HEADER_SZ + obj->size)) {
+		int offset;
+		int size = count < obj->size ? count : obj->size;
+
+		/*
+		 * If the desired gpuaddr isn't at the beginning of the region,
+		 * then offset the source pointer
+		 */
+
+		offset = obj->gpuaddr - obj->entry->memdesc.gpuaddr;
+
+		/*
+		 * Then  adjust it to account for the offset for the output
+		 * buffer.
+		 */
+
+		if (off > GPU_OBJ_HEADER_SZ) {
+			int loff = (off - GPU_OBJ_HEADER_SZ);
+
+			/* Adjust the size so we don't walk off the end */
+
+			if ((loff + size) > obj->size)
+				size = obj->size - loff;
+
+			offset += loff;
+		}
+
+		memcpy(buf + ret, obj->entry->memdesc.hostptr + offset, size);
+		ret += size;
+	}
+
+	return ret;
+}
+
+static void kgsl_snapshot_put_object(struct kgsl_device *device,
+	struct kgsl_snapshot_object *obj)
+{
+	list_del(&obj->node);
+
+	obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN;
+	kgsl_mem_entry_put(obj->entry);
+
+	kfree(obj);
+}
+
+/* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
+ * @device - the device that is being snapshotted
+ * @ptbase - the pagetable base of the object to freeze
+ * @gpuaddr - The gpu address of the object to freeze
+ * @size - the size of the object (may not always be the size of the region)
+ * @type - the type of object being saved (shader, vbo, etc)
+ *
+ * Mark and freeze a GPU buffer object.  This will prevent it from being
+ * freed until it can be copied out as part of the snapshot dump.  Returns the
+ * size of the object being frozen
+ */
+
+int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
+	unsigned int gpuaddr, unsigned int size, unsigned int type)
+{
+	struct kgsl_mem_entry *entry;
+	struct kgsl_snapshot_object *obj;
+	int offset;
+
+	entry = kgsl_get_mem_entry(ptbase, gpuaddr, size);
+
+	if (entry == NULL) {
+		KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
+				gpuaddr);
+		return 0;
+	}
+
+	/* We can't freeze external memory, because we don't own it */
+	if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
+		KGSL_DRV_ERR(device,
+			"Only internal GPU buffers can be frozen\n");
+		return 0;
+	}
+
+	/*
+	 * size indicates the number of bytes in the region to save. This might
+	 * not always be the entire size of the region because some buffers are
+	 * sub-allocated from a larger region.  However, if size 0 was passed
+	 * thats a flag that the caller wants to capture the entire buffer
+	 */
+
+	if (size == 0) {
+		size = entry->memdesc.size;
+		offset = 0;
+
+		/* Adjust the gpuaddr to the start of the object */
+		gpuaddr = entry->memdesc.gpuaddr;
+	} else {
+		offset = gpuaddr - entry->memdesc.gpuaddr;
+	}
+
+	if (size + offset > entry->memdesc.size) {
+		KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
+				gpuaddr);
+		return 0;
+	}
+
+	/* If the buffer is already on the list, skip it */
+	list_for_each_entry(obj, &device->snapshot_obj_list, node) {
+		if (obj->gpuaddr == gpuaddr && obj->ptbase == ptbase) {
+			/* If the size is different, use the new size */
+			if (obj->size != size)
+				obj->size = size;
+
+			return 0;
+		}
+	}
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+
+	if (obj == NULL) {
+		KGSL_DRV_ERR(device, "Unable to allocate memory\n");
+		return 0;
+	}
+
+	/* Ref count the mem entry */
+	kgsl_mem_entry_get(entry);
+
+	obj->type = type;
+	obj->entry = entry;
+	obj->gpuaddr = gpuaddr;
+	obj->ptbase = ptbase;
+	obj->size = size;
+
+	list_add(&obj->node, &device->snapshot_obj_list);
+
+	/*
+	 * Return the size of the entire mem entry that was frozen - this gets
+	 * used for tracking how much memory is frozen for a hang.  Also, mark
+	 * the memory entry as frozen. If the entry was already marked as
+	 * frozen, then another buffer already got to it.  In that case, return
+	 * 0 so it doesn't get counted twice
+	 */
+
+	if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
+		return 0;
+
+	entry->flags |= KGSL_MEM_ENTRY_FROZEN;
+
+	return entry->memdesc.size;
+}
+EXPORT_SYMBOL(kgsl_snapshot_get_object);
+
 /*
  * kgsl_snapshot_dump_regs - helper function to dump device registers
  * @device - the device to dump registers from
@@ -289,16 +492,16 @@
 		snapshot = device->ftbl->snapshot(device, snapshot, &remain,
 			hang);
 
-	/* Add the empty end section to let the parser know we are done */
-	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_END,
-		snapshot, &remain, NULL, NULL);
-
 	device->snapshot_timestamp = get_seconds();
 	device->snapshot_size = (int) (snapshot - device->snapshot);
 
 	/* 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);
@@ -323,6 +526,8 @@
 	size_t count)
 {
 	struct kgsl_device *device = kobj_to_device(kobj);
+	struct kgsl_snapshot_object *obj, *tmp;
+	unsigned int size, src, dst = 0;
 
 	if (device == NULL)
 		return 0;
@@ -334,25 +539,80 @@
 	/* Get the mutex to keep things from changing while we are dumping */
 	mutex_lock(&device->mutex);
 
-	/*
-	 * Release the freeze on the snapshot the first time the buffer is read
-	 */
+	if (off < device->snapshot_size) {
+		size = count < (device->snapshot_size - off) ?
+			count : device->snapshot_size - off;
+
+		memcpy(buf, device->snapshot + off, size);
+
+		count -= size;
+		dst += size;
+	}
+
+	if (count == 0)
+		goto done;
+
+	src = device->snapshot_size;
+
+	list_for_each_entry(obj, &device->snapshot_obj_list, node) {
+
+		int objsize = GPU_OBJ_SECTION_SIZE(obj);
+		int offset;
+
+		/* If the offset is beyond this object, then move on */
+
+		if (off >= (src + objsize)) {
+			src += objsize;
+			continue;
+		}
+
+		/* Adjust the offset to be relative to the object */
+		offset = (off >= src) ? (off - src) : 0;
+
+		size = kgsl_snapshot_dump_object(device, obj, buf + dst,
+			offset, count);
+
+		count -= size;
+		dst += size;
+
+		if (count == 0)
+			goto done;
+
+		/* Move on to the next object - update src accordingly */
+		src += objsize;
+	}
+
+	/* Add the end section */
+
+	if (off < (src + sizeof(struct kgsl_snapshot_section_header))) {
+		if (count >= sizeof(struct kgsl_snapshot_section_header)) {
+			struct kgsl_snapshot_section_header *head =
+				(void *) (buf + dst);
+
+			head->magic = SNAPSHOT_SECTION_MAGIC;
+			head->id = KGSL_SNAPSHOT_SECTION_END;
+			head->size = sizeof(*head);
+
+			dst += sizeof(*head);
+		} else {
+			goto done;
+		}
+	}
+
+	/* Release the buffers and unfreeze the snapshot */
+
+	list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list, node)
+		kgsl_snapshot_put_object(device, obj);
+
+	if (device->snapshot_frozen)
+		KGSL_DRV_ERR(device, "Snapshot objects released\n");
 
 	device->snapshot_frozen = 0;
 
-	if (off >= device->snapshot_size) {
-		count = 0;
-		goto exit;
-	}
-
-	if (off + count > device->snapshot_size)
-		count = device->snapshot_size - off;
-
-	memcpy(buf, device->snapshot + off, count);
-
-exit:
+done:
 	mutex_unlock(&device->mutex);
-	return count;
+
+	return dst;
 }
 
 /* Show the timestamp of the last collected snapshot */
@@ -448,7 +708,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;
@@ -456,6 +716,8 @@
 	device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
 	device->snapshot_timestamp = 0;
 
+	INIT_LIST_HEAD(&device->snapshot_obj_list);
+
 	ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
 		&device->dev->kobj, "snapshot");
 	if (ret)
@@ -491,7 +753,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_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 3b72b0f..304f4bb 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -48,6 +48,8 @@
 #define KGSL_SNAPSHOT_SECTION_ISTORE       0x0801
 #define KGSL_SNAPSHOT_SECTION_DEBUG        0x0901
 #define KGSL_SNAPSHOT_SECTION_DEBUGBUS     0x0A01
+#define KGSL_SNAPSHOT_SECTION_GPU_OBJECT   0x0B01
+
 #define KGSL_SNAPSHOT_SECTION_END          0xFFFF
 
 /* OS sub-section header */
@@ -149,6 +151,17 @@
 	int count; /* Number of dwords in the dump */
 } __packed;
 
+#define SNAPSHOT_GPU_OBJECT_SHADER  1
+#define SNAPSHOT_GPU_OBJECT_IB      2
+#define SNAPSHOT_GPU_OBJECT_GENERIC 3
+
+struct kgsl_snapshot_gpu_object {
+	int type;      /* Type of GPU object */
+	__u32 gpuaddr; /* GPU address of the the object */
+	__u32 ptbase;  /* Base for the pagetable the GPU address is valid in */
+	int size;    /* Size of the object (in dwords) */
+};
+
 #ifdef __KERNEL__
 
 /* Allocate 512K for each device snapshot */
@@ -272,6 +285,9 @@
 	void *snapshot, int *remain, unsigned int index,
 	unsigned int data, unsigned int start, unsigned int count);
 
+/* Freeze a GPU buffer so it can be dumped in the snapshot */
+int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
+	unsigned int gpuaddr, unsigned int size, unsigned int type);
 
 #endif
 #endif
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 718fac9..41f4435 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);
 
@@ -407,7 +409,7 @@
 	unsigned int index	= 0;
 	unsigned int nextindex;
 	unsigned int nextcnt    = Z180_STREAM_END_CMD | 5;
-	struct kgsl_memdesc tmp = {0};
+	struct kgsl_mem_entry *entry = NULL;
 	unsigned int cmd;
 	struct kgsl_device *device = dev_priv->device;
 	struct kgsl_pagetable *pagetable = dev_priv->process_priv->pagetable;
@@ -425,8 +427,30 @@
 	}
 	cmd = ibdesc[0].gpuaddr;
 	sizedwords = ibdesc[0].sizedwords;
-
-	tmp.hostptr = (void *)*timestamp;
+	/*
+	 * Get a kernel mapping to the IB for monkey patching.
+	 * See the end of this function.
+	 */
+	entry = kgsl_sharedmem_find_region(dev_priv->process_priv, cmd,
+		sizedwords);
+	if (entry == NULL) {
+		KGSL_DRV_ERR(device, "Bad ibdesc: gpuaddr 0x%x size %d\n",
+			     cmd, sizedwords);
+		result = -EINVAL;
+		goto error;
+	}
+	/*
+	 * This will only map memory if it exists, otherwise it will reuse the
+	 * mapping. And the 2d userspace reuses IBs so we likely won't create
+	 * too many mappings.
+	 */
+	if (kgsl_gpuaddr_to_vaddr(&entry->memdesc, cmd) == NULL) {
+		KGSL_DRV_ERR(device,
+			     "Cannot make kernel mapping for gpuaddr 0x%x\n",
+			     cmd);
+		result = -EINVAL;
+		goto error;
+	}
 
 	KGSL_CMD_INFO(device, "ctxt %d ibaddr 0x%08x sizedwords %d\n",
 		context->id, cmd, sizedwords);
@@ -468,12 +492,13 @@
 	nextaddr = z180_dev->ringbuffer.cmdbufdesc.gpuaddr
 		+ rb_offset(nextindex);
 
-	tmp.hostptr = (void *)(tmp.hostptr +
-			(sizedwords * sizeof(unsigned int)));
-	tmp.size = 12;
-
-	kgsl_sharedmem_writel(&tmp, 4, nextaddr);
-	kgsl_sharedmem_writel(&tmp, 8, nextcnt);
+	/* monkey patch the IB so that it jumps back to the ringbuffer */
+	kgsl_sharedmem_writel(&entry->memdesc,
+			      ((sizedwords + 1) * sizeof(unsigned int)),
+			      nextaddr);
+	kgsl_sharedmem_writel(&entry->memdesc,
+			      ((sizedwords + 2) * sizeof(unsigned int)),
+			      nextcnt);
 
 	/* sync memory before activating the hardware for the new command*/
 	mb();
@@ -566,7 +591,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);
@@ -584,6 +609,8 @@
 	device->ftbl->irqctrl(device, 0);
 	z180_idle(device, KGSL_TIMEOUT_DEFAULT);
 
+	del_timer_sync(&device->idle_timer);
+
 	kgsl_mmu_stop(device);
 
 	/* Disable the clocks before the power rail. */
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 36ca465..7e0acf4 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -69,7 +69,7 @@
 	Say Y here if you want to enable support for ACRUX game controllers.
 
 config HID_ACRUX_FF
-	tristate "ACRUX force feedback support"
+	bool "ACRUX force feedback support"
 	depends on HID_ACRUX
 	select INPUT_FF_MEMLESS
 	---help---
@@ -314,6 +314,7 @@
 	  - Hanvon dual touch panels
 	  - Ilitek dual touch panels
 	  - IrTouch Infrared USB panels
+	  - LG Display panels (Dell ST2220Tc)
 	  - Lumio CrystalTouch panels
 	  - MosArt dual-touch panels
 	  - PenMount dual touch panels
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index b85744f..299d238 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -444,11 +444,20 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
 			APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
+		.driver_data = APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
+		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS),
+		.driver_data = APPLE_HAS_FN },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
 			APPLE_ISO_KEYBOARD },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
+		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+			APPLE_ISO_KEYBOARD },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
@@ -487,6 +496,24 @@
 		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
 		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
+		.driver_data = APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
+		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
+		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
+		.driver_data = APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
+		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
+		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
+		.driver_data = APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
+		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
+		.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 6f3289a..2f855b1 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -361,7 +361,7 @@
 
 	case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
 		parser->global.report_size = item_udata(item);
-		if (parser->global.report_size > 32) {
+		if (parser->global.report_size > 96) {
 			dbg_hid("invalid report_size %d\n",
 					parser->global.report_size);
 			return -1;
@@ -1340,9 +1340,22 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
+ 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
@@ -1369,11 +1382,13 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
@@ -1395,6 +1410,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1707,8 +1723,8 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) },
@@ -1883,6 +1899,9 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
 	{ }
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index c946d90..e0a28ad 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -21,6 +21,7 @@
 #define USB_VENDOR_ID_3M		0x0596
 #define USB_DEVICE_ID_3M1968		0x0500
 #define USB_DEVICE_ID_3M2256		0x0502
+#define USB_DEVICE_ID_3M3266		0x0506
 
 #define USB_VENDOR_ID_A4TECH		0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
@@ -109,9 +110,22 @@
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI	0x0245
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO	0x0246
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS	0x0247
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI	0x0249
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO	0x024a
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS	0x024b
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI	0x024c
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO	0x024d
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS	0x024e
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI	0x024f
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO	0x0250
+#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS	0x0251
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI	0x0252
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO	0x0253
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS	0x0254
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL	0x8241
@@ -217,11 +231,14 @@
 
 #define USB_VENDOR_ID_DWAV		0x0eef
 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER	0x0001
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH	0x480d
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1	0x720c
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2	0x72a1
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3	0x480e
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4	0x726b
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D	0x480d
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E	0x480e
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C	0x720c
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B	0x726b
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1	0x72a1
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA	0x72fa
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302	0x7302
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001	0xa001
 
 #define USB_VENDOR_ID_ELECOM		0x056e
 #define USB_DEVICE_ID_ELECOM_BM084	0x0061
@@ -253,7 +270,7 @@
 #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR	0x0002
 
 #define USB_VENDOR_ID_GENERAL_TOUCH	0x0dfc
-#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0001
+#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003
 
 #define USB_VENDOR_ID_GLAB		0x06c2
 #define USB_DEVICE_ID_4_PHIDGETSERVO_30	0x0038
@@ -274,6 +291,7 @@
 #define USB_DEVICE_ID_PENPOWER		0x00f4
 
 #define USB_VENDOR_ID_GREENASIA		0x0e8f
+#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD	0x3013
 
 #define USB_VENDOR_ID_GRETAGMACBETH	0x0971
 #define USB_DEVICE_ID_GRETAGMACBETH_HUEY	0x2005
@@ -416,6 +434,9 @@
 #define USB_DEVICE_ID_LD_HYBRID		0x2090
 #define USB_DEVICE_ID_LD_HEATCONTROL	0x20A0
 
+#define USB_VENDOR_ID_LG		0x1fd2
+#define USB_DEVICE_ID_LG_MULTITOUCH	0x0064
+
 #define USB_VENDOR_ID_LOGITECH		0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 5de25ff..91319f9 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -603,6 +603,9 @@
 	{ .driver_data = MT_CLS_3M,
 		HID_USB_DEVICE(USB_VENDOR_ID_3M,
 			USB_DEVICE_ID_3M2256) },
+	{ .driver_data = MT_CLS_3M,
+		HID_USB_DEVICE(USB_VENDOR_ID_3M,
+			USB_DEVICE_ID_3M3266) },
 
 	/* ActionStar panels */
 	{ .driver_data = MT_CLS_DEFAULT,
@@ -639,23 +642,32 @@
 			USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
 
 	/* eGalax devices (resistive) */
-	{  .driver_data = MT_CLS_EGALAX,
+	{ .driver_data = MT_CLS_EGALAX,
 		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
-	{  .driver_data = MT_CLS_EGALAX,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
+	{ .driver_data = MT_CLS_EGALAX,
 		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
 
 	/* eGalax devices (capacitive) */
-	{  .driver_data = MT_CLS_EGALAX,
+	{ .driver_data = MT_CLS_EGALAX,
 		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
-	{  .driver_data = MT_CLS_EGALAX,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
+	{ .driver_data = MT_CLS_EGALAX,
 		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
-	{  .driver_data = MT_CLS_EGALAX,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
+	{ .driver_data = MT_CLS_EGALAX,
 		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
 
 	/* Elo TouchSystems IntelliTouch Plus panel */
 	{ .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
@@ -682,6 +694,11 @@
 		HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
 			USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
 
+	/* LG Display panels */
+	{ .driver_data = MT_CLS_DEFAULT,
+		HID_USB_DEVICE(USB_VENDOR_ID_LG,
+			USB_DEVICE_ID_LG_MULTITOUCH) },
+
 	/* Lumio panels */
 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
 		HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 4bdb5d4..3146fdc 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -47,6 +47,7 @@
 	{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
 
 	{ USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 	{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a0f4669..36c370e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -797,6 +797,14 @@
 	  The driver supports reading the HKADC, XOADC and support to set and receive
 	  temperature threshold notifications using the Battery temperature module.
 
+config SENSORS_EPM_ADC
+	tristate "EPM ADC Driver for power measurement"
+	depends on I2C && SPI_MASTER
+	default n
+	help
+	  Provides interface for measuring the current on specific power rails
+	  through the channels on ADC1158 ADC
+
 config SENSORS_PC87360
 	tristate "National Semiconductor PC87360 family"
 	select HWMON_VID
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 137f469..4a3de1a 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -121,6 +121,7 @@
 obj-$(CONFIG_SENSORS_WPCE775X)	+= wpce775x.o
 obj-$(CONFIG_SENSORS_MSM_ADC)	+= msm_adc.o m_adcproc.o
 obj-$(CONFIG_SENSORS_PM8XXX_ADC)	+= pm8xxx-adc.o pm8xxx-adc-scale.o
+obj-$(CONFIG_SENSORS_EPM_ADC)	+= epm_adc.o
 
 # PMBus drivers
 obj-$(CONFIG_PMBUS)		+= pmbus_core.o
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 0070d54..6163cfa 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -50,14 +50,13 @@
 #ifdef CONFIG_SMP
 #define TO_PHYS_ID(cpu)		cpu_data(cpu).phys_proc_id
 #define TO_CORE_ID(cpu)		cpu_data(cpu).cpu_core_id
-#define TO_ATTR_NO(cpu)		(TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO)
 #define for_each_sibling(i, cpu)	for_each_cpu(i, cpu_sibling_mask(cpu))
 #else
 #define TO_PHYS_ID(cpu)		(cpu)
 #define TO_CORE_ID(cpu)		(cpu)
-#define TO_ATTR_NO(cpu)		(cpu)
 #define for_each_sibling(i, cpu)	for (i = 0; false; )
 #endif
+#define TO_ATTR_NO(cpu)		(TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO)
 
 /*
  * Per-Core Temperature Data
@@ -540,6 +539,8 @@
 		return;
 
 	pdata = platform_get_drvdata(pdev);
+	if (!pdata)
+		return;
 
 	err = create_core_data(pdata, pdev, cpu, pkg_flag);
 	if (err)
@@ -746,6 +747,8 @@
 		return;
 
 	pdata = platform_get_drvdata(pdev);
+	if (!pdata)
+		return;
 
 	indx = TO_ATTR_NO(cpu);
 
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
new file mode 100644
index 0000000..daa0b58
--- /dev/null
+++ b/drivers/hwmon/epm_adc.c
@@ -0,0 +1,916 @@
+/* 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/init.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/hwmon.h>
+#include <linux/delay.h>
+#include <linux/epm_adc.h>
+#include <linux/uaccess.h>
+#include <linux/spi/spi.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+
+#define EPM_ADC_DRIVER_NAME		"epm_adc"
+#define EPM_ADC_MAX_FNAME		20
+#define EPM_ADC_CONVERSION_DELAY	100 /* milliseconds */
+/* Command Bits */
+#define EPM_ADC_ADS_SPI_BITS_PER_WORD	8
+#define EPM_ADC_ADS_DATA_READ_CMD	(0x1 << 5)
+#define EPM_ADC_ADS_REG_READ_CMD	(0x2 << 5)
+#define EPM_ADC_ADS_REG_WRITE_CMD	(0x3 << 5)
+#define EPM_ADC_ADS_PULSE_CONVERT_CMD	(0x4 << 5)
+#define EPM_ADC_ADS_MULTIPLE_REG_ACCESS	(0x1 << 4)
+/* Register map */
+#define EPM_ADC_ADS_CONFIG0_REG_ADDR	0x0
+#define EPM_ADC_ADS_CONFIG1_REG_ADDR	0x1
+#define EPM_ADC_ADS_MUXSG0_REG_ADDR	0x4
+#define EPM_ADC_ADS_MUXSG1_REG_ADDR	0x5
+/* Register map default data */
+#define EPM_ADC_ADS_REG0_DEFAULT	0x2
+#define EPM_ADC_ADS_REG1_DEFAULT	0x52
+#define EPM_ADC_ADS_CHANNEL_DATA_CHID	0x1f
+/* Channel ID */
+#define EPM_ADC_ADS_CHANNEL_OFFSET	0x18
+#define EPM_ADC_ADS_CHANNEL_VCC		0x1a
+#define EPM_ADC_ADS_CHANNEL_TEMP	0x1b
+#define EPM_ADC_ADS_CHANNEL_GAIN	0x1c
+#define EPM_ADC_ADS_CHANNEL_REF		0x1d
+/* Scaling data co-efficients */
+#define EPM_ADC_SCALE_MILLI		1000
+#define EPM_ADC_SCALE_CODE_VOLTS	3072
+#define EPM_ADC_SCALE_CODE_GAIN		30720
+#define EPM_ADC_TEMP_SENSOR_COEFF	394
+#define EPM_ADC_TEMP_TO_DEGC_COEFF	168000
+#define EPM_ADC_CHANNEL_AIN_OFFSET	8
+#define EPM_ADC_MAX_NEGATIVE_SCALE_CODE	0x8000
+#define EPM_ADC_NEG_LSB_CODE		0xffff
+#define EPM_ADC_VREF_CODE		0x7800
+#define EPM_ADC_MILLI_VOLTS_SOURCE	4750
+#define EPM_ADC_SCALE_FACTOR		64
+#define GPIO_EPM_GLOBAL_ENABLE		86
+#define EPM_ADC_CONVERSION_TIME_MIN	50000
+#define EPM_ADC_CONVERSION_TIME_MAX	51000
+
+struct epm_adc_drv {
+	struct platform_device		*pdev;
+	struct device			*hwmon;
+	struct sensor_device_attribute	*sens_attr;
+	char				**fnames;
+	struct spi_device		*epm_spi_client;
+	struct mutex			conv_lock;
+	uint32_t			bus_id;
+	struct miscdevice		misc;
+};
+
+static struct epm_adc_drv *epm_adc_drv;
+static struct i2c_board_info *epm_i2c_info;
+static bool epm_adc_first_request;
+static int epm_gpio_expander_base_addr;
+static bool epm_adc_expander_register;
+
+#define GPIO_EPM_EXPANDER_IO0	epm_gpio_expander_base_addr
+#define GPIO_PWR_MON_ENABLE	(GPIO_EPM_EXPANDER_IO0 + 1)
+#define GPIO_ADC1_PWDN_N	(GPIO_PWR_MON_ENABLE + 1)
+#define GPIO_PWR_MON_RESET_N	(GPIO_ADC1_PWDN_N + 1)
+#define GPIO_EPM_SPI_ADC1_CS_N	(GPIO_PWR_MON_RESET_N + 1)
+#define GPIO_PWR_MON_START	(GPIO_EPM_SPI_ADC1_CS_N + 1)
+#define GPIO_ADC1_DRDY_N	(GPIO_PWR_MON_START + 1)
+#define GPIO_ADC2_PWDN_N	(GPIO_ADC1_DRDY_N + 1)
+#define GPIO_EPM_SPI_ADC2_CS_N	(GPIO_ADC2_PWDN_N + 1)
+#define GPIO_ADC2_DRDY_N	(GPIO_EPM_SPI_ADC2_CS_N + 1)
+
+static int epm_adc_i2c_expander_register(void)
+{
+	int rc = 0;
+	static struct i2c_adapter *i2c_adap;
+	static struct i2c_client *epm_i2c_client;
+
+	rc = gpio_request(GPIO_EPM_GLOBAL_ENABLE, "EPM_GLOBAL_EN");
+	if (!rc) {
+		gpio_direction_output(GPIO_EPM_GLOBAL_ENABLE, 1);
+	} else {
+		pr_err("%s: Configure EPM_GLOBAL_EN Failed\n", __func__);
+		return rc;
+	}
+
+	usleep_range(EPM_ADC_CONVERSION_TIME_MIN,
+			EPM_ADC_CONVERSION_TIME_MAX);
+
+	i2c_adap = i2c_get_adapter(epm_adc_drv->bus_id);
+	if (i2c_adap == NULL) {
+		pr_err("%s: i2c_get_adapter() failed\n", __func__);
+		return -EINVAL;
+	}
+
+	usleep_range(EPM_ADC_CONVERSION_TIME_MIN,
+			EPM_ADC_CONVERSION_TIME_MAX);
+
+	epm_i2c_client = i2c_new_device(i2c_adap, epm_i2c_info);
+	if (IS_ERR(epm_i2c_client)) {
+		pr_err("Error with i2c epm device register\n");
+		return -ENODEV;
+	}
+
+	epm_adc_first_request = false;
+
+	return 0;
+}
+
+static int epm_adc_gpio_configure_expander_enable(void)
+{
+	int rc = 0;
+
+	if (epm_adc_first_request) {
+		rc = gpio_request(GPIO_EPM_GLOBAL_ENABLE, "EPM_GLOBAL_EN");
+		if (!rc) {
+			gpio_direction_output(GPIO_EPM_GLOBAL_ENABLE, 1);
+		} else {
+			pr_err("%s: Configure EPM_GLOBAL_EN Failed\n",
+								__func__);
+			return rc;
+		}
+	} else {
+		epm_adc_first_request = true;
+	}
+
+	usleep_range(EPM_ADC_CONVERSION_TIME_MIN,
+			EPM_ADC_CONVERSION_TIME_MAX);
+
+	rc = gpio_request(GPIO_PWR_MON_ENABLE, "GPIO_PWR_MON_ENABLE");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_PWR_MON_ENABLE, 1);
+		if (rc) {
+			pr_err("%s: Set GPIO_PWR_MON_ENABLE failed\n",
+					__func__);
+			return rc;
+		}
+	} else {
+		pr_err("%s: gpio_request GPIO_PWR_MON_ENABLE failed\n",
+				__func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_ADC1_PWDN_N, "GPIO_ADC1_PWDN_N");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_ADC1_PWDN_N, 1);
+		if (rc) {
+			pr_err("%s: Set GPIO_ADC1_PWDN_N failed\n", __func__);
+			return rc;
+		}
+	} else {
+		pr_err("%s: gpio_request GPIO_ADC1_PWDN_N failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_ADC2_PWDN_N, "GPIO_ADC2_PWDN_N");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_ADC2_PWDN_N, 1);
+		if (rc) {
+			pr_err("%s: Set GPIO_ADC2_PWDN_N failed\n",
+					__func__);
+			return rc;
+		}
+	} else {
+		pr_err("%s: gpio_request GPIO_ADC2_PWDN_N failed\n",
+				__func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_EPM_SPI_ADC1_CS_N, "GPIO_EPM_SPI_ADC1_CS_N");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC1_CS_N, 1);
+		if (rc) {
+			pr_err("%s:Set GPIO_EPM_SPI_ADC1_CS_N failed\n",
+					__func__);
+			return rc;
+		}
+	} else {
+		pr_err("%s: gpio_request GPIO_EPM_SPI_ADC1_CS_N failed\n",
+				__func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_EPM_SPI_ADC2_CS_N,
+			"GPIO_EPM_SPI_ADC2_CS_N");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC2_CS_N, 1);
+		if (rc) {
+			pr_err("%s: Set GPIO_EPM_SPI_ADC2_CS_N "
+					"failed\n", __func__);
+			return rc;
+		}
+	} else {
+		pr_err("%s: gpio_request GPIO_EPM_SPI_ADC2_CS_N "
+				"failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_direction_output(GPIO_EPM_SPI_ADC1_CS_N, 0);
+	if (rc) {
+		pr_err("%s:Reset GPIO_EPM_SPI_ADC1_CS_N failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_direction_output(GPIO_EPM_SPI_ADC1_CS_N, 1);
+	if (rc) {
+		pr_err("%s: Set GPIO_EPM_SPI_ADC1_CS_N failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_PWR_MON_START, "GPIO_PWR_MON_START");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_PWR_MON_START, 0);
+		if (rc) {
+			pr_err("%s: Reset GPIO_PWR_MON_START failed\n",
+					__func__);
+			return rc;
+		}
+	} else {
+		pr_err("%s: gpio_request GPIO_PWR_MON_START failed\n",
+				__func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_PWR_MON_RESET_N, "GPIO_PWR_MON_RESET_N");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_PWR_MON_RESET_N, 0);
+		if (rc) {
+			pr_err("%s: Reset GPIO_PWR_MON_RESET_N failed\n",
+					__func__);
+			return rc;
+		}
+	} else {
+		pr_err("%s: gpio_request GPIO_PWR_MON_RESET_N failed\n",
+				__func__);
+		return rc;
+	}
+
+	rc = gpio_direction_output(GPIO_PWR_MON_RESET_N, 1);
+	if (rc) {
+		pr_err("%s: Set GPIO_PWR_MON_RESET_N failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_direction_output(GPIO_EPM_SPI_ADC1_CS_N, 0);
+	if (rc) {
+		pr_err("%s:Reset GPIO_EPM_SPI_ADC1_CS_N failed\n", __func__);
+		return rc;
+	}
+	return rc;
+}
+
+static int epm_adc_gpio_configure_expander_disable(void)
+{
+	int rc = 0;
+	gpio_free(GPIO_PWR_MON_ENABLE);
+	gpio_free(GPIO_ADC1_PWDN_N);
+	gpio_free(GPIO_ADC2_PWDN_N);
+	gpio_free(GPIO_EPM_SPI_ADC1_CS_N);
+	gpio_free(GPIO_EPM_SPI_ADC2_CS_N);
+	gpio_free(GPIO_PWR_MON_START);
+	gpio_free(GPIO_PWR_MON_RESET_N);
+	rc = gpio_direction_output(GPIO_EPM_GLOBAL_ENABLE, 0);
+	if (rc)
+		pr_debug("%s: Disable EPM_GLOBAL_EN Failed\n", __func__);
+	gpio_free(GPIO_EPM_GLOBAL_ENABLE);
+	return rc;
+}
+
+static int epm_adc_spi_chip_select(int32_t id)
+{
+	int rc = 0;
+	if (id == 0) {
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC2_CS_N, 1);
+		if (rc) {
+			pr_err("%s:Disable SPI_ADC2_CS failed",
+					__func__);
+			return rc;
+		}
+
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC1_CS_N, 0);
+		if (rc) {
+			pr_err("%s:Enable SPI_ADC1_CS failed", __func__);
+			return rc;
+		}
+	} else if (id == 1) {
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC1_CS_N, 1);
+		if (rc) {
+			pr_err("%s:Disable SPI_ADC1_CS failed", __func__);
+			return rc;
+		}
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC2_CS_N, 0);
+		if (rc) {
+			pr_err("%s:Enable SPI_ADC2_CS failed", __func__);
+			return rc;
+		}
+	} else {
+		rc = -EFAULT;
+	}
+	return rc;
+}
+
+static int epm_adc_ads_spi_write(struct epm_adc_drv *epm_adc,
+		uint8_t addr, uint8_t val)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[2];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = EPM_ADC_ADS_REG_WRITE_CMD | addr;
+	tx_buf[1] = val;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+
+	return rc;
+}
+
+static int epm_adc_init_ads(struct epm_adc_drv *epm_adc)
+{
+	int rc = 0;
+
+	rc = epm_adc_ads_spi_write(epm_adc, EPM_ADC_ADS_CONFIG0_REG_ADDR,
+						EPM_ADC_ADS_REG0_DEFAULT);
+	if (rc)
+		return rc;
+
+	rc = epm_adc_ads_spi_write(epm_adc, EPM_ADC_ADS_CONFIG1_REG_ADDR,
+						EPM_ADC_ADS_REG1_DEFAULT);
+	if (rc)
+		return rc;
+	return rc;
+}
+
+static int epm_adc_ads_pulse_convert(struct epm_adc_drv *epm_adc)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[1];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = EPM_ADC_ADS_PULSE_CONVERT_CMD;
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+
+	return rc;
+}
+
+static int epm_adc_ads_read_data(struct epm_adc_drv *epm_adc, char *adc_data)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[4], rx_buf[4];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = EPM_ADC_ADS_DATA_READ_CMD |
+			EPM_ADC_ADS_MULTIPLE_REG_ACCESS;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	adc_data[0] = rx_buf[1];
+	adc_data[1] = rx_buf[2];
+	adc_data[2] = rx_buf[3];
+
+	return rc;
+}
+
+static int epm_adc_hw_init(struct epm_adc_drv *epm_adc)
+{
+	int rc = 0;
+
+	mutex_lock(&epm_adc->conv_lock);
+	rc = epm_adc_gpio_configure_expander_enable();
+	if (rc != 0) {
+		pr_err("epm gpio configure expander failed, rc = %d\n", rc);
+		goto epm_adc_hw_init_err;
+	}
+	rc = epm_adc_init_ads(epm_adc);
+	if (rc) {
+		pr_err("epm_adc_init_ads failed, rc=%d\n", rc);
+		goto epm_adc_hw_init_err;
+	}
+
+epm_adc_hw_init_err:
+	mutex_unlock(&epm_adc->conv_lock);
+	return rc;
+}
+
+static int epm_adc_hw_deinit(struct epm_adc_drv *epm_adc)
+{
+	int rc = 0;
+
+	mutex_lock(&epm_adc->conv_lock);
+	rc = epm_adc_gpio_configure_expander_disable();
+	if (rc != 0) {
+		pr_err("epm gpio configure expander disable failed,"
+			" rc = %d\n", rc);
+		goto epm_adc_hw_deinit_err;
+	}
+
+epm_adc_hw_deinit_err:
+	mutex_unlock(&epm_adc->conv_lock);
+	return rc;
+}
+
+static int epm_adc_ads_scale_result(struct epm_adc_drv *epm_adc,
+		uint8_t *adc_raw_data, struct epm_chan_request *conv)
+{
+	uint32_t channel_num;
+	int16_t  sign_bit;
+	struct epm_adc_platform_data *pdata = epm_adc->pdev->dev.platform_data;
+	uint32_t chan_idx = (conv->device_idx * pdata->chan_per_adc) +
+					conv->channel_idx;
+	int32_t *adc_scaled_data = &conv->physical;
+
+	/* Get the channel number */
+	channel_num = (adc_raw_data[0] & EPM_ADC_ADS_CHANNEL_DATA_CHID);
+	sign_bit    = 1;
+	/* This is the 16-bit raw data */
+	*adc_scaled_data = ((adc_raw_data[1] << 8) | adc_raw_data[2]);
+	/* Obtain the internal system reading */
+	if (channel_num == EPM_ADC_ADS_CHANNEL_VCC) {
+		*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+		*adc_scaled_data /= EPM_ADC_SCALE_CODE_VOLTS;
+	} else if (channel_num == EPM_ADC_ADS_CHANNEL_GAIN) {
+		*adc_scaled_data /= EPM_ADC_SCALE_CODE_GAIN;
+	} else if (channel_num == EPM_ADC_ADS_CHANNEL_REF) {
+		*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+		*adc_scaled_data /= EPM_ADC_SCALE_CODE_VOLTS;
+	} else if (channel_num == EPM_ADC_ADS_CHANNEL_TEMP) {
+		/* Convert Code to micro-volts */
+		/* Use this formula to get the temperature reading */
+		*adc_scaled_data -= EPM_ADC_TEMP_TO_DEGC_COEFF;
+		*adc_scaled_data /= EPM_ADC_TEMP_SENSOR_COEFF;
+	} else if (channel_num == EPM_ADC_ADS_CHANNEL_OFFSET) {
+		/* The offset should be zero */
+		pr_debug("%s: ADC Channel Offset\n", __func__);
+		return -EFAULT;
+	} else {
+		channel_num -= EPM_ADC_CHANNEL_AIN_OFFSET;
+		/*
+		 * Conversion for the adc channels.
+		 * mvVRef is in milli-volts and resistorValue is in micro-ohms.
+		 * Hence, I = V/R gives us current in kilo-amps.
+		 */
+		if (*adc_scaled_data & EPM_ADC_MAX_NEGATIVE_SCALE_CODE) {
+			sign_bit = -1;
+			*adc_scaled_data = (~*adc_scaled_data
+				& EPM_ADC_NEG_LSB_CODE);
+		}
+		if (*adc_scaled_data != 0) {
+			*adc_scaled_data *= EPM_ADC_SCALE_FACTOR;
+			 /* Device is calibrated for 1LSB = VREF/7800h.*/
+			*adc_scaled_data *= EPM_ADC_MILLI_VOLTS_SOURCE;
+			*adc_scaled_data /= EPM_ADC_VREF_CODE;
+			 /* Data will now be in micro-volts.*/
+			*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+			 /* Divide by amplifier gain value.*/
+			*adc_scaled_data /= pdata->channel[chan_idx].gain;
+			 /* Data will now be in nano-volts.*/
+			*adc_scaled_data /= EPM_ADC_SCALE_FACTOR;
+			*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+			 /* Data is now in micro-amps.*/
+			*adc_scaled_data /=
+				pdata->channel[chan_idx].resistorValue;
+			 /* Set the sign bit for lekage current. */
+			*adc_scaled_data *= sign_bit;
+		}
+	}
+	return 0;
+}
+
+static int epm_adc_blocking_conversion(struct epm_adc_drv *epm_adc,
+					struct epm_chan_request *conv)
+{
+	struct epm_adc_platform_data *pdata = epm_adc->pdev->dev.platform_data;
+	int32_t channel_num = 0, mux_chan_idx = 0;
+	char adc_data[3];
+	int rc = 0;
+
+	mutex_lock(&epm_adc->conv_lock);
+
+	rc = epm_adc_spi_chip_select(conv->device_idx);
+	if (rc) {
+		pr_err("epm_adc_chip_select failed, rc=%d\n", rc);
+		goto conv_err;
+	}
+
+	if (conv->channel_idx < pdata->chan_per_mux) {
+		/* Reset MUXSG1_REGISTER */
+		rc = epm_adc_ads_spi_write(epm_adc, EPM_ADC_ADS_MUXSG1_REG_ADDR,
+							0x0);
+		if (rc)
+			goto conv_err;
+
+		mux_chan_idx = 1 << conv->channel_idx;
+		/* Select Channel index in MUXSG0_REGISTER */
+		rc = epm_adc_ads_spi_write(epm_adc, EPM_ADC_ADS_MUXSG0_REG_ADDR,
+				mux_chan_idx);
+		if (rc)
+			goto conv_err;
+	} else {
+		/* Reset MUXSG0_REGISTER */
+		rc = epm_adc_ads_spi_write(epm_adc, EPM_ADC_ADS_MUXSG0_REG_ADDR,
+							0x0);
+		if (rc)
+			goto conv_err;
+
+		mux_chan_idx = 1 << (conv->channel_idx - pdata->chan_per_mux);
+		/* Select Channel index in MUXSG1_REGISTER */
+		rc = epm_adc_ads_spi_write(epm_adc, EPM_ADC_ADS_MUXSG1_REG_ADDR,
+				mux_chan_idx);
+		if (rc)
+			goto conv_err;
+	}
+
+	rc = epm_adc_ads_pulse_convert(epm_adc);
+	if (rc) {
+		pr_err("epm_adc_ads_pulse_convert failed, rc=%d\n", rc);
+		goto conv_err;
+	}
+
+	rc = epm_adc_ads_read_data(epm_adc, adc_data);
+	if (rc) {
+		pr_err("epm_adc_ads_read_data failed, rc=%d\n", rc);
+		goto conv_err;
+	}
+
+	channel_num = (adc_data[0] & EPM_ADC_ADS_CHANNEL_DATA_CHID);
+	pr_debug("ADC data Read: adc_data =%d, %d, %d\n",
+			adc_data[0], adc_data[1], adc_data[2]);
+
+	epm_adc_ads_scale_result(epm_adc, (uint8_t *)adc_data, conv);
+
+	pr_debug("channel_num(0x) = %x, scaled_data = %d\n",
+		 (channel_num - EPM_ADC_ADS_SPI_BITS_PER_WORD),
+						conv->physical);
+conv_err:
+	mutex_unlock(&epm_adc->conv_lock);
+	return rc;
+}
+
+static long epm_adc_ioctl(struct file *file, unsigned int cmd,
+						unsigned long arg)
+{
+	struct epm_adc_drv *epm_adc = epm_adc_drv;
+
+	switch (cmd) {
+	case EPM_ADC_REQUEST:
+		{
+			struct epm_chan_request conv;
+			int rc;
+
+			if (copy_from_user(&conv, (void __user *)arg,
+					sizeof(struct epm_chan_request)))
+				return -EFAULT;
+
+			rc = epm_adc_blocking_conversion(epm_adc, &conv);
+			if (rc) {
+				pr_err("Failed EPM conversion:%d\n", rc);
+				return rc;
+			}
+
+			if (copy_to_user((void __user *)arg, &conv,
+				sizeof(struct epm_chan_request)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_ADC_INIT:
+		{
+			uint32_t result;
+			if (!epm_adc_expander_register) {
+				result = epm_adc_i2c_expander_register();
+				if (result) {
+					pr_err("Failed i2c register:%d\n",
+								result);
+					return result;
+				}
+				epm_adc_expander_register = true;
+			}
+
+			result = epm_adc_hw_init(epm_adc_drv);
+
+			if (copy_to_user((void __user *)arg, &result,
+						sizeof(uint32_t)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_ADC_DEINIT:
+		{
+			uint32_t result;
+			result = epm_adc_hw_deinit(epm_adc_drv);
+
+			if (copy_to_user((void __user *)arg, &result,
+						sizeof(uint32_t)))
+				return -EFAULT;
+			break;
+		}
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+const struct file_operations epm_adc_fops = {
+	.unlocked_ioctl = epm_adc_ioctl,
+};
+
+static ssize_t epm_adc_show_in(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct epm_adc_drv *epm_adc = dev_get_drvdata(dev);
+	struct epm_adc_platform_data *pdata = epm_adc->pdev->dev.platform_data;
+	struct epm_chan_request conv;
+	int rc = 0;
+
+	conv.device_idx = attr->index / pdata->chan_per_adc;
+	conv.channel_idx = attr->index % pdata->chan_per_adc;
+	conv.physical = 0;
+	pr_debug("%s: device_idx=%d channel_idx=%d", __func__, conv.device_idx,
+			conv.channel_idx);
+	if (!epm_adc_expander_register) {
+		rc = epm_adc_i2c_expander_register();
+		if (rc) {
+			pr_err("I2C expander register failed:%d\n", rc);
+			return rc;
+		}
+		epm_adc_expander_register = true;
+	}
+
+	rc = epm_adc_hw_init(epm_adc);
+	if (rc) {
+		pr_err("%s: epm_adc_hw_init() failed, rc = %d",
+			__func__, rc);
+		return 0;
+	}
+
+	rc = epm_adc_blocking_conversion(epm_adc, &conv);
+	if (rc) {
+		pr_err("%s: epm_adc_blocking_conversion() failed, rc = %d\n",
+			__func__, rc);
+		return 0;
+	}
+	rc = epm_adc_hw_deinit(epm_adc);
+	if (rc) {
+		pr_err("%s: epm_adc_hw_deinit() failed, rc = %d",
+			__func__, rc);
+		return 0;
+	}
+
+	return snprintf(buf, 16, "Result: %d\n", conv.physical);
+}
+
+static struct sensor_device_attribute epm_adc_in_attr =
+	SENSOR_ATTR(NULL, S_IRUGO, epm_adc_show_in, NULL, 0);
+
+static int __devinit epm_adc_init_hwmon(struct platform_device *pdev,
+					       struct epm_adc_drv *epm_adc)
+{
+	struct epm_adc_platform_data *pdata = pdev->dev.platform_data;
+	int num_chans = pdata->num_channels, dev_idx = 0, chan_idx = 0;
+	int i = 0, rc = 0;
+	const char prefix[] = "ads", postfix[] = "_chan";
+	char tmpbuf[3];
+
+	epm_adc->fnames = devm_kzalloc(&pdev->dev,
+				num_chans * EPM_ADC_MAX_FNAME +
+				num_chans * sizeof(char *), GFP_KERNEL);
+	if (!epm_adc->fnames) {
+		dev_err(&pdev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	epm_adc->sens_attr = devm_kzalloc(&pdev->dev, num_chans *
+			    sizeof(struct sensor_device_attribute), GFP_KERNEL);
+	if (!epm_adc->sens_attr) {
+		dev_err(&pdev->dev, "Unable to allocate memory\n");
+		rc = -ENOMEM;
+	}
+
+	for (i = 0; i < num_chans; i++, chan_idx++) {
+		epm_adc->fnames[i] = (char *)epm_adc->fnames +
+			(i * EPM_ADC_MAX_FNAME) + (num_chans *
+			sizeof(char *));
+		if (chan_idx == pdata->chan_per_adc) {
+			chan_idx = 0;
+			dev_idx++;
+		}
+		strlcpy(epm_adc->fnames[i], prefix, EPM_ADC_MAX_FNAME);
+		snprintf(tmpbuf, sizeof(tmpbuf), "%d", dev_idx);
+		strlcat(epm_adc->fnames[i], tmpbuf, EPM_ADC_MAX_FNAME);
+		strlcat(epm_adc->fnames[i], postfix, EPM_ADC_MAX_FNAME);
+		snprintf(tmpbuf, sizeof(tmpbuf), "%d", chan_idx);
+		strlcat(epm_adc->fnames[i], tmpbuf, EPM_ADC_MAX_FNAME);
+		epm_adc_in_attr.index = i;
+		epm_adc_in_attr.dev_attr.attr.name = epm_adc->fnames[i];
+		memcpy(&epm_adc->sens_attr[i], &epm_adc_in_attr,
+						sizeof(epm_adc_in_attr));
+		rc = device_create_file(&pdev->dev,
+				&epm_adc->sens_attr[i].dev_attr);
+		if (rc) {
+			dev_err(&pdev->dev, "device_create_file failed\n");
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int __devinit epm_adc_spi_probe(struct spi_device *spi)
+
+{
+	if (!epm_adc_drv)
+		return -ENODEV;
+	epm_adc_drv->epm_spi_client = spi;
+	epm_adc_drv->epm_spi_client->bits_per_word =
+				EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	return 0;
+}
+
+static int __devexit epm_adc_spi_remove(struct spi_device *spi)
+{
+	epm_adc_drv->epm_spi_client = NULL;
+	return 0;
+}
+
+static struct spi_driver epm_spi_driver = {
+	.probe = epm_adc_spi_probe,
+	.remove = __devexit_p(epm_adc_spi_remove),
+	.driver = {
+		.name = EPM_ADC_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int epm_adc_probe(struct platform_device *pdev)
+{
+	struct epm_adc_drv *epm_adc;
+	struct epm_adc_platform_data *pdata = pdev->dev.platform_data;
+	int rc = 0;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data?\n");
+		return -EINVAL;
+	}
+
+	epm_adc = kzalloc(sizeof(struct epm_adc_drv), GFP_KERNEL);
+	if (!epm_adc) {
+		dev_err(&pdev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, epm_adc);
+	epm_adc_drv = epm_adc;
+	epm_adc->pdev = pdev;
+
+	epm_adc->misc.name = EPM_ADC_DRIVER_NAME;
+	epm_adc->misc.minor = MISC_DYNAMIC_MINOR;
+	epm_adc->misc.fops = &epm_adc_fops;
+
+	if (misc_register(&epm_adc->misc)) {
+		dev_err(&pdev->dev, "Unable to register misc device!\n");
+		return -EFAULT;
+	}
+
+	rc = epm_adc_init_hwmon(pdev, epm_adc);
+	if (rc) {
+		dev_err(&pdev->dev, "msm_adc_dev_init failed\n");
+		misc_deregister(&epm_adc->misc);
+		return rc;
+	}
+
+	epm_adc->hwmon = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(epm_adc->hwmon)) {
+		dev_err(&pdev->dev, "hwmon_device_register failed\n");
+		misc_deregister(&epm_adc->misc);
+		rc = PTR_ERR(epm_adc->hwmon);
+		return rc;
+	}
+
+	mutex_init(&epm_adc->conv_lock);
+	epm_i2c_info = &pdata->epm_i2c_board_info;
+	epm_adc->bus_id = pdata->bus_id;
+	epm_gpio_expander_base_addr = pdata->gpio_expander_base_addr;
+	epm_adc_expander_register = false;
+	return rc;
+}
+
+static int __devexit epm_adc_remove(struct platform_device *pdev)
+{
+	struct epm_adc_drv *epm_adc = platform_get_drvdata(pdev);
+	struct epm_adc_platform_data *pdata = pdev->dev.platform_data;
+	int num_chans = pdata->num_channels;
+	int i = 0;
+
+	if (epm_adc->sens_attr)
+		for (i = 0; i < num_chans; i++)
+			device_remove_file(&pdev->dev,
+					&epm_adc->sens_attr[i].dev_attr);
+	hwmon_device_unregister(epm_adc->hwmon);
+	misc_deregister(&epm_adc->misc);
+	epm_adc = NULL;
+
+	return 0;
+}
+
+static struct platform_driver epm_adc_driver = {
+	.probe = epm_adc_probe,
+	.remove = __devexit_p(epm_adc_remove),
+	.driver = {
+		.name = EPM_ADC_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init epm_adc_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&epm_adc_driver);
+	if (ret) {
+		pr_err("%s: driver register failed, rc=%d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = spi_register_driver(&epm_spi_driver);
+	if (ret)
+		pr_err("%s: spi register failed: rc=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static void __exit epm_adc_exit(void)
+{
+	spi_unregister_driver(&epm_spi_driver);
+	platform_driver_unregister(&epm_adc_driver);
+}
+
+module_init(epm_adc_init);
+module_exit(epm_adc_exit);
+
+MODULE_DESCRIPTION("EPM ADC Driver");
+MODULE_ALIAS("platform:epm_adc");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 92f9497..6dbfd3e 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -283,11 +283,11 @@
 
 static inline u8 temp_to_reg(long val)
 {
-	if (val < 0)
-		val = 0;
-	else if (val > 1000 * 0xff)
-		val = 0xff;
-	return ((val + 500) / 1000);
+	if (val <= 0)
+		return 0;
+	if (val >= 1000 * 0xff)
+		return 0xff;
+	return (val + 500) / 1000;
 }
 
 /*
diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c
index fea292d..b65a4da 100644
--- a/drivers/hwmon/jz4740-hwmon.c
+++ b/drivers/hwmon/jz4740-hwmon.c
@@ -59,7 +59,7 @@
 {
 	struct jz4740_hwmon *hwmon = dev_get_drvdata(dev);
 	struct completion *completion = &hwmon->read_completion;
-	unsigned long t;
+	long t;
 	unsigned long val;
 	int ret;
 
diff --git a/drivers/hwmon/msm_adc.c b/drivers/hwmon/msm_adc.c
index b8d581e..39bfc3a 100644
--- a/drivers/hwmon/msm_adc.c
+++ b/drivers/hwmon/msm_adc.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
@@ -1380,7 +1380,7 @@
 	},
 };
 
-static int msm_adc_probe(struct platform_device *pdev)
+static int __devinit msm_adc_probe(struct platform_device *pdev)
 {
 	struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
 	struct msm_adc_drv *msm_adc;
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 5f8faee..2f59235 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -131,7 +131,6 @@
 	struct mutex				adc_lock;
 	struct mutex				mpp_adc_lock;
 	spinlock_t				btm_lock;
-	uint32_t				adc_num_channel;
 	uint32_t				adc_num_board_channel;
 	struct completion			adc_rslt_completion;
 	struct pm8xxx_adc_amux			*adc_channel;
@@ -165,6 +164,7 @@
 };
 
 static struct pm8xxx_adc *pmic_adc;
+static struct regulator *pa_therm;
 
 static struct pm8xxx_adc_scale_fn adc_scale_fn[] = {
 	[ADC_SCALE_DEFAULT] = {pm8xxx_adc_scale_default},
@@ -200,6 +200,17 @@
 static bool pm8xxx_adc_calib_first_adc;
 static bool pm8xxx_adc_initialized, pm8xxx_adc_calib_device_init;
 
+static int32_t pm8xxx_adc_check_channel_valid(uint32_t channel)
+{
+	if (channel < CHANNEL_VCOIN ||
+	(channel > CHANNEL_MUXOFF && channel < ADC_MPP_1_ATEST_8) ||
+	(channel > ADC_MPP_1_ATEST_7 && channel < ADC_MPP_2_ATEST_8)
+	|| (channel >= ADC_CHANNEL_MAX_NUM))
+		return -EBADF;
+	else
+		return 0;
+}
+
 static int32_t pm8xxx_adc_arb_cntrl(uint32_t arb_cntrl,
 					uint32_t channel)
 {
@@ -238,26 +249,21 @@
 
 static int32_t pm8xxx_adc_patherm_power(bool on)
 {
-	static struct regulator *pa_therm;
-	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	int rc = 0;
-	if (on) {
-		pa_therm = regulator_get(adc_pmic->dev,
-						"pa_therm");
-		if (IS_ERR(pa_therm)) {
-			rc = PTR_ERR(pa_therm);
-			pr_err("failed to request pa_therm vreg "
-					"with error %d\n", rc);
-			return rc;
-		}
 
+	if (!pa_therm) {
+		pr_err("pm8xxx adc pa_therm not valid\n");
+		return -EINVAL;
+	}
+
+	if (on) {
 		rc = regulator_set_voltage(pa_therm,
 				PM8XXX_ADC_PA_THERM_VREG_UV_MIN,
 				PM8XXX_ADC_PA_THERM_VREG_UV_MAX);
 		if (rc < 0) {
 			pr_err("failed to set the voltage for "
 					"pa_therm with error %d\n", rc);
-			goto fail;
+			return rc;
 		}
 
 		rc = regulator_set_optimum_mode(pa_therm,
@@ -265,25 +271,25 @@
 		if (rc < 0) {
 			pr_err("failed to set optimum mode for "
 					"pa_therm with error %d\n", rc);
-			goto fail;
+			return rc;
 		}
 
-		if (regulator_enable(pa_therm)) {
-			pr_err("failed to enable pa_therm vreg with "
-						"error %d\n", rc);
-			goto fail;
+		rc = regulator_enable(pa_therm);
+		if (rc < 0) {
+			pr_err("failed to enable pa_therm vreg "
+					"with error %d\n", rc);
+			return rc;
 		}
 	} else {
-		if (pa_therm != NULL) {
-			regulator_disable(pa_therm);
-			regulator_put(pa_therm);
+		rc = regulator_disable(pa_therm);
+		if (rc < 0) {
+			pr_err("failed to disable pa_therm vreg "
+					"with error %d\n", rc);
+			return rc;
 		}
 	}
 
 	return rc;
-fail:
-	regulator_put(pa_therm);
-	return rc;
 }
 
 static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
@@ -293,7 +299,7 @@
 
 	switch (channel)
 	case ADC_MPP_1_AMUX8:
-		pm8xxx_adc_patherm_power(power_cntrl);
+		rc = pm8xxx_adc_patherm_power(power_cntrl);
 
 	return rc;
 }
@@ -679,12 +685,13 @@
 
 	mutex_lock(&adc_pmic->adc_lock);
 
-	for (i = 0; i < adc_pmic->adc_num_channel; i++) {
+	for (i = 0; i < adc_pmic->adc_num_board_channel; i++) {
 		if (channel == adc_pmic->adc_channel[i].channel_name)
 			break;
 	}
 
-	if (i == adc_pmic->adc_num_channel) {
+	if (i == adc_pmic->adc_num_board_channel ||
+		(pm8xxx_adc_check_channel_valid(channel) != 0)) {
 		rc = -EBADF;
 		goto fail_unlock;
 	}
@@ -769,6 +776,9 @@
 	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	int rc = 0;
 
+	if (!pm8xxx_adc_initialized)
+		return -ENODEV;
+
 	if (!adc_pmic->mpp_base) {
 		rc = -EINVAL;
 		pr_info("PM8xxx MPP base invalid with error %d\n", rc);
@@ -1002,12 +1012,10 @@
 			struct device_attribute *devattr, char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	struct pm8xxx_adc_chan_result result;
 	int rc = -1;
 
-	if (attr->index < adc_pmic->adc_num_channel)
-		rc = pm8xxx_adc_read(attr->index, &result);
+	rc = pm8xxx_adc_read(attr->index, &result);
 
 	if (rc)
 		return 0;
@@ -1077,9 +1085,14 @@
 static int32_t pm8xxx_adc_init_hwmon(struct platform_device *pdev)
 {
 	struct pm8xxx_adc *adc_pmic = pmic_adc;
-	int rc = 0, i;
+	int rc = 0, i, channel;
 
 	for (i = 0; i < pmic_adc->adc_num_board_channel; i++) {
+		channel = adc_pmic->adc_channel[i].channel_name;
+		if (pm8xxx_adc_check_channel_valid(channel)) {
+			pr_err("Invalid ADC init HWMON channel: %d\n", channel);
+			continue;
+		}
 		pm8xxx_adc_attr.index = adc_pmic->adc_channel[i].channel_name;
 		pm8xxx_adc_attr.dev_attr.attr.name =
 						adc_pmic->adc_channel[i].name;
@@ -1138,6 +1151,10 @@
 	wake_lock_destroy(&adc_pmic->adc_wakelock);
 	platform_set_drvdata(pdev, NULL);
 	pmic_adc = NULL;
+	if (!pa_therm) {
+		regulator_put(pa_therm);
+		pa_therm = NULL;
+	}
 	for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
 		device_remove_file(adc_pmic->dev,
 				&adc_pmic->sens_attr[i].dev_attr);
@@ -1181,7 +1198,6 @@
 	init_completion(&adc_pmic->adc_rslt_completion);
 	adc_pmic->adc_channel = pdata->adc_channel;
 	adc_pmic->adc_num_board_channel = pdata->adc_num_board_channel;
-	adc_pmic->adc_num_channel = ADC_MPP_2_CHANNEL_NONE;
 	adc_pmic->mpp_base = pdata->adc_mpp_base;
 
 	mutex_init(&adc_pmic->adc_lock);
@@ -1252,6 +1268,13 @@
 		dev_err(&pdev->dev, "failed to initialize pm8xxx hwmon adc\n");
 	}
 	adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
+
+	pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
+	if (IS_ERR(pa_therm)) {
+		rc = PTR_ERR(pa_therm);
+		pr_err("failed to request pa_therm vreg with error %d\n", rc);
+		pa_therm = NULL;
+	}
 	return 0;
 }
 
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index cf4330b..9594cdb 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -883,7 +883,7 @@
 
 static int __devinit sht15_probe(struct platform_device *pdev)
 {
-	int ret = 0;
+	int ret;
 	struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
 	u8 status = 0;
 
@@ -901,6 +901,7 @@
 	init_waitqueue_head(&data->wait_queue);
 
 	if (pdev->dev.platform_data == NULL) {
+		ret = -EINVAL;
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		goto err_free_data;
 	}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 36d7f27..359bb1e 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -1295,6 +1295,7 @@
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	int nr = sensor_attr->index;
 	unsigned long val;
 	int err;
@@ -1306,6 +1307,11 @@
 
 	if (val > 1)
 		return -EINVAL;
+
+	/* On NCT67766F, DC mode is only supported for pwm1 */
+	if (sio_data->kind == nct6776 && nr && val != 1)
+		return -EINVAL;
+
 	mutex_lock(&data->update_lock);
 	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
 	data->pwm_mode[nr] = val;
@@ -1756,7 +1762,17 @@
 		diode = 0x70;
 	}
 	for (i = 0; i < 3; i++) {
-		if ((tmp & (0x02 << i)))
+		const char *label = NULL;
+
+		if (data->temp_label)
+			label = data->temp_label[data->temp_src[i]];
+
+		/* Digital source overrides analog type */
+		if (label && strncmp(label, "PECI", 4) == 0)
+			data->temp_type[i] = 6;
+		else if (label && strncmp(label, "AMD", 3) == 0)
+			data->temp_type[i] = 5;
+		else if ((tmp & (0x02 << i)))
 			data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
 		else
 			data->temp_type[i] = 4; /* thermistor */
@@ -2088,9 +2104,29 @@
 		fan4min = 0;
 		fan5pin = 0;
 	} else if (sio_data->kind == nct6776) {
-		fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
-		fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
-		fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
+		bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
+		u8 regval;
+
+		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+		regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
+
+		if (regval & 0x80)
+			fan3pin = gpok;
+		else
+			fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+
+		if (regval & 0x40)
+			fan4pin = gpok;
+		else
+			fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C)
+				     & 0x01);
+
+		if (regval & 0x20)
+			fan5pin = gpok;
+		else
+			fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C)
+				     & 0x02);
+
 		fan4min = fan4pin;
 	} else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
 		fan3pin = 1;
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 43a6271..12f7c83 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -26,6 +26,7 @@
 #include <linux/radix-tree.h>
 #include <linux/hwspinlock.h>
 #include <linux/pm_runtime.h>
+#include <linux/mutex.h>
 
 #include "hwspinlock_internal.h"
 
@@ -52,10 +53,12 @@
 static RADIX_TREE(hwspinlock_tree, GFP_KERNEL);
 
 /*
- * Synchronization of access to the tree is achieved using this spinlock,
+ * Synchronization of access to the tree is achieved using this mutex,
  * as the radix-tree API requires that users provide all synchronisation.
+ * A mutex is needed because we're using non-atomic radix tree allocations.
  */
-static DEFINE_SPINLOCK(hwspinlock_tree_lock);
+static DEFINE_MUTEX(hwspinlock_tree_lock);
+
 
 /**
  * __hwspin_trylock() - attempt to lock a specific hwspinlock
@@ -261,8 +264,7 @@
  * This function should be called from the underlying platform-specific
  * implementation, to register a new hwspinlock instance.
  *
- * Can be called from an atomic context (will not sleep) but not from
- * within interrupt context.
+ * Should be called from a process context (might sleep)
  *
  * Returns 0 on success, or an appropriate error code on failure
  */
@@ -279,7 +281,7 @@
 
 	spin_lock_init(&hwlock->lock);
 
-	spin_lock(&hwspinlock_tree_lock);
+	mutex_lock(&hwspinlock_tree_lock);
 
 	ret = radix_tree_insert(&hwspinlock_tree, hwlock->id, hwlock);
 	if (ret)
@@ -293,7 +295,7 @@
 	WARN_ON(tmp != hwlock);
 
 out:
-	spin_unlock(&hwspinlock_tree_lock);
+	mutex_unlock(&hwspinlock_tree_lock);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_register);
@@ -305,8 +307,7 @@
  * This function should be called from the underlying platform-specific
  * implementation, to unregister an existing (and unused) hwspinlock.
  *
- * Can be called from an atomic context (will not sleep) but not from
- * within interrupt context.
+ * Should be called from a process context (might sleep)
  *
  * Returns the address of hwspinlock @id on success, or NULL on failure
  */
@@ -315,7 +316,7 @@
 	struct hwspinlock *hwlock = NULL;
 	int ret;
 
-	spin_lock(&hwspinlock_tree_lock);
+	mutex_lock(&hwspinlock_tree_lock);
 
 	/* make sure the hwspinlock is not in use (tag is set) */
 	ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
@@ -331,7 +332,7 @@
 	}
 
 out:
-	spin_unlock(&hwspinlock_tree_lock);
+	mutex_unlock(&hwspinlock_tree_lock);
 	return hwlock;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
@@ -400,9 +401,7 @@
  * to the remote core before it can be used for synchronization (to get the
  * id of a given hwlock, use hwspin_lock_get_id()).
  *
- * Can be called from an atomic context (will not sleep) but not from
- * within interrupt context (simply because there is no use case for
- * that yet).
+ * Should be called from a process context (might sleep)
  *
  * Returns the address of the assigned hwspinlock, or NULL on error
  */
@@ -411,7 +410,7 @@
 	struct hwspinlock *hwlock;
 	int ret;
 
-	spin_lock(&hwspinlock_tree_lock);
+	mutex_lock(&hwspinlock_tree_lock);
 
 	/* look for an unused lock */
 	ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock,
@@ -431,7 +430,7 @@
 		hwlock = NULL;
 
 out:
-	spin_unlock(&hwspinlock_tree_lock);
+	mutex_unlock(&hwspinlock_tree_lock);
 	return hwlock;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_request);
@@ -445,9 +444,7 @@
  * Usually early board code will be calling this function in order to
  * reserve specific hwspinlock ids for predefined purposes.
  *
- * Can be called from an atomic context (will not sleep) but not from
- * within interrupt context (simply because there is no use case for
- * that yet).
+ * Should be called from a process context (might sleep)
  *
  * Returns the address of the assigned hwspinlock, or NULL on error
  */
@@ -456,7 +453,7 @@
 	struct hwspinlock *hwlock;
 	int ret;
 
-	spin_lock(&hwspinlock_tree_lock);
+	mutex_lock(&hwspinlock_tree_lock);
 
 	/* make sure this hwspinlock exists */
 	hwlock = radix_tree_lookup(&hwspinlock_tree, id);
@@ -482,7 +479,7 @@
 		hwlock = NULL;
 
 out:
-	spin_unlock(&hwspinlock_tree_lock);
+	mutex_unlock(&hwspinlock_tree_lock);
 	return hwlock;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
@@ -495,9 +492,7 @@
  * Should only be called with an @hwlock that was retrieved from
  * an earlier call to omap_hwspin_lock_request{_specific}.
  *
- * Can be called from an atomic context (will not sleep) but not from
- * within interrupt context (simply because there is no use case for
- * that yet).
+ * Should be called from a process context (might sleep)
  *
  * Returns 0 on success, or an appropriate error code on failure
  */
@@ -511,7 +506,7 @@
 		return -EINVAL;
 	}
 
-	spin_lock(&hwspinlock_tree_lock);
+	mutex_lock(&hwspinlock_tree_lock);
 
 	/* make sure the hwspinlock is used */
 	ret = radix_tree_tag_get(&hwspinlock_tree, hwlock->id,
@@ -538,7 +533,7 @@
 	module_put(hwlock->owner);
 
 out:
-	spin_unlock(&hwspinlock_tree_lock);
+	mutex_unlock(&hwspinlock_tree_lock);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_free);
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index d6d5868..eca3bcc 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -486,7 +486,7 @@
 
 	if (flags & I2C_M_TEN) {
 		/* a ten bit address */
-		addr = 0xf0 | ((msg->addr >> 7) & 0x03);
+		addr = 0xf0 | ((msg->addr >> 7) & 0x06);
 		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
 		/* try extended address code...*/
 		ret = try_address(i2c_adap, addr, retries);
@@ -496,7 +496,7 @@
 			return -EREMOTEIO;
 		}
 		/* the remaining 8 bit address */
-		ret = i2c_outb(i2c_adap, msg->addr & 0x7f);
+		ret = i2c_outb(i2c_adap, msg->addr & 0xff);
 		if ((ret != 1) && !nak_ok) {
 			/* the chip did not ack / xmission error occurred */
 			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index dd36417..cd7ac5c 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -140,7 +140,7 @@
    defined to make the transition easier. */
 static int __devinit ali1535_setup(struct pci_dev *dev)
 {
-	int retval = -ENODEV;
+	int retval;
 	unsigned char temp;
 
 	/* Check the following things:
@@ -155,6 +155,7 @@
 	if (ali1535_smba == 0) {
 		dev_warn(&dev->dev,
 			"ALI1535_smb region uninitialized - upgrade BIOS?\n");
+		retval = -ENODEV;
 		goto exit;
 	}
 
@@ -167,6 +168,7 @@
 			    ali1535_driver.name)) {
 		dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n",
 			ali1535_smba);
+		retval = -EBUSY;
 		goto exit;
 	}
 
@@ -174,6 +176,7 @@
 	pci_read_config_byte(dev, SMBCFG, &temp);
 	if ((temp & ALI1535_SMBIO_EN) == 0) {
 		dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n");
+		retval = -ENODEV;
 		goto exit_free;
 	}
 
@@ -181,6 +184,7 @@
 	pci_read_config_byte(dev, SMBHSTCFG, &temp);
 	if ((temp & 1) == 0) {
 		dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n");
+		retval = -ENODEV;
 		goto exit_free;
 	}
 
@@ -198,12 +202,11 @@
 	dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
 	dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba);
 
-	retval = 0;
-exit:
-	return retval;
+	return 0;
 
 exit_free:
 	release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+exit:
 	return retval;
 }
 
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 8abfa4a..656b028 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -242,7 +242,7 @@
 	if (pch_clk > PCH_MAX_CLK)
 		pch_clk = 62500;
 
-	pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / pch_i2c_speed * 8;
+	pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8);
 	/* Set transfer speed in I2CBC */
 	iowrite32(pch_i2cbc, p + PCH_I2CBC);
 
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index ff1e127..4853b52 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -356,7 +356,7 @@
 	error = acpi_check_region(smbus->base, smbus->size,
 				  nforce2_driver.name);
 	if (error)
-		return -1;
+		return error;
 
 	if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
 		dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 41bee16..84d33f8 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -235,7 +235,7 @@
 	[OMAP_I2C_BUF_REG] = 0x94,
 	[OMAP_I2C_CNT_REG] = 0x98,
 	[OMAP_I2C_DATA_REG] = 0x9c,
-	[OMAP_I2C_SYSC_REG] = 0x20,
+	[OMAP_I2C_SYSC_REG] = 0x10,
 	[OMAP_I2C_CON_REG] = 0xa4,
 	[OMAP_I2C_OA_REG] = 0xa8,
 	[OMAP_I2C_SA_REG] = 0xac,
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 4988313..195c99b 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -33,6 +33,8 @@
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
 
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.2");
@@ -759,16 +761,9 @@
 		return -EIO;
 	}
 
-	if (dev->clk_state == 0) {
-		if (dev->clk_ctl == 0) {
-			if (dev->pdata->src_clk_rate > 0)
-				clk_set_rate(dev->clk,
-						dev->pdata->src_clk_rate);
-			else
-				dev->pdata->src_clk_rate = 19200000;
-		}
+	if (dev->clk_state == 0)
 		qup_i2c_pwr_mgmt(dev, 1);
-	}
+
 	/* Initialize QUP registers during first transfer */
 	if (dev->clk_ctl == 0) {
 		int fs_div;
@@ -1101,7 +1096,24 @@
 	gsbi_mem = NULL;
 	dev_dbg(&pdev->dev, "qup_i2c_probe\n");
 
-	pdata = pdev->dev.platform_data;
+	if (pdev->dev.of_node) {
+		struct device_node *node = pdev->dev.of_node;
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+		ret = of_property_read_u32(node, "qcom,i2c-bus-freq",
+					&pdata->clk_freq);
+		if (ret)
+			goto get_res_failed;
+		ret = of_property_read_u32(node, "cell-index", &pdev->id);
+		if (ret)
+			goto get_res_failed;
+		/* Optional property */
+		of_property_read_u32(node, "qcom,i2c-src-freq",
+					&pdata->src_clk_rate);
+	} else
+		pdata = pdev->dev.platform_data;
+
 	if (!pdata) {
 		dev_err(&pdev->dev, "platform data not initialized\n");
 		return -ENOSYS;
@@ -1110,7 +1122,8 @@
 						"qup_phys_addr");
 	if (!qup_mem) {
 		dev_err(&pdev->dev, "no qup mem resource?\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto get_res_failed;
 	}
 
 	/*
@@ -1127,22 +1140,27 @@
 						"qup_err_intr");
 	if (!err_irq) {
 		dev_err(&pdev->dev, "no error irq resource?\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto get_res_failed;
 	}
 
 	qup_io = request_mem_region(qup_mem->start, resource_size(qup_mem),
 					pdev->name);
 	if (!qup_io) {
 		dev_err(&pdev->dev, "QUP region already claimed\n");
-		return -EBUSY;
+		ret = -EBUSY;
+		goto get_res_failed;
 	}
 	if (!pdata->use_gsbi_shared_mode) {
 		gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 							"gsbi_qup_i2c_addr");
 		if (!gsbi_mem) {
-			dev_err(&pdev->dev, "no gsbi mem resource?\n");
-			ret = -ENODEV;
-			goto err_res_failed;
+			dev_dbg(&pdev->dev, "Assume BLSP\n");
+			/*
+			 * BLSP core does not need protocol programming so this
+			 * resource is not expected
+			 */
+			goto blsp_core_init;
 		}
 		gsbi_io = request_mem_region(gsbi_mem->start,
 						resource_size(gsbi_mem),
@@ -1154,6 +1172,7 @@
 		}
 	}
 
+blsp_core_init:
 	clk = clk_get(&pdev->dev, "core_clk");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "Could not get core_clk\n");
@@ -1228,6 +1247,24 @@
 	dev->pos = 0;
 
 	/*
+	 * If bootloaders leave a pending interrupt on certain GSBI's,
+	 * then we reset the core before registering for interrupts.
+	 */
+
+	if (dev->pdata->src_clk_rate > 0)
+		clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
+	else
+		dev->pdata->src_clk_rate = 19200000;
+
+	clk_prepare_enable(dev->clk);
+	clk_prepare_enable(dev->pclk);
+	writel_relaxed(1, dev->base + QUP_SW_RESET);
+	if (qup_i2c_poll_state(dev, 0, true) != 0)
+		goto err_reset_failed;
+	clk_disable_unprepare(dev->clk);
+	clk_disable_unprepare(dev->pclk);
+
+	/*
 	 * We use num_irqs to also indicate if we got 3 interrupts or just 1.
 	 * If we have just 1, we use err_irq as the general purpose irq
 	 * and handle the changes in ISR accordingly
@@ -1300,14 +1337,20 @@
 			free_irq(dev->in_irq, dev);
 		}
 		free_irq(dev->err_irq, dev);
-	} else
+	} else {
+		if (dev->dev->of_node)
+			of_i2c_register_devices(&dev->adapter);
 		return 0;
+	}
 
 
 err_request_irq_failed:
 	qup_i2c_free_gpios(dev);
 	if (dev->gsbi)
 		iounmap(dev->gsbi);
+err_reset_failed:
+	clk_disable_unprepare(dev->clk);
+	clk_disable_unprepare(dev->pclk);
 err_request_gpio_failed:
 err_gsbi_failed:
 	iounmap(dev->base);
@@ -1322,6 +1365,9 @@
 		release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));
 err_res_failed:
 	release_mem_region(qup_mem->start, resource_size(qup_mem));
+get_res_failed:
+	if (pdev->dev.of_node)
+		kfree(pdata);
 	return ret;
 }
 
@@ -1365,6 +1411,8 @@
 	qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"qup_phys_addr");
 	release_mem_region(qup_mem->start, resource_size(qup_mem));
+	if (dev->dev->of_node)
+		kfree(dev->pdata);
 	kfree(dev);
 	return 0;
 }
@@ -1432,6 +1480,13 @@
 	)
 };
 
+static struct of_device_id i2c_qup_dt_match[] = {
+	{
+		.compatible = "qcom,i2c-qup",
+	},
+	{}
+};
+
 static struct platform_driver qup_i2c_driver = {
 	.probe		= qup_i2c_probe,
 	.remove		= __devexit_p(qup_i2c_remove),
@@ -1439,6 +1494,7 @@
 		.name	= "qup_i2c",
 		.owner	= THIS_MODULE,
 		.pm = &i2c_qup_dev_pm_ops,
+		.of_match_table = i2c_qup_dt_match,
 	},
 };
 
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 4375866..6d60284 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -147,7 +147,7 @@
 	u16 a;
 	u8 val;
 	int *i;
-	int retval = -ENODEV;
+	int retval;
 
 	/* Look for imposters */
 	for (i = blacklist; *i != 0; i++) {
@@ -223,7 +223,7 @@
 
 error:
 	release_region(sis5595_base + SMB_INDEX, 2);
-	return retval;
+	return -ENODEV;
 }
 
 static int sis5595_transaction(struct i2c_adapter *adap)
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index e6f539e..b617fd0 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -393,7 +393,7 @@
 {
 	unsigned char b;
 	struct pci_dev *dummy = NULL;
-	int retval = -ENODEV, i;
+	int retval, i;
 
 	/* check for supported SiS devices */
 	for (i=0; supported[i] > 0 ; i++) {
@@ -418,18 +418,21 @@
 	*/
 	if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
 		dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
+		retval = -ENODEV;
 		goto exit;
 	}
 	/* if ACPI already enabled , do nothing */
 	if (!(b & 0x80) &&
 	    pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
 		dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
+		retval = -ENODEV;
 		goto exit;
 	}
 
 	/* Determine the ACPI base address */
 	if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
 		dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n");
+		retval = -ENODEV;
 		goto exit;
 	}
 
@@ -445,6 +448,7 @@
 			    sis630_driver.name)) {
 		dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already "
 			"in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA);
+		retval = -EBUSY;
 		goto exit;
 	}
 
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 0b012f1..58261d4 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -324,7 +324,7 @@
 				 const struct pci_device_id *id)
 {
 	unsigned char temp;
-	int error = -ENODEV;
+	int error;
 
 	/* Determine the address of the SMBus areas */
 	if (force_addr) {
@@ -390,6 +390,7 @@
 			dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
 				"controller not enabled! - upgrade BIOS or "
 				"use force=1\n");
+			error = -ENODEV;
 			goto release_region;
 		}
 	}
@@ -422,9 +423,11 @@
 		 "SMBus Via Pro adapter at %04x", vt596_smba);
 
 	vt596_pdev = pci_dev_get(pdev);
-	if (i2c_add_adapter(&vt596_adapter)) {
+	error = i2c_add_adapter(&vt596_adapter);
+	if (error) {
 		pci_dev_put(vt596_pdev);
 		vt596_pdev = NULL;
+		goto release_region;
 	}
 
 	/* Always return failure here.  This is to allow other drivers to bind
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
index d267b7a..a22ca84 100644
--- a/drivers/ide/ide-floppy_ioctl.c
+++ b/drivers/ide/ide-floppy_ioctl.c
@@ -292,8 +292,7 @@
 	 * and CDROM_SEND_PACKET (legacy) ioctls
 	 */
 	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
-		err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk,
-				mode, cmd, argp);
+		err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
 
 	if (err == -ENOTTY)
 		err = generic_ide_ioctl(drive, bdev, cmd, arg);
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index a46dddf..026f9aa 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -321,7 +321,8 @@
 	cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates);
 
 	if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
-		!(ecx & CPUID5_ECX_INTERRUPT_BREAK))
+	    !(ecx & CPUID5_ECX_INTERRUPT_BREAK) ||
+	    !mwait_substates)
 			return -ENODEV;
 
 	pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
@@ -367,7 +368,7 @@
 	if (boot_cpu_has(X86_FEATURE_ARAT))	/* Always Reliable APIC Timer */
 		lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
 	else {
-		smp_call_function(__setup_broadcast_timer, (void *)true, 1);
+		on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
 		register_cpu_notifier(&setup_broadcast_notifier);
 	}
 
@@ -459,7 +460,7 @@
 		}
 	}
 	if (auto_demotion_disable_flags)
-		smp_call_function(auto_demotion_disable, NULL, 1);
+		on_each_cpu(auto_demotion_disable, NULL, 1);
 
 	return 0;
 }
@@ -499,7 +500,7 @@
 	cpuidle_unregister_driver(&intel_idle_driver);
 
 	if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
-		smp_call_function(__setup_broadcast_timer, (void *)false, 1);
+		on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
 		unregister_cpu_notifier(&setup_broadcast_notifier);
 	}
 
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 8e21d45..f2a84c6 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -215,7 +215,9 @@
 
 	neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev);
 	if (!neigh || !(neigh->nud_state & NUD_VALID)) {
-		neigh_event_send(rt->dst.neighbour, NULL);
+		rcu_read_lock();
+		neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
+		rcu_read_unlock();
 		ret = -ENODATA;
 		if (neigh)
 			goto release;
@@ -273,14 +275,16 @@
 		goto put;
 	}
 
-	neigh = dst->neighbour;
+	rcu_read_lock();
+	neigh = dst_get_neighbour(dst);
 	if (!neigh || !(neigh->nud_state & NUD_VALID)) {
-		neigh_event_send(dst->neighbour, NULL);
+		if (neigh)
+			neigh_event_send(neigh, NULL);
 		ret = -ENODATA;
-		goto put;
+	} else {
+		ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
 	}
-
-	ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
+	rcu_read_unlock();
 put:
 	dst_release(dst);
 	return ret;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 2332dc2..e55ce7a 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1328,6 +1328,7 @@
 	struct iwch_ep *child_ep, *parent_ep = ctx;
 	struct cpl_pass_accept_req *req = cplhdr(skb);
 	unsigned int hwtid = GET_TID(req);
+	struct neighbour *neigh;
 	struct dst_entry *dst;
 	struct l2t_entry *l2t;
 	struct rtable *rt;
@@ -1364,7 +1365,10 @@
 		goto reject;
 	}
 	dst = &rt->dst;
-	l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev);
+	rcu_read_lock();
+	neigh = dst_get_neighbour(dst);
+	l2t = t3_l2t_get(tdev, neigh, neigh->dev);
+	rcu_read_unlock();
 	if (!l2t) {
 		printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
 		       __func__);
@@ -1874,10 +1878,11 @@
 
 int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 {
-	int err = 0;
 	struct iwch_dev *h = to_iwch_dev(cm_id->device);
+	struct neighbour *neigh;
 	struct iwch_ep *ep;
 	struct rtable *rt;
+	int err = 0;
 
 	if (is_loopback_dst(cm_id)) {
 		err = -ENOSYS;
@@ -1933,9 +1938,12 @@
 	}
 	ep->dst = &rt->dst;
 
+	rcu_read_lock();
+	neigh = dst_get_neighbour(ep->dst);
+
 	/* get a l2t entry */
-	ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour,
-			     ep->dst->neighbour->dev);
+	ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev);
+	rcu_read_unlock();
 	if (!ep->l2t) {
 		printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
 		err = -ENOMEM;
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 31fb440..daa93e9 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -1325,6 +1325,7 @@
 	unsigned int stid = GET_POPEN_TID(ntohl(req->tos_stid));
 	struct tid_info *t = dev->rdev.lldi.tids;
 	unsigned int hwtid = GET_TID(req);
+	struct neighbour *neigh;
 	struct dst_entry *dst;
 	struct l2t_entry *l2t;
 	struct rtable *rt;
@@ -1357,11 +1358,12 @@
 		goto reject;
 	}
 	dst = &rt->dst;
-	if (dst->neighbour->dev->flags & IFF_LOOPBACK) {
+	rcu_read_lock();
+	neigh = dst_get_neighbour(dst);
+	if (neigh->dev->flags & IFF_LOOPBACK) {
 		pdev = ip_dev_find(&init_net, peer_ip);
 		BUG_ON(!pdev);
-		l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour,
-				    pdev, 0);
+		l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, pdev, 0);
 		mtu = pdev->mtu;
 		tx_chan = cxgb4_port_chan(pdev);
 		smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
@@ -1372,18 +1374,18 @@
 		rss_qid = dev->rdev.lldi.rxq_ids[cxgb4_port_idx(pdev) * step];
 		dev_put(pdev);
 	} else {
-		l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour,
-					dst->neighbour->dev, 0);
+		l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, neigh->dev, 0);
 		mtu = dst_mtu(dst);
-		tx_chan = cxgb4_port_chan(dst->neighbour->dev);
-		smac_idx = (cxgb4_port_viid(dst->neighbour->dev) & 0x7F) << 1;
+		tx_chan = cxgb4_port_chan(neigh->dev);
+		smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1;
 		step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan;
-		txq_idx = cxgb4_port_idx(dst->neighbour->dev) * step;
-		ctrlq_idx = cxgb4_port_idx(dst->neighbour->dev);
+		txq_idx = cxgb4_port_idx(neigh->dev) * step;
+		ctrlq_idx = cxgb4_port_idx(neigh->dev);
 		step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
 		rss_qid = dev->rdev.lldi.rxq_ids[
-			  cxgb4_port_idx(dst->neighbour->dev) * step];
+			  cxgb4_port_idx(neigh->dev) * step];
 	}
+	rcu_read_unlock();
 	if (!l2t) {
 		printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
 		       __func__);
@@ -1847,6 +1849,7 @@
 	struct c4iw_ep *ep;
 	struct rtable *rt;
 	struct net_device *pdev;
+	struct neighbour *neigh;
 	int step;
 
 	if ((conn_param->ord > c4iw_max_read_depth) ||
@@ -1908,14 +1911,16 @@
 	}
 	ep->dst = &rt->dst;
 
+	rcu_read_lock();
+	neigh = dst_get_neighbour(ep->dst);
+
 	/* get a l2t entry */
-	if (ep->dst->neighbour->dev->flags & IFF_LOOPBACK) {
+	if (neigh->dev->flags & IFF_LOOPBACK) {
 		PDBG("%s LOOPBACK\n", __func__);
 		pdev = ip_dev_find(&init_net,
 				   cm_id->remote_addr.sin_addr.s_addr);
 		ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
-					ep->dst->neighbour,
-					pdev, 0);
+					neigh, pdev, 0);
 		ep->mtu = pdev->mtu;
 		ep->tx_chan = cxgb4_port_chan(pdev);
 		ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
@@ -1930,21 +1935,20 @@
 		dev_put(pdev);
 	} else {
 		ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
-					ep->dst->neighbour,
-					ep->dst->neighbour->dev, 0);
+					neigh, neigh->dev, 0);
 		ep->mtu = dst_mtu(ep->dst);
-		ep->tx_chan = cxgb4_port_chan(ep->dst->neighbour->dev);
-		ep->smac_idx = (cxgb4_port_viid(ep->dst->neighbour->dev) &
-				0x7F) << 1;
+		ep->tx_chan = cxgb4_port_chan(neigh->dev);
+		ep->smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1;
 		step = ep->com.dev->rdev.lldi.ntxq /
 		       ep->com.dev->rdev.lldi.nchan;
-		ep->txq_idx = cxgb4_port_idx(ep->dst->neighbour->dev) * step;
-		ep->ctrlq_idx = cxgb4_port_idx(ep->dst->neighbour->dev);
+		ep->txq_idx = cxgb4_port_idx(neigh->dev) * step;
+		ep->ctrlq_idx = cxgb4_port_idx(neigh->dev);
 		step = ep->com.dev->rdev.lldi.nrxq /
 		       ep->com.dev->rdev.lldi.nchan;
 		ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[
-			      cxgb4_port_idx(ep->dst->neighbour->dev) * step];
+			      cxgb4_port_idx(neigh->dev) * step];
 	}
+	rcu_read_unlock();
 	if (!ep->l2t) {
 		printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
 		err = -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 57ffa50..44fc310 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -255,12 +255,9 @@
 			return IB_MAD_RESULT_SUCCESS;
 
 		/*
-		 * Don't process SMInfo queries or vendor-specific
-		 * MADs -- the SMA can't handle them.
+		 * Don't process SMInfo queries -- the SMA can't handle them.
 		 */
-		if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO ||
-		    ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) ==
-		     IB_SMP_ATTR_VENDOR_MASK))
+		if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO)
 			return IB_MAD_RESULT_SUCCESS;
 	} else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
 		   in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1   ||
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 2001f20..23c04ff 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1301,7 +1301,7 @@
 	int is_eth;
 	int is_vlan = 0;
 	int is_grh;
-	u16 vlan;
+	u16 vlan = 0;
 
 	send_size = 0;
 	for (i = 0; i < wr->num_sge; ++i)
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index e74cdf9..a1f74f6 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1150,9 +1150,11 @@
 		neigh_release(neigh);
 	}
 
-	if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
-		neigh_event_send(rt->dst.neighbour, NULL);
-
+	if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) {
+		rcu_read_lock();
+		neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
+		rcu_read_unlock();
+	}
 	ip_rt_put(rt);
 	return rc;
 }
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index d8ca0a0..65df26c 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -2076,9 +2076,11 @@
 static void qib_update_6120_usrhead(struct qib_ctxtdata *rcd, u64 hd,
 				    u32 updegr, u32 egrhd, u32 npkts)
 {
-	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
 	if (updegr)
 		qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt);
+	mmiowb();
+	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+	mmiowb();
 }
 
 static u32 qib_6120_hdrqempty(struct qib_ctxtdata *rcd)
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index c765a2e..759bb63 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -2704,9 +2704,11 @@
 static void qib_update_7220_usrhead(struct qib_ctxtdata *rcd, u64 hd,
 				    u32 updegr, u32 egrhd, u32 npkts)
 {
-	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
 	if (updegr)
 		qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt);
+	mmiowb();
+	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+	mmiowb();
 }
 
 static u32 qib_7220_hdrqempty(struct qib_ctxtdata *rcd)
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 8ec5237..49e4a58 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -4060,10 +4060,12 @@
 	 */
 	if (hd >> IBA7322_HDRHEAD_PKTINT_SHIFT)
 		adjust_rcv_timeout(rcd, npkts);
-	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
-	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
 	if (updegr)
 		qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt);
+	mmiowb();
+	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+	qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
+	mmiowb();
 }
 
 static u32 qib_7322_hdrqempty(struct qib_ctxtdata *rcd)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 86addca..a98c414 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -555,14 +555,17 @@
 	return 0;
 }
 
+/* called with rcu_read_lock */
 static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_path *path;
 	struct ipoib_neigh *neigh;
+	struct neighbour *n;
 	unsigned long flags;
 
-	neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev);
+	n = dst_get_neighbour(skb_dst(skb));
+	neigh = ipoib_neigh_alloc(n, skb->dev);
 	if (!neigh) {
 		++dev->stats.tx_dropped;
 		dev_kfree_skb_any(skb);
@@ -571,9 +574,9 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4);
+	path = __path_find(dev, n->ha + 4);
 	if (!path) {
-		path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4);
+		path = path_rec_create(dev, n->ha + 4);
 		if (!path)
 			goto err_path;
 
@@ -607,7 +610,7 @@
 			}
 		} else {
 			spin_unlock_irqrestore(&priv->lock, flags);
-			ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
+			ipoib_send(dev, skb, path->ah, IPOIB_QPN(n->ha));
 			return;
 		}
 	} else {
@@ -634,20 +637,24 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
+/* called with rcu_read_lock */
 static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(skb->dev);
+	struct dst_entry *dst = skb_dst(skb);
+	struct neighbour *n;
 
 	/* Look up path record for unicasts */
-	if (skb_dst(skb)->neighbour->ha[4] != 0xff) {
+	n = dst_get_neighbour(dst);
+	if (n->ha[4] != 0xff) {
 		neigh_add_path(skb, dev);
 		return;
 	}
 
 	/* Add in the P_Key for multicasts */
-	skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff;
-	skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff;
-	ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb);
+	n->ha[8] = (priv->pkey >> 8) & 0xff;
+	n->ha[9] = priv->pkey & 0xff;
+	ipoib_mcast_send(dev, n->ha + 4, skb);
 }
 
 static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
@@ -712,18 +719,23 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_neigh *neigh;
+	struct neighbour *n = NULL;
 	unsigned long flags;
 
-	if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) {
-		if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) {
+	rcu_read_lock();
+	if (likely(skb_dst(skb)))
+		n = dst_get_neighbour(skb_dst(skb));
+
+	if (likely(n)) {
+		if (unlikely(!*to_ipoib_neigh(n))) {
 			ipoib_path_lookup(skb, dev);
-			return NETDEV_TX_OK;
+			goto unlock;
 		}
 
-		neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour);
+		neigh = *to_ipoib_neigh(n);
 
 		if (unlikely((memcmp(&neigh->dgid.raw,
-				     skb_dst(skb)->neighbour->ha + 4,
+				     n->ha + 4,
 				     sizeof(union ib_gid))) ||
 			     (neigh->dev != dev))) {
 			spin_lock_irqsave(&priv->lock, flags);
@@ -740,17 +752,17 @@
 			ipoib_neigh_free(dev, neigh);
 			spin_unlock_irqrestore(&priv->lock, flags);
 			ipoib_path_lookup(skb, dev);
-			return NETDEV_TX_OK;
+			goto unlock;
 		}
 
 		if (ipoib_cm_get(neigh)) {
 			if (ipoib_cm_up(neigh)) {
 				ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
-				return NETDEV_TX_OK;
+				goto unlock;
 			}
 		} else if (neigh->ah) {
-			ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
-			return NETDEV_TX_OK;
+			ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha));
+			goto unlock;
 		}
 
 		if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
@@ -784,13 +796,14 @@
 					   phdr->hwaddr + 4);
 				dev_kfree_skb_any(skb);
 				++dev->stats.tx_dropped;
-				return NETDEV_TX_OK;
+				goto unlock;
 			}
 
 			unicast_arp_send(skb, dev, phdr);
 		}
 	}
-
+unlock:
+	rcu_read_unlock();
 	return NETDEV_TX_OK;
 }
 
@@ -812,6 +825,8 @@
 			     const void *daddr, const void *saddr, unsigned len)
 {
 	struct ipoib_header *header;
+	struct dst_entry *dst;
+	struct neighbour *n;
 
 	header = (struct ipoib_header *) skb_push(skb, sizeof *header);
 
@@ -823,7 +838,11 @@
 	 * destination address onto the front of the skb so we can
 	 * figure out where to send the packet later.
 	 */
-	if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) {
+	dst = skb_dst(skb);
+	n = NULL;
+	if (dst)
+		n = dst_get_neighbour_raw(dst);
+	if ((!dst || !n) && daddr) {
 		struct ipoib_pseudoheader *phdr =
 			(struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
 		memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 3871ac6..a8d2a89 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -258,11 +258,15 @@
 	netif_tx_lock_bh(dev);
 	while (!skb_queue_empty(&mcast->pkt_queue)) {
 		struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
+		struct dst_entry *dst = skb_dst(skb);
+		struct neighbour *n = NULL;
+
 		netif_tx_unlock_bh(dev);
 
 		skb->dev = dev;
-
-		if (!skb_dst(skb) || !skb_dst(skb)->neighbour) {
+		if (dst)
+			n = dst_get_neighbour_raw(dst);
+		if (!dst || !n) {
 			/* put pseudoheader back on for next time */
 			skb_push(skb, sizeof (struct ipoib_pseudoheader));
 		}
@@ -715,11 +719,15 @@
 
 out:
 	if (mcast && mcast->ah) {
-		if (skb_dst(skb)		&&
-		    skb_dst(skb)->neighbour &&
-		    !*to_ipoib_neigh(skb_dst(skb)->neighbour)) {
-			struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour,
-									skb->dev);
+		struct dst_entry *dst = skb_dst(skb);
+		struct neighbour *n = NULL;
+
+		rcu_read_lock();
+		if (dst)
+			n = dst_get_neighbour(dst);
+		if (n && !*to_ipoib_neigh(n)) {
+			struct ipoib_neigh *neigh = ipoib_neigh_alloc(n,
+								      skb->dev);
 
 			if (neigh) {
 				kref_get(&mcast->ah->ref);
@@ -727,7 +735,7 @@
 				list_add_tail(&neigh->list, &mcast->neigh_list);
 			}
 		}
-
+		rcu_read_unlock();
 		spin_unlock_irqrestore(&priv->lock, flags);
 		ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN);
 		return;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 6e7dd68..6288d7d 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -45,6 +45,7 @@
 	unsigned int packet_head; /* [future] position of the first element of next packet */
 	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
 	struct wake_lock wake_lock;
+	bool use_wake_lock;
 	char name[28];
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
@@ -62,7 +63,6 @@
 	/* Interrupts are disabled, just acquire the lock. */
 	spin_lock(&client->buffer_lock);
 
-	wake_lock_timeout(&client->wake_lock, 5 * HZ);
 	client->buffer[client->head++] = *event;
 	client->head &= client->bufsize - 1;
 
@@ -79,10 +79,14 @@
 		client->buffer[client->tail].value = 0;
 
 		client->packet_head = client->tail;
+		if (client->use_wake_lock)
+			wake_unlock(&client->wake_lock);
 	}
 
 	if (event->type == EV_SYN && event->code == SYN_REPORT) {
 		client->packet_head = client->head;
+		if (client->use_wake_lock)
+			wake_lock(&client->wake_lock);
 		kill_fasync(&client->fasync, SIGIO, POLL_IN);
 	}
 
@@ -262,7 +266,8 @@
 	mutex_unlock(&evdev->mutex);
 
 	evdev_detach_client(evdev, client);
-	wake_lock_destroy(&client->wake_lock);
+	if (client->use_wake_lock)
+		wake_lock_destroy(&client->wake_lock);
 	kfree(client);
 
 	evdev_close_device(evdev);
@@ -316,7 +321,6 @@
 	spin_lock_init(&client->buffer_lock);
 	snprintf(client->name, sizeof(client->name), "%s-%d",
 			dev_name(&evdev->dev), task_tgid_vnr(current));
-	wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
 	client->evdev = evdev;
 	evdev_attach_client(evdev, client);
 
@@ -331,7 +335,6 @@
 
  err_free_client:
 	evdev_detach_client(evdev, client);
-	wake_lock_destroy(&client->wake_lock);
 	kfree(client);
  err_put_evdev:
 	put_device(&evdev->dev);
@@ -385,7 +388,8 @@
 	if (have_event) {
 		*event = client->buffer[client->tail++];
 		client->tail &= client->bufsize - 1;
-		if (client->head == client->tail)
+		if (client->use_wake_lock &&
+		    client->packet_head == client->tail)
 			wake_unlock(&client->wake_lock);
 	}
 
@@ -635,6 +639,35 @@
 	return input_set_keycode(dev, &ke);
 }
 
+static int evdev_enable_suspend_block(struct evdev *evdev,
+				      struct evdev_client *client)
+{
+	if (client->use_wake_lock)
+		return 0;
+
+	spin_lock_irq(&client->buffer_lock);
+	wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
+	client->use_wake_lock = true;
+	if (client->packet_head != client->tail)
+		wake_lock(&client->wake_lock);
+	spin_unlock_irq(&client->buffer_lock);
+	return 0;
+}
+
+static int evdev_disable_suspend_block(struct evdev *evdev,
+				       struct evdev_client *client)
+{
+	if (!client->use_wake_lock)
+		return 0;
+
+	spin_lock_irq(&client->buffer_lock);
+	client->use_wake_lock = false;
+	wake_lock_destroy(&client->wake_lock);
+	spin_unlock_irq(&client->buffer_lock);
+
+	return 0;
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 			   void __user *p, int compat_mode)
 {
@@ -708,6 +741,15 @@
 
 	case EVIOCSKEYCODE_V2:
 		return evdev_handle_set_keycode_v2(dev, p);
+
+	case EVIOCGSUSPENDBLOCK:
+		return put_user(client->use_wake_lock, ip);
+
+	case EVIOCSSUSPENDBLOCK:
+		if (p)
+			return evdev_enable_suspend_block(evdev, client);
+		else
+			return evdev_disable_suspend_block(evdev, client);
 	}
 
 	size = _IOC_SIZE(cmd);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index e06e045..6ad728f 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -24,6 +24,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/dmi.h>
 #include <linux/input/mt.h>
 #include <linux/serio.h>
@@ -760,6 +761,16 @@
 
 	do {
 		psmouse_reset(psmouse);
+		if (retry) {
+			/*
+			 * On some boxes, right after resuming, the touchpad
+			 * needs some time to finish initializing (I assume
+			 * it needs time to calibrate) and start responding
+			 * to Synaptics-specific queries, so let's wait a
+			 * bit.
+			 */
+			ssleep(1);
+		}
 		error = synaptics_detect(psmouse, 0);
 	} while (error && ++retry < 3);
 
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 87cdb02..eef0891 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -817,4 +817,18 @@
 
          To compile this driver as a module, choose M here: the
          module will be called cyttsp-i2c.
+
+config TOUCHSCREEN_FT5X06
+       tristate "FocalTech touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have a ft5X06 touchscreen.
+	 Ft5x06 controllers are multi touch controllers which can
+	 report 5 touches at a time.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ft5x06_ts.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 1d67427..616b3a4 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -26,6 +26,7 @@
 obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELAN_I2C_8232) += elan8232_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
+obj-$(CONFIG_TOUCHSCREEN_FT5X06)	+= ft5x06_ts.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 40aae69..39c158d 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,12 +319,11 @@
 	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];
 	unsigned int irq;
-	unsigned int touch_x_size;
-	unsigned int touch_y_size;
 	struct regulator *vcc_ana;
 	struct regulator *vcc_dig;
 	struct regulator *vcc_i2c;
@@ -323,6 +342,7 @@
 	u8 t15_min_reportid;
 	u8 curr_cfg_version;
 	int cfg_version_idx;
+	const char *fw_name;
 };
 
 static struct dentry *debug_base;
@@ -409,8 +429,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 +550,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 +594,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__);
@@ -612,6 +749,17 @@
 			continue;
 
 		input_mt_slot(input_dev, id);
+		/* Firmware reports min/max values when the touch is
+		 * outside screen area. Send a release event in
+		 * such cases to avoid unwanted touches.
+		 */
+		if (finger[id].x <= data->pdata->panel_minx ||
+				finger[id].x >= data->pdata->panel_maxx ||
+				finger[id].y <= data->pdata->panel_miny ||
+				finger[id].y >= data->pdata->panel_maxy) {
+			finger[id].status = MXT_RELEASE;
+		}
+
 		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
 				finger[id].status != MXT_RELEASE);
 
@@ -632,6 +780,13 @@
 
 	input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
 
+	if (finger[single_id].x <= data->pdata->panel_minx ||
+		finger[single_id].x >= data->pdata->panel_maxx ||
+		finger[single_id].y <= data->pdata->panel_miny ||
+		finger[single_id].y >= data->pdata->panel_maxy) {
+		status = MXT_RELEASE;
+	}
+
 	if (status != MXT_RELEASE) {
 		input_report_abs(input_dev, ABS_X, finger[single_id].x);
 		input_report_abs(input_dev, ABS_Y, finger[single_id].y);
@@ -670,9 +825,9 @@
 
 	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
 	y = (message->message[2] << 4) | ((message->message[3] & 0xf));
-	if (data->touch_x_size < 1024)
+	if (data->pdata->panel_maxx < 1024)
 		x = x >> 2;
-	if (data->touch_y_size < 1024)
+	if (data->pdata->panel_maxy < 1024)
 		y = y >> 2;
 
 	area = message->message[4];
@@ -735,6 +890,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 +1081,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 +1165,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 +1296,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 +1353,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 +1645,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 +1661,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 +2121,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;
@@ -1835,9 +2139,9 @@
 
 	/* For single touch */
 	input_set_abs_params(input_dev, ABS_X,
-			     0, data->pdata->x_size, 0, 0);
+			pdata->disp_minx, pdata->disp_maxx, 0, 0);
 	input_set_abs_params(input_dev, ABS_Y,
-			     0, data->pdata->y_size, 0, 0);
+			pdata->disp_miny, pdata->disp_maxy, 0, 0);
 	input_set_abs_params(input_dev, ABS_PRESSURE,
 			     0, 255, 0, 0);
 
@@ -1846,22 +2150,12 @@
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
 			     0, MXT_MAX_AREA, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-			     0, data->pdata->x_size, 0, 0);
+			pdata->disp_minx, pdata->disp_maxx, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-			     0, data->pdata->y_size, 0, 0);
+			pdata->disp_miny, pdata->disp_maxy, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_PRESSURE,
 			     0, 255, 0, 0);
 
-	if (pdata->touch_x_size)
-		data->touch_x_size = pdata->touch_x_size;
-	else
-		data->touch_x_size = pdata->x_size;
-
-	if (pdata->touch_y_size)
-		data->touch_y_size = pdata->touch_y_size;
-	else
-		data->touch_y_size = pdata->y_size;
-
 	/* set key array supported keys */
 	if (pdata->key_codes) {
 		for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) {
@@ -1941,9 +2235,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/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
new file mode 100644
index 0000000..c9905a4
--- /dev/null
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -0,0 +1,654 @@
+/*
+ *
+ * FocalTech ft5x06 TouchScreen driver.
+ *
+ * Copyright (c) 2010  Focal tech Ltd.
+ * Copyright (c) 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/input/ft5x06_ts.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+/* Early-suspend level */
+#define FT5X06_SUSPEND_LEVEL 1
+#endif
+
+#define CFG_MAX_TOUCH_POINTS	5
+
+#define FT_STARTUP_DLY		150
+#define FT_RESET_DLY		20
+
+#define FT_PRESS		0x7F
+#define FT_MAX_ID		0x0F
+#define FT_TOUCH_STEP		6
+#define FT_TOUCH_X_H_POS	3
+#define FT_TOUCH_X_L_POS	4
+#define FT_TOUCH_Y_H_POS	5
+#define FT_TOUCH_Y_L_POS	6
+#define FT_TOUCH_EVENT_POS	3
+#define FT_TOUCH_ID_POS		5
+
+#define POINT_READ_BUF	(3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)
+
+/*register address*/
+#define FT5X06_REG_PMODE	0xA5
+#define FT5X06_REG_FW_VER	0xA6
+#define FT5X06_REG_POINT_RATE	0x88
+#define FT5X06_REG_THGROUP	0x80
+
+/* power register bits*/
+#define FT5X06_PMODE_ACTIVE		0x00
+#define FT5X06_PMODE_MONITOR		0x01
+#define FT5X06_PMODE_STANDBY		0x02
+#define FT5X06_PMODE_HIBERNATE		0x03
+
+#define FT5X06_VTG_MIN_UV	2600000
+#define FT5X06_VTG_MAX_UV	3300000
+#define FT5X06_I2C_VTG_MIN_UV	1800000
+#define FT5X06_I2C_VTG_MAX_UV	1800000
+
+struct ts_event {
+	u16 x[CFG_MAX_TOUCH_POINTS];	/*x coordinate */
+	u16 y[CFG_MAX_TOUCH_POINTS];	/*y coordinate */
+	/* touch event: 0 -- down; 1-- contact; 2 -- contact */
+	u8 touch_event[CFG_MAX_TOUCH_POINTS];
+	u8 finger_id[CFG_MAX_TOUCH_POINTS];	/*touch ID */
+	u16 pressure;
+	u8 touch_point;
+};
+
+struct ft5x06_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct ts_event event;
+	const struct ft5x06_ts_platform_data *pdata;
+	struct regulator *vdd;
+	struct regulator *vcc_i2c;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+};
+
+static int ft5x06_i2c_read(struct i2c_client *client, char *writebuf,
+			   int writelen, char *readbuf, int readlen)
+{
+	int ret;
+
+	if (writelen > 0) {
+		struct i2c_msg msgs[] = {
+			{
+				 .addr = client->addr,
+				 .flags = 0,
+				 .len = writelen,
+				 .buf = writebuf,
+			 },
+			{
+				 .addr = client->addr,
+				 .flags = I2C_M_RD,
+				 .len = readlen,
+				 .buf = readbuf,
+			 },
+		};
+		ret = i2c_transfer(client->adapter, msgs, 2);
+		if (ret < 0)
+			dev_err(&client->dev, "%s: i2c read error.\n",
+				__func__);
+	} else {
+		struct i2c_msg msgs[] = {
+			{
+				 .addr = client->addr,
+				 .flags = I2C_M_RD,
+				 .len = readlen,
+				 .buf = readbuf,
+			 },
+		};
+		ret = i2c_transfer(client->adapter, msgs, 1);
+		if (ret < 0)
+			dev_err(&client->dev, "%s:i2c read error.\n", __func__);
+	}
+	return ret;
+}
+
+static int ft5x06_i2c_write(struct i2c_client *client, char *writebuf,
+			    int writelen)
+{
+	int ret;
+
+	struct i2c_msg msgs[] = {
+		{
+			 .addr = client->addr,
+			 .flags = 0,
+			 .len = writelen,
+			 .buf = writebuf,
+		 },
+	};
+	ret = i2c_transfer(client->adapter, msgs, 1);
+	if (ret < 0)
+		dev_err(&client->dev, "%s: i2c write error.\n", __func__);
+
+	return ret;
+}
+
+static void ft5x06_report_value(struct ft5x06_ts_data *data)
+{
+	struct ts_event *event = &data->event;
+	int i;
+	int fingerdown = 0;
+
+	for (i = 0; i < event->touch_point; i++) {
+		if (event->touch_event[i] == 0 || event->touch_event[i] == 2) {
+			event->pressure = FT_PRESS;
+			fingerdown++;
+		} else {
+			event->pressure = 0;
+		}
+
+		input_report_abs(data->input_dev, ABS_MT_POSITION_X,
+				 event->x[i]);
+		input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
+				 event->y[i]);
+		input_report_abs(data->input_dev, ABS_MT_PRESSURE,
+				 event->pressure);
+		input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,
+				 event->finger_id[i]);
+		input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
+				 event->pressure);
+		input_mt_sync(data->input_dev);
+	}
+
+	input_report_key(data->input_dev, BTN_TOUCH, !!fingerdown);
+	input_sync(data->input_dev);
+}
+
+static int ft5x06_handle_touchdata(struct ft5x06_ts_data *data)
+{
+	struct ts_event *event = &data->event;
+	int ret, i;
+	u8 buf[POINT_READ_BUF] = { 0 };
+	u8 pointid = FT_MAX_ID;
+
+	ret = ft5x06_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "%s read touchdata failed.\n",
+			__func__);
+		return ret;
+	}
+	memset(event, 0, sizeof(struct ts_event));
+
+	event->touch_point = 0;
+	for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) {
+		pointid = (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
+		if (pointid >= FT_MAX_ID)
+			break;
+		else
+			event->touch_point++;
+		event->x[i] =
+		    (s16) (buf[FT_TOUCH_X_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
+		    8 | (s16) buf[FT_TOUCH_X_L_POS + FT_TOUCH_STEP * i];
+		event->y[i] =
+		    (s16) (buf[FT_TOUCH_Y_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
+		    8 | (s16) buf[FT_TOUCH_Y_L_POS + FT_TOUCH_STEP * i];
+		event->touch_event[i] =
+		    buf[FT_TOUCH_EVENT_POS + FT_TOUCH_STEP * i] >> 6;
+		event->finger_id[i] =
+		    (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
+	}
+
+	ft5x06_report_value(data);
+
+	return 0;
+}
+
+static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
+{
+	struct ft5x06_ts_data *data = dev_id;
+	int rc;
+
+	rc = ft5x06_handle_touchdata(data);
+	if (rc)
+		pr_err("%s: handling touchdata failed\n", __func__);
+
+	return IRQ_HANDLED;
+}
+
+static int ft5x06_power_on(struct ft5x06_ts_data *data, bool on)
+{
+	int rc;
+
+	if (!on)
+		goto power_off;
+
+	rc = regulator_enable(data->vdd);
+	if (rc) {
+		dev_err(&data->client->dev,
+			"Regulator vdd enable failed rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = regulator_enable(data->vcc_i2c);
+	if (rc) {
+		dev_err(&data->client->dev,
+			"Regulator vcc_i2c enable failed rc=%d\n", rc);
+		regulator_disable(data->vdd);
+	}
+
+	return rc;
+
+power_off:
+	rc = regulator_disable(data->vdd);
+	if (rc) {
+		dev_err(&data->client->dev,
+			"Regulator vdd disable failed rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = regulator_disable(data->vcc_i2c);
+	if (rc) {
+		dev_err(&data->client->dev,
+			"Regulator vcc_i2c disable failed rc=%d\n", rc);
+		regulator_enable(data->vdd);
+	}
+
+	return rc;
+}
+
+static int ft5x06_power_init(struct ft5x06_ts_data *data, bool on)
+{
+	int rc;
+
+	if (!on)
+		goto pwr_deinit;
+
+	data->vdd = regulator_get(&data->client->dev, "vdd");
+	if (IS_ERR(data->vdd)) {
+		rc = PTR_ERR(data->vdd);
+		dev_err(&data->client->dev,
+			"Regulator get failed vdd rc=%d\n", rc);
+		return rc;
+	}
+
+	if (regulator_count_voltages(data->vdd) > 0) {
+		rc = regulator_set_voltage(data->vdd, FT5X06_VTG_MIN_UV,
+					   FT5X06_VTG_MAX_UV);
+		if (rc) {
+			dev_err(&data->client->dev,
+				"Regulator set_vtg failed vdd rc=%d\n", rc);
+			goto reg_vdd_put;
+		}
+	}
+
+	data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
+	if (IS_ERR(data->vcc_i2c)) {
+		rc = PTR_ERR(data->vcc_i2c);
+		dev_err(&data->client->dev,
+			"Regulator get failed vcc_i2c rc=%d\n", rc);
+		goto reg_vdd_set_vtg;
+	}
+
+	if (regulator_count_voltages(data->vcc_i2c) > 0) {
+		rc = regulator_set_voltage(data->vcc_i2c, FT5X06_I2C_VTG_MIN_UV,
+					   FT5X06_I2C_VTG_MAX_UV);
+		if (rc) {
+			dev_err(&data->client->dev,
+			"Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
+			goto reg_vcc_i2c_put;
+		}
+	}
+
+	return 0;
+
+reg_vcc_i2c_put:
+	regulator_put(data->vcc_i2c);
+reg_vdd_set_vtg:
+	if (regulator_count_voltages(data->vdd) > 0)
+		regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
+reg_vdd_put:
+	regulator_put(data->vdd);
+	return rc;
+
+pwr_deinit:
+	if (regulator_count_voltages(data->vdd) > 0)
+		regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
+
+	regulator_put(data->vdd);
+
+	if (regulator_count_voltages(data->vcc_i2c) > 0)
+		regulator_set_voltage(data->vcc_i2c, 0, FT5X06_I2C_VTG_MAX_UV);
+
+	regulator_put(data->vcc_i2c);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ft5x06_ts_suspend(struct device *dev)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+	char txbuf[2];
+
+	disable_irq(data->client->irq);
+
+	if (gpio_is_valid(data->pdata->reset_gpio)) {
+		txbuf[0] = FT5X06_REG_PMODE;
+		txbuf[1] = FT5X06_PMODE_HIBERNATE;
+		ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf));
+	}
+
+	return 0;
+}
+
+static int ft5x06_ts_resume(struct device *dev)
+{
+	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+
+	if (gpio_is_valid(data->pdata->reset_gpio)) {
+		gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
+		msleep(FT_RESET_DLY);
+		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
+	}
+	enable_irq(data->client->irq);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void ft5x06_ts_early_suspend(struct early_suspend *handler)
+{
+	struct ft5x06_ts_data *data = container_of(handler,
+						   struct ft5x06_ts_data,
+						   early_suspend);
+
+	ft5x06_ts_suspend(&data->client->dev);
+}
+
+static void ft5x06_ts_late_resume(struct early_suspend *handler)
+{
+	struct ft5x06_ts_data *data = container_of(handler,
+						   struct ft5x06_ts_data,
+						   early_suspend);
+
+	ft5x06_ts_resume(&data->client->dev);
+}
+#endif
+
+static const struct dev_pm_ops ft5x06_ts_pm_ops = {
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend = ft5x06_ts_suspend,
+	.resume = ft5x06_ts_resume,
+#endif
+};
+#endif
+
+static int ft5x06_ts_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	const struct ft5x06_ts_platform_data *pdata = client->dev.platform_data;
+	struct ft5x06_ts_data *data;
+	struct input_dev *input_dev;
+	u8 reg_value;
+	u8 reg_addr;
+	int err;
+
+	if (!pdata) {
+		dev_err(&client->dev, "Invalid pdata\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "I2C not supported\n");
+		return -ENODEV;
+	}
+
+	data = kzalloc(sizeof(struct ft5x06_ts_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&client->dev, "Not enough memory\n");
+		return -ENOMEM;
+	}
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		err = -ENOMEM;
+		dev_err(&client->dev, "failed to allocate input device\n");
+		goto free_mem;
+	}
+
+	data->input_dev = input_dev;
+	data->client = client;
+	data->pdata = pdata;
+
+	input_dev->name = "ft5x06_ts";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	input_set_drvdata(input_dev, data);
+	i2c_set_clientdata(client, data);
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+			     pdata->x_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+			     pdata->y_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
+			     CFG_MAX_TOUCH_POINTS, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, FT_PRESS, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, FT_PRESS, 0, 0);
+
+	err = input_register_device(input_dev);
+	if (err) {
+		dev_err(&client->dev, "Input device registration failed\n");
+		goto free_inputdev;
+	}
+
+	if (pdata->power_init) {
+		err = pdata->power_init(true);
+		if (err) {
+			dev_err(&client->dev, "power init failed");
+			goto unreg_inputdev;
+		}
+	} else {
+		err = ft5x06_power_init(data, true);
+		if (err) {
+			dev_err(&client->dev, "power init failed");
+			goto unreg_inputdev;
+		}
+	}
+
+	if (pdata->power_on) {
+		err = pdata->power_on(true);
+		if (err) {
+			dev_err(&client->dev, "power on failed");
+			goto pwr_deinit;
+		}
+	} else {
+		err = ft5x06_power_on(data, true);
+		if (err) {
+			dev_err(&client->dev, "power on failed");
+			goto pwr_deinit;
+		}
+	}
+
+	if (gpio_is_valid(pdata->irq_gpio)) {
+		err = gpio_request(pdata->irq_gpio, "ft5x06_irq_gpio");
+		if (err) {
+			dev_err(&client->dev, "irq gpio request failed");
+			goto pwr_off;
+		}
+		err = gpio_direction_input(pdata->irq_gpio);
+		if (err) {
+			dev_err(&client->dev,
+				"set_direction for irq gpio failed\n");
+			goto free_irq_gpio;
+		}
+	}
+
+	if (gpio_is_valid(pdata->reset_gpio)) {
+		err = gpio_request(pdata->reset_gpio, "ft5x06_reset_gpio");
+		if (err) {
+			dev_err(&client->dev, "reset gpio request failed");
+			goto free_irq_gpio;
+		}
+
+		err = gpio_direction_output(pdata->reset_gpio, 0);
+		if (err) {
+			dev_err(&client->dev,
+				"set_direction for reset gpio failed\n");
+			goto free_reset_gpio;
+		}
+		msleep(FT_RESET_DLY);
+		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
+	}
+
+	/* make sure CTP already finish startup process */
+	msleep(FT_STARTUP_DLY);
+
+	/*get some register information */
+	reg_addr = FT5X06_REG_FW_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+	if (err)
+		dev_err(&client->dev, "version read failed");
+
+	dev_info(&client->dev, "[FTS] Firmware version = 0x%x\n", reg_value);
+
+	reg_addr = FT5X06_REG_POINT_RATE;
+	ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+	if (err)
+		dev_err(&client->dev, "report rate read failed");
+	dev_info(&client->dev, "[FTS] report rate is %dHz.\n", reg_value * 10);
+
+	reg_addr = FT5X06_REG_THGROUP;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+	if (err)
+		dev_err(&client->dev, "threshold read failed");
+	dev_dbg(&client->dev, "[FTS] touch threshold is %d.\n", reg_value * 4);
+
+	err = request_threaded_irq(client->irq, NULL,
+				   ft5x06_ts_interrupt, pdata->irqflags,
+				   client->dev.driver->name, data);
+	if (err) {
+		dev_err(&client->dev, "request irq failed\n");
+		goto free_reset_gpio;
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
+	    FT5X06_SUSPEND_LEVEL;
+	data->early_suspend.suspend = ft5x06_ts_early_suspend;
+	data->early_suspend.resume = ft5x06_ts_late_resume;
+	register_early_suspend(&data->early_suspend);
+#endif
+
+	return 0;
+
+free_reset_gpio:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+free_irq_gpio:
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->reset_gpio);
+pwr_off:
+	if (pdata->power_on)
+		pdata->power_on(false);
+	else
+		ft5x06_power_on(data, false);
+pwr_deinit:
+	if (pdata->power_init)
+		pdata->power_init(false);
+	else
+		ft5x06_power_init(data, false);
+unreg_inputdev:
+	input_unregister_device(input_dev);
+	input_dev = NULL;
+free_inputdev:
+	input_free_device(input_dev);
+free_mem:
+	kfree(data);
+	return err;
+}
+
+static int __devexit ft5x06_ts_remove(struct i2c_client *client)
+{
+	struct ft5x06_ts_data *data = i2c_get_clientdata(client);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&data->early_suspend);
+#endif
+	free_irq(client->irq, data);
+
+	if (gpio_is_valid(data->pdata->reset_gpio))
+		gpio_free(data->pdata->reset_gpio);
+
+	if (gpio_is_valid(data->pdata->irq_gpio))
+		gpio_free(data->pdata->reset_gpio);
+
+	if (data->pdata->power_on)
+		data->pdata->power_on(false);
+	else
+		ft5x06_power_on(data, false);
+
+	if (data->pdata->power_init)
+		data->pdata->power_init(false);
+	else
+		ft5x06_power_init(data, false);
+
+	input_unregister_device(data->input_dev);
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id ft5x06_ts_id[] = {
+	{"ft5x06_ts", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ft5x06_ts_id);
+
+static struct i2c_driver ft5x06_ts_driver = {
+	.probe = ft5x06_ts_probe,
+	.remove = __devexit_p(ft5x06_ts_remove),
+	.driver = {
+		   .name = "ft5x06_ts",
+		   .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		   .pm = &ft5x06_ts_pm_ops,
+#endif
+		   },
+	.id_table = ft5x06_ts_id,
+};
+
+static int __init ft5x06_ts_init(void)
+{
+	return i2c_add_driver(&ft5x06_ts_driver);
+}
+module_init(ft5x06_ts_init);
+
+static void __exit ft5x06_ts_exit(void)
+{
+	i2c_del_driver(&ft5x06_ts_driver);
+}
+module_exit(ft5x06_ts_exit);
+
+MODULE_DESCRIPTION("FocalTech ft5x06 TouchScreen driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index b76b6d9..336a33f 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -289,6 +289,8 @@
 		   unsigned long *delay_on,
 		   unsigned long *delay_off)
 {
+	del_timer_sync(&led_cdev->blink_timer);
+
 	if (led_cdev->blink_set &&
 	    !led_cdev->blink_set(led_cdev, delay_on, delay_off))
 		return;
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index 46199d8..fa42c2c 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -71,7 +71,7 @@
 #define WLED_OP_FDBCK_MASK		0x1C
 #define WLED_OP_FDBCK_BIT_SHFT		0x02
 
-#define WLED_MAX_LEVEL			100
+#define WLED_MAX_LEVEL			255
 #define WLED_8_BIT_MASK			0xFF
 #define WLED_8_BIT_SHFT			0x08
 #define WLED_MAX_DUTY_CYCLE		0xFFF
@@ -79,6 +79,13 @@
 #define WLED_SYNC_VAL			0x07
 #define WLED_SYNC_RESET_VAL		0x00
 
+#define SSBI_REG_ADDR_RGB_CNTL1		0x12D
+#define SSBI_REG_ADDR_RGB_CNTL2		0x12E
+
+#define PM8XXX_DRV_RGB_RED_LED		BIT(2)
+#define PM8XXX_DRV_RGB_GREEN_LED	BIT(1)
+#define PM8XXX_DRV_RGB_BLUE_LED		BIT(0)
+
 #define MAX_FLASH_LED_CURRENT		300
 #define MAX_LC_LED_CURRENT		40
 #define MAX_KP_BL_LED_CURRENT		300
@@ -98,6 +105,40 @@
 
 #define PM8XXX_LED_PWM_FLAGS	(PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
 
+#define LED_MAP(_version, _kb, _led0, _led1, _led2, _flash_led0, _flash_led1, \
+	_wled, _rgb_led_red, _rgb_led_green, _rgb_led_blue)\
+	{\
+		.version = _version,\
+		.supported = _kb << PM8XXX_ID_LED_KB_LIGHT | \
+			_led0 << PM8XXX_ID_LED_0 | _led1 << PM8XXX_ID_LED_1 | \
+			_led2 << PM8XXX_ID_LED_2  | \
+			_flash_led0 << PM8XXX_ID_FLASH_LED_0 | \
+			_flash_led1 << PM8XXX_ID_FLASH_LED_1 | \
+			_wled << PM8XXX_ID_WLED | \
+			_rgb_led_red << PM8XXX_ID_RGB_LED_RED | \
+			_rgb_led_green << PM8XXX_ID_RGB_LED_GREEN | \
+			_rgb_led_blue << PM8XXX_ID_RGB_LED_BLUE, \
+	}
+
+/**
+ * supported_leds - leds supported for each PMIC version
+ * @version - version of PMIC
+ * @supported - which leds are supported on version
+ */
+
+struct supported_leds {
+	enum pm8xxx_version version;
+	u32 supported;
+};
+
+static const struct supported_leds led_map[] = {
+	LED_MAP(PM8XXX_VERSION_8058, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
+	LED_MAP(PM8XXX_VERSION_8921, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
+	LED_MAP(PM8XXX_VERSION_8018, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+	LED_MAP(PM8XXX_VERSION_8922, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1),
+	LED_MAP(PM8XXX_VERSION_8038, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1),
+};
+
 /**
  * struct pm8xxx_led_data - internal led data structure
  * @led_classdev - led class device
@@ -260,6 +301,44 @@
 	}
 }
 
+static void
+led_rgb_set(struct pm8xxx_led_data *led, enum led_brightness value)
+{
+	int rc;
+	u8 val, mask;
+
+	rc = pm8xxx_readb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL2, &val);
+	if (rc) {
+		dev_err(led->cdev.dev, "can't read rgb ctrl register rc=%d\n",
+							rc);
+		return;
+	}
+
+	switch (led->id) {
+	case PM8XXX_ID_RGB_LED_RED:
+		mask = PM8XXX_DRV_RGB_RED_LED;
+		break;
+	case PM8XXX_ID_RGB_LED_GREEN:
+		mask = PM8XXX_DRV_RGB_GREEN_LED;
+		break;
+	case PM8XXX_ID_RGB_LED_BLUE:
+		mask = PM8XXX_DRV_RGB_BLUE_LED;
+		break;
+	default:
+		return;
+	}
+
+	if (value)
+		val |= mask;
+	else
+		val &= ~mask;
+
+	rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL2, val);
+	if (rc < 0)
+		dev_err(led->cdev.dev, "can't set rgb led %d level rc=%d\n",
+			 led->id, rc);
+}
+
 static int pm8xxx_led_pwm_work(struct pm8xxx_led_data *led)
 {
 	int duty_us;
@@ -305,6 +384,11 @@
 		if (rc < 0)
 			pr_err("wled brightness set failed %d\n", rc);
 		break;
+	case PM8XXX_ID_RGB_LED_RED:
+	case PM8XXX_ID_RGB_LED_GREEN:
+	case PM8XXX_ID_RGB_LED_BLUE:
+		led_rgb_set(led, level);
+		break;
 	default:
 		dev_err(led->cdev.dev, "unknown led id %d", led->id);
 		break;
@@ -349,8 +433,6 @@
 static int pm8xxx_set_led_mode_and_max_brightness(struct pm8xxx_led_data *led,
 		enum pm8xxx_led_modes led_mode, int max_current)
 {
-	int rc = 0;
-
 	switch (led->id) {
 	case PM8XXX_ID_LED_0:
 	case PM8XXX_ID_LED_1:
@@ -389,13 +471,17 @@
 	case PM8XXX_ID_WLED:
 		led->cdev.max_brightness = WLED_MAX_LEVEL;
 		break;
-	default:
-		rc = -EINVAL;
-		pr_err("LED Id is invalid");
+	case PM8XXX_ID_RGB_LED_RED:
+	case PM8XXX_ID_RGB_LED_GREEN:
+	case PM8XXX_ID_RGB_LED_BLUE:
+		led->cdev.max_brightness = LED_FULL;
 		break;
+	default:
+		dev_err(led->cdev.dev, "LED Id is invalid");
+		return -EINVAL;
 	}
 
-	return rc;
+	return 0;
 }
 
 static enum led_brightness pm8xxx_led_get(struct led_classdev *led_cdev)
@@ -550,6 +636,35 @@
 	return 0;
 }
 
+static int __devinit init_rgb_led(struct pm8xxx_led_data *led)
+{
+	int rc;
+	u8 val;
+
+	rc = pm8xxx_readb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL1, &val);
+	if (rc) {
+		dev_err(led->cdev.dev, "can't read rgb ctrl1 register rc=%d\n",
+							rc);
+		return rc;
+	}
+
+	switch (led->id) {
+	case PM8XXX_ID_RGB_LED_RED:
+		val |= PM8XXX_DRV_RGB_RED_LED;
+		break;
+	case PM8XXX_ID_RGB_LED_GREEN:
+		val |= PM8XXX_DRV_RGB_GREEN_LED;
+		break;
+	case PM8XXX_ID_RGB_LED_BLUE:
+		val |= PM8XXX_DRV_RGB_BLUE_LED;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL1, val);
+}
+
 static int __devinit get_init_value(struct pm8xxx_led_data *led, u8 *val)
 {
 	int rc, offset;
@@ -577,6 +692,17 @@
 			dev_err(led->cdev.dev, "can't initialize wled rc=%d\n",
 								rc);
 		return rc;
+	case PM8XXX_ID_RGB_LED_RED:
+	case PM8XXX_ID_RGB_LED_GREEN:
+	case PM8XXX_ID_RGB_LED_BLUE:
+		rc = init_rgb_led(led);
+		if (rc) {
+			dev_err(led->cdev.dev, "can't initialize rgb rc=%d\n",
+								rc);
+			return rc;
+		}
+		addr = SSBI_REG_ADDR_RGB_CNTL1;
+		break;
 	default:
 		dev_err(led->cdev.dev, "unknown led id %d", led->id);
 		return -EINVAL;
@@ -639,7 +765,9 @@
 	struct led_info *curr_led;
 	struct pm8xxx_led_data *led, *led_dat;
 	struct pm8xxx_led_config *led_cfg;
-	int rc, i;
+	enum pm8xxx_version version;
+	bool found = false;
+	int rc, i, j;
 
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "platform data not supplied\n");
@@ -674,8 +802,26 @@
 
 		if (!((led_dat->id >= PM8XXX_ID_LED_KB_LIGHT) &&
 				(led_dat->id < PM8XXX_ID_MAX))) {
-			dev_err(&pdev->dev, "invalid LED ID (%d) specified\n",
-						 led_dat->id);
+			dev_err(&pdev->dev, "invalid LED ID(%d) specified\n",
+				led_dat->id);
+			rc = -EINVAL;
+			goto fail_id_check;
+
+		}
+
+		found = false;
+		version = pm8xxx_get_version(pdev->dev.parent);
+		for (j = 0; j < ARRAY_SIZE(led_map); j++) {
+			if (version == led_map[j].version
+			&& (led_map[j].supported & (1 << led_dat->id))) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			dev_err(&pdev->dev, "invalid LED ID(%d) specified\n",
+				led_dat->id);
 			rc = -EINVAL;
 			goto fail_id_check;
 		}
@@ -714,7 +860,12 @@
 			led->cdev.brightness = LED_OFF;
 
 		if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) {
-			__pm8xxx_led_work(led_dat,
+			if (led_dat->id == PM8XXX_ID_RGB_LED_RED ||
+				led_dat->id == PM8XXX_ID_RGB_LED_GREEN ||
+				led_dat->id == PM8XXX_ID_RGB_LED_BLUE)
+				__pm8xxx_led_work(led_dat, 0);
+			else
+				__pm8xxx_led_work(led_dat,
 					led_dat->cdev.max_brightness);
 
 			if (led_dat->pwm_channel != -1) {
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index ea79062..3e90b80 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -149,8 +149,17 @@
 static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg)
 {
 	struct flakey_c *fc = ti->private;
+	struct dm_dev *dev = fc->dev;
+	int r = 0;
 
-	return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg);
+	/*
+	 * Only pass ioctls through if the device sizes match exactly.
+	 */
+	if (fc->start ||
+	    ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
+		r = scsi_verify_blk_ioctl(NULL, cmd);
+
+	return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
 }
 
 static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 3921e3b..9728839 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -116,7 +116,17 @@
 			unsigned long arg)
 {
 	struct linear_c *lc = (struct linear_c *) ti->private;
-	return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg);
+	struct dm_dev *dev = lc->dev;
+	int r = 0;
+
+	/*
+	 * Only pass ioctls through if the device sizes match exactly.
+	 */
+	if (lc->start ||
+	    ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
+		r = scsi_verify_blk_ioctl(NULL, cmd);
+
+	return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
 }
 
 static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 209991b..70373bf 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1584,6 +1584,12 @@
 
 	spin_unlock_irqrestore(&m->lock, flags);
 
+	/*
+	 * Only pass ioctls through if the device sizes match exactly.
+	 */
+	if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
+		r = scsi_verify_blk_ioctl(NULL, cmd);
+
 	return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 }
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2581ba1..1f6c68d 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3078,7 +3078,7 @@
 			/* Not in-sync */;
 		else if (test_bit(In_sync, &rdev->flags))
 			set_bit(R5_Insync, &dev->flags);
-		else {
+		else if (!test_bit(Faulty, &rdev->flags)) {
 			/* could be in-sync depending on recovery/reshape status */
 			if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset)
 				set_bit(R5_Insync, &dev->flags);
@@ -3120,12 +3120,16 @@
 	/* check if the array has lost two devices and, if so, some requests might
 	 * need to be failed
 	 */
-	if (s.failed > 1 && s.to_read+s.to_write+s.written)
-		handle_failed_stripe(conf, sh, &s, disks, &return_bi);
-	if (s.failed > 1 && s.syncing) {
-		md_done_sync(conf->mddev, STRIPE_SECTORS,0);
-		clear_bit(STRIPE_SYNCING, &sh->state);
-		s.syncing = 0;
+	if (s.failed > 1) {
+		sh->check_state = 0;
+		sh->reconstruct_state = 0;
+		if (s.to_read+s.to_write+s.written)
+			handle_failed_stripe(conf, sh, &s, disks, &return_bi);
+		if (s.syncing) {
+			md_done_sync(conf->mddev, STRIPE_SECTORS,0);
+			clear_bit(STRIPE_SYNCING, &sh->state);
+			s.syncing = 0;
+		}
 	}
 
 	/* might be able to return some write requests if the parity block
@@ -3369,7 +3373,7 @@
 			/* Not in-sync */;
 		else if (test_bit(In_sync, &rdev->flags))
 			set_bit(R5_Insync, &dev->flags);
-		else {
+		else if (!test_bit(Faulty, &rdev->flags)) {
 			/* in sync if before recovery_offset */
 			if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset)
 				set_bit(R5_Insync, &dev->flags);
@@ -3412,12 +3416,16 @@
 	/* check if the array has lost >2 devices and, if so, some requests
 	 * might need to be failed
 	 */
-	if (s.failed > 2 && s.to_read+s.to_write+s.written)
-		handle_failed_stripe(conf, sh, &s, disks, &return_bi);
-	if (s.failed > 2 && s.syncing) {
-		md_done_sync(conf->mddev, STRIPE_SECTORS,0);
-		clear_bit(STRIPE_SYNCING, &sh->state);
-		s.syncing = 0;
+	if (s.failed > 2) {
+		sh->check_state = 0;
+		sh->reconstruct_state = 0;
+		if (s.to_read+s.to_write+s.written)
+			handle_failed_stripe(conf, sh, &s, disks, &return_bi);
+		if (s.syncing) {
+			md_done_sync(conf->mddev, STRIPE_SECTORS,0);
+			clear_bit(STRIPE_SYNCING, &sh->state);
+			s.syncing = 0;
+		}
 	}
 
 	/*
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 5eb91b4..a224e94 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -30,6 +30,11 @@
 	struct dib0700_state *st = d->priv;
 	int ret;
 
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		deb_info("could not acquire lock");
+		return 0;
+	}
+
 	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
 				  REQUEST_GET_VERSION,
 				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
@@ -46,6 +51,7 @@
 	if (fwtype != NULL)
 		*fwtype     = (st->buf[12] << 24) | (st->buf[13] << 16) |
 			(st->buf[14] << 8) | st->buf[15];
+	mutex_unlock(&d->usb_mutex);
 	return ret;
 }
 
@@ -108,7 +114,12 @@
 int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
 {
 	struct dib0700_state *st = d->priv;
-	s16 ret;
+	int ret;
+
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		deb_info("could not acquire lock");
+		return 0;
+	}
 
 	st->buf[0] = REQUEST_SET_GPIO;
 	st->buf[1] = gpio;
@@ -116,6 +127,7 @@
 
 	ret = dib0700_ctrl_wr(d, st->buf, 3);
 
+	mutex_unlock(&d->usb_mutex);
 	return ret;
 }
 
@@ -125,6 +137,11 @@
 	int ret;
 
 	if (st->fw_version >= 0x10201) {
+		if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+			deb_info("could not acquire lock");
+			return 0;
+		}
+
 		st->buf[0] = REQUEST_SET_USB_XFER_LEN;
 		st->buf[1] = (nb_ts_packets >> 8) & 0xff;
 		st->buf[2] = nb_ts_packets & 0xff;
@@ -132,6 +149,7 @@
 		deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
 
 		ret = dib0700_ctrl_wr(d, st->buf, 3);
+		mutex_unlock(&d->usb_mutex);
 	} else {
 		deb_info("this firmware does not allow to change the USB xfer len\n");
 		ret = -EIO;
@@ -208,6 +226,10 @@
 
 		} else {
 			/* Write request */
+			if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+				deb_info("could not acquire lock");
+				return 0;
+			}
 			st->buf[0] = REQUEST_NEW_I2C_WRITE;
 			st->buf[1] = msg[i].addr << 1;
 			st->buf[2] = (en_start << 7) | (en_stop << 6) |
@@ -227,6 +249,7 @@
 						 USB_TYPE_VENDOR | USB_DIR_OUT,
 						 0, 0, st->buf, msg[i].len + 4,
 						 USB_CTRL_GET_TIMEOUT);
+			mutex_unlock(&d->usb_mutex);
 			if (result < 0) {
 				deb_info("i2c write error (status = %d)\n", result);
 				break;
@@ -249,6 +272,10 @@
 
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		deb_info("could not acquire lock");
+		return 0;
+	}
 
 	for (i = 0; i < num; i++) {
 		/* fill in the address */
@@ -279,6 +306,7 @@
 				break;
 		}
 	}
+	mutex_unlock(&d->usb_mutex);
 	mutex_unlock(&d->i2c_mutex);
 
 	return i;
@@ -337,7 +365,12 @@
 	u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
 {
 	struct dib0700_state *st = d->priv;
-	s16 ret;
+	int ret;
+
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		deb_info("could not acquire lock");
+		return 0;
+	}
 
 	st->buf[0] = REQUEST_SET_CLOCK;
 	st->buf[1] = (en_pll << 7) | (pll_src << 6) |
@@ -352,6 +385,7 @@
 	st->buf[9] =  dsuScaler         & 0xff; /* LSB */
 
 	ret = dib0700_ctrl_wr(d, st->buf, 10);
+	mutex_unlock(&d->usb_mutex);
 
 	return ret;
 }
@@ -360,10 +394,16 @@
 {
 	struct dib0700_state *st = d->priv;
 	u16 divider;
+	int ret;
 
 	if (scl_kHz == 0)
 		return -EINVAL;
 
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		deb_info("could not acquire lock");
+		return 0;
+	}
+
 	st->buf[0] = REQUEST_SET_I2C_PARAM;
 	divider = (u16) (30000 / scl_kHz);
 	st->buf[1] = 0;
@@ -379,7 +419,11 @@
 	deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
 		(st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
 		st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
-	return dib0700_ctrl_wr(d, st->buf, 8);
+
+	ret = dib0700_ctrl_wr(d, st->buf, 8);
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
 }
 
 
@@ -515,6 +559,11 @@
 		}
 	}
 
+	if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
+		deb_info("could not acquire lock");
+		return 0;
+	}
+
 	st->buf[0] = REQUEST_ENABLE_VIDEO;
 	/* this bit gives a kind of command,
 	 * rather than enabling something or not */
@@ -548,7 +597,10 @@
 
 	deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
 
-	return dib0700_ctrl_wr(adap->dev, st->buf, 4);
+	ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
+	mutex_unlock(&adap->dev->usb_mutex);
+
+	return ret;
 }
 
 int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
@@ -557,6 +609,11 @@
 	struct dib0700_state *st = d->priv;
 	int new_proto, ret;
 
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		deb_info("could not acquire lock");
+		return 0;
+	}
+
 	st->buf[0] = REQUEST_SET_RC;
 	st->buf[1] = 0;
 	st->buf[2] = 0;
@@ -567,23 +624,29 @@
 	else if (rc_type == RC_TYPE_NEC)
 		new_proto = 0;
 	else if (rc_type == RC_TYPE_RC6) {
-		if (st->fw_version < 0x10200)
-			return -EINVAL;
+		if (st->fw_version < 0x10200) {
+			ret = -EINVAL;
+			goto out;
+		}
 
 		new_proto = 2;
-	} else
-		return -EINVAL;
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	st->buf[1] = new_proto;
 
 	ret = dib0700_ctrl_wr(d, st->buf, 3);
 	if (ret < 0) {
 		err("ir protocol setup failed");
-		return ret;
+		goto out;
 	}
 
 	d->props.rc.core.protocol = rc_type;
 
+out:
+	mutex_unlock(&d->usb_mutex);
 	return ret;
 }
 
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
index 1d47d4d..dc1cb17 100644
--- a/drivers/media/dvb/frontends/dib0070.c
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 
@@ -78,10 +79,18 @@
 	struct i2c_msg msg[2];
 	u8 i2c_write_buffer[3];
 	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
 };
 
-static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
 {
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
 	state->i2c_write_buffer[0] = reg;
 
 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
@@ -96,13 +105,23 @@
 
 	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
 		printk(KERN_WARNING "DiB0070 I2C read failed\n");
-		return 0;
-	}
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+		ret = 0;
+	} else
+		ret = (state->i2c_read_buffer[0] << 8)
+			| state->i2c_read_buffer[1];
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 {
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
 	state->i2c_write_buffer[0] = reg;
 	state->i2c_write_buffer[1] = val >> 8;
 	state->i2c_write_buffer[2] = val & 0xff;
@@ -115,9 +134,12 @@
 
 	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
 		printk(KERN_WARNING "DiB0070 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
+		ret = -EREMOTEIO;
+	} else
+		ret = 0;
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 #define HARD_RESET(state) do { \
@@ -734,6 +756,7 @@
 	state->cfg = cfg;
 	state->i2c = i2c;
 	state->fe  = fe;
+	mutex_init(&state->i2c_buffer_lock);
 	fe->tuner_priv = state;
 
 	if (dib0070_reset(fe) != 0)
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
index c9c935a..b174d1c 100644
--- a/drivers/media/dvb/frontends/dib0090.c
+++ b/drivers/media/dvb/frontends/dib0090.c
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 
@@ -196,6 +197,7 @@
 	struct i2c_msg msg[2];
 	u8 i2c_write_buffer[3];
 	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
 };
 
 struct dib0090_fw_state {
@@ -208,10 +210,18 @@
 	struct i2c_msg msg;
 	u8 i2c_write_buffer[2];
 	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
 };
 
 static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
 {
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
 	state->i2c_write_buffer[0] = reg;
 
 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
@@ -226,14 +236,24 @@
 
 	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
 		printk(KERN_WARNING "DiB0090 I2C read failed\n");
-		return 0;
-	}
+		ret = 0;
+	} else
+		ret = (state->i2c_read_buffer[0] << 8)
+			| state->i2c_read_buffer[1];
 
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
 {
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
 	state->i2c_write_buffer[0] = reg & 0xff;
 	state->i2c_write_buffer[1] = val >> 8;
 	state->i2c_write_buffer[2] = val & 0xff;
@@ -246,13 +266,23 @@
 
 	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
 		printk(KERN_WARNING "DiB0090 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
+		ret = -EREMOTEIO;
+	} else
+		ret = 0;
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
 {
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
 	state->i2c_write_buffer[0] = reg;
 
 	memset(&state->msg, 0, sizeof(struct i2c_msg));
@@ -262,13 +292,24 @@
 	state->msg.len = 2;
 	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
 		printk(KERN_WARNING "DiB0090 I2C read failed\n");
-		return 0;
-	}
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+		ret = 0;
+	} else
+		ret = (state->i2c_read_buffer[0] << 8)
+			| state->i2c_read_buffer[1];
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
 {
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
 	state->i2c_write_buffer[0] = val >> 8;
 	state->i2c_write_buffer[1] = val & 0xff;
 
@@ -279,9 +320,12 @@
 	state->msg.len = 2;
 	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
 		printk(KERN_WARNING "DiB0090 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
+		ret = -EREMOTEIO;
+	} else
+		ret = 0;
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 #define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
@@ -2440,6 +2484,7 @@
 	st->config = config;
 	st->i2c = i2c;
 	st->fe = fe;
+	mutex_init(&st->i2c_buffer_lock);
 	fe->tuner_priv = st;
 
 	if (config->wbd == NULL)
@@ -2471,6 +2516,7 @@
 	st->config = config;
 	st->i2c = i2c;
 	st->fe = fe;
+	mutex_init(&st->i2c_buffer_lock);
 	fe->tuner_priv = st;
 
 	if (dib0090_fw_reset_digital(fe, st->config) != 0)
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index 79cb1c2..dbb76d7 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 
@@ -55,6 +56,7 @@
 	struct i2c_msg msg[2];
 	u8 i2c_write_buffer[4];
 	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
 };
 
 enum dib7000m_power_mode {
@@ -69,6 +71,13 @@
 
 static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
 {
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
 	state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
 	state->i2c_write_buffer[1] = reg & 0xff;
 
@@ -85,11 +94,21 @@
 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
 		dprintk("i2c read error on %d",reg);
 
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	mutex_unlock(&state->i2c_buffer_lock);
+
+	return ret;
 }
 
 static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
 {
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
 	state->i2c_write_buffer[1] = reg & 0xff;
 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -101,7 +120,10 @@
 	state->msg[0].buf = state->i2c_write_buffer;
 	state->msg[0].len = 4;
 
-	return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
+	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
+			-EREMOTEIO : 0);
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
 {
@@ -1385,6 +1407,7 @@
 	demod                   = &st->demod;
 	demod->demodulator_priv = st;
 	memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+	mutex_init(&st->i2c_buffer_lock);
 
 	st->timf_default = cfg->bw->timf;
 
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 0c9f40c..292bc19 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dvb_math.h"
 #include "dvb_frontend.h"
@@ -68,6 +69,7 @@
 	struct i2c_msg msg[2];
 	u8 i2c_write_buffer[4];
 	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
 };
 
 enum dib7000p_power_mode {
@@ -81,6 +83,13 @@
 
 static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
 {
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
 	state->i2c_write_buffer[0] = reg >> 8;
 	state->i2c_write_buffer[1] = reg & 0xff;
 
@@ -97,11 +106,20 @@
 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
 		dprintk("i2c read error on %d", reg);
 
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
 {
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
 	state->i2c_write_buffer[1] = reg & 0xff;
 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -113,7 +131,10 @@
 	state->msg[0].buf = state->i2c_write_buffer;
 	state->msg[0].len = 4;
 
-	return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
+	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
+			-EREMOTEIO : 0);
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
 }
 
 static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
@@ -1646,6 +1667,7 @@
 		return -ENOMEM;
 
 	dpst->i2c_adap = i2c;
+	mutex_init(&dpst->i2c_buffer_lock);
 
 	for (k = no_of_demods - 1; k >= 0; k--) {
 		dpst->cfg = cfg[k];
@@ -2324,6 +2346,7 @@
 	demod = &st->demod;
 	demod->demodulator_priv = st;
 	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
+	mutex_init(&st->i2c_buffer_lock);
 
 	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
 
@@ -2333,8 +2356,9 @@
 	st->version = dib7000p_read_word(st, 897);
 
 	/* FIXME: make sure the dev.parent field is initialized, or else
-		request_firmware() will hit an OOPS (this should be moved somewhere
-		more common) */
+	   request_firmware() will hit an OOPS (this should be moved somewhere
+	   more common) */
+	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
 
 	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
 
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
index 7d2ea11..fe284d5 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb/frontends/dib8000.c
@@ -10,6 +10,8 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
+
 #include "dvb_math.h"
 
 #include "dvb_frontend.h"
@@ -37,6 +39,7 @@
 	u8 addr;
 	u8 *i2c_write_buffer;
 	u8 *i2c_read_buffer;
+	struct mutex *i2c_buffer_lock;
 };
 
 struct dib8000_state {
@@ -77,6 +80,7 @@
 	struct i2c_msg msg[2];
 	u8 i2c_write_buffer[4];
 	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
 };
 
 enum dib8000_power_mode {
@@ -86,24 +90,39 @@
 
 static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
 {
+	u16 ret;
 	struct i2c_msg msg[2] = {
-		{.addr = i2c->addr >> 1, .flags = 0,
-			.buf = i2c->i2c_write_buffer, .len = 2},
-		{.addr = i2c->addr >> 1, .flags = I2C_M_RD,
-			.buf = i2c->i2c_read_buffer, .len = 2},
+		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
+		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
 	};
 
+	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	msg[0].buf    = i2c->i2c_write_buffer;
 	msg[0].buf[0] = reg >> 8;
 	msg[0].buf[1] = reg & 0xff;
+	msg[1].buf    = i2c->i2c_read_buffer;
 
 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
 		dprintk("i2c read error on %d", reg);
 
-	return (msg[1].buf[0] << 8) | msg[1].buf[1];
+	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
+	mutex_unlock(i2c->i2c_buffer_lock);
+	return ret;
 }
 
 static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
 {
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
 	state->i2c_write_buffer[0] = reg >> 8;
 	state->i2c_write_buffer[1] = reg & 0xff;
 
@@ -120,7 +139,10 @@
 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
 		dprintk("i2c read error on %d", reg);
 
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	mutex_unlock(&state->i2c_buffer_lock);
+
+	return ret;
 }
 
 static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
@@ -135,22 +157,35 @@
 
 static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
 {
-	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
-		.buf = i2c->i2c_write_buffer, .len = 4};
+	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
 	int ret = 0;
 
+	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	msg.buf    = i2c->i2c_write_buffer;
 	msg.buf[0] = (reg >> 8) & 0xff;
 	msg.buf[1] = reg & 0xff;
 	msg.buf[2] = (val >> 8) & 0xff;
 	msg.buf[3] = val & 0xff;
 
 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+	mutex_unlock(i2c->i2c_buffer_lock);
 
 	return ret;
 }
 
 static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
 {
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
 	state->i2c_write_buffer[1] = reg & 0xff;
 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -162,7 +197,11 @@
 	state->msg[0].buf = state->i2c_write_buffer;
 	state->msg[0].len = 4;
 
-	return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
+	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
+			-EREMOTEIO : 0);
+	mutex_unlock(&state->i2c_buffer_lock);
+
+	return ret;
 }
 
 static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
@@ -2434,8 +2473,15 @@
 	if (!client.i2c_read_buffer) {
 		dprintk("%s: not enough memory", __func__);
 		ret = -ENOMEM;
-		goto error_memory;
+		goto error_memory_read;
 	}
+	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
+	if (!client.i2c_buffer_lock) {
+		dprintk("%s: not enough memory", __func__);
+		ret = -ENOMEM;
+		goto error_memory_lock;
+	}
+	mutex_init(client.i2c_buffer_lock);
 
 	for (k = no_of_demods - 1; k >= 0; k--) {
 		/* designated i2c address */
@@ -2476,8 +2522,10 @@
 	}
 
 error:
+	kfree(client.i2c_buffer_lock);
+error_memory_lock:
 	kfree(client.i2c_read_buffer);
-error_memory:
+error_memory_read:
 	kfree(client.i2c_write_buffer);
 
 	return ret;
@@ -2581,6 +2629,8 @@
 	state->i2c.addr = i2c_addr;
 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
+	mutex_init(&state->i2c_buffer_lock);
+	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
 	state->gpio_val = cfg->gpio_val;
 	state->gpio_dir = cfg->gpio_dir;
 
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
index a085588..b931074 100644
--- a/drivers/media/dvb/frontends/dib9000.c
+++ b/drivers/media/dvb/frontends/dib9000.c
@@ -38,6 +38,15 @@
 #define DibInitLock(lock) mutex_init(lock)
 #define DibFreeLock(lock)
 
+struct dib9000_pid_ctrl {
+#define DIB9000_PID_FILTER_CTRL 0
+#define DIB9000_PID_FILTER      1
+	u8 cmd;
+	u8 id;
+	u16 pid;
+	u8 onoff;
+};
+
 struct dib9000_state {
 	struct i2c_device i2c;
 
@@ -99,6 +108,10 @@
 	struct i2c_msg msg[2];
 	u8 i2c_write_buffer[255];
 	u8 i2c_read_buffer[255];
+	DIB_LOCK demod_lock;
+	u8 get_frontend_internal;
+	struct dib9000_pid_ctrl pid_ctrl[10];
+	s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
 };
 
 static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1743,19 +1756,56 @@
 int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 {
 	struct dib9000_state *state = fe->demodulator_priv;
-	u16 val = dib9000_read_word(state, 294 + 1) & 0xffef;
+	u16 val;
+	int ret;
+
+	if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
+		/* postpone the pid filtering cmd */
+		dprintk("pid filter cmd postpone");
+		state->pid_ctrl_index++;
+		state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
+		state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
+		return 0;
+	}
+
+	DibAcquireLock(&state->demod_lock);
+
+	val = dib9000_read_word(state, 294 + 1) & 0xffef;
 	val |= (onoff & 0x1) << 4;
 
 	dprintk("PID filter enabled %d", onoff);
-	return dib9000_write_word(state, 294 + 1, val);
+	ret = dib9000_write_word(state, 294 + 1, val);
+	DibReleaseLock(&state->demod_lock);
+	return ret;
+
 }
 EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
 
 int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 {
 	struct dib9000_state *state = fe->demodulator_priv;
+	int ret;
+
+	if (state->pid_ctrl_index != -2) {
+		/* postpone the pid filtering cmd */
+		dprintk("pid filter postpone");
+		if (state->pid_ctrl_index < 9) {
+			state->pid_ctrl_index++;
+			state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
+			state->pid_ctrl[state->pid_ctrl_index].id = id;
+			state->pid_ctrl[state->pid_ctrl_index].pid = pid;
+			state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
+		} else
+			dprintk("can not add any more pid ctrl cmd");
+		return 0;
+	}
+
+	DibAcquireLock(&state->demod_lock);
 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
-	return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0);
+	ret = dib9000_write_word(state, 300 + 1 + id,
+			onoff ? (1 << 13) | pid : 0);
+	DibReleaseLock(&state->demod_lock);
+	return ret;
 }
 EXPORT_SYMBOL(dib9000_fw_pid_filter);
 
@@ -1778,6 +1828,7 @@
 	DibFreeLock(&state->platform.risc.mbx_lock);
 	DibFreeLock(&state->platform.risc.mem_lock);
 	DibFreeLock(&state->platform.risc.mem_mbx_lock);
+	DibFreeLock(&state->demod_lock);
 	dibx000_exit_i2c_master(&st->i2c_master);
 
 	i2c_del_adapter(&st->tuner_adap);
@@ -1795,14 +1846,19 @@
 {
 	struct dib9000_state *state = fe->demodulator_priv;
 	u8 index_frontend;
-	int ret;
+	int ret = 0;
 
+	DibAcquireLock(&state->demod_lock);
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
 		if (ret < 0)
-			return ret;
+			goto error;
 	}
-	return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
+	ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
+
+error:
+	DibReleaseLock(&state->demod_lock);
+	return ret;
 }
 
 static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
@@ -1816,7 +1872,10 @@
 	struct dib9000_state *state = fe->demodulator_priv;
 	u8 index_frontend, sub_index_frontend;
 	fe_status_t stat;
-	int ret;
+	int ret = 0;
+
+	if (state->get_frontend_internal == 0)
+		DibAcquireLock(&state->demod_lock);
 
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
@@ -1846,14 +1905,15 @@
 					    state->fe[index_frontend]->dtv_property_cache.rolloff;
 				}
 			}
-			return 0;
+			ret = 0;
+			goto return_value;
 		}
 	}
 
 	/* get the channel from master chip */
 	ret = dib9000_fw_get_channel(fe, fep);
 	if (ret != 0)
-		return ret;
+		goto return_value;
 
 	/* synchronize the cache with the other frontends */
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
@@ -1866,8 +1926,12 @@
 		state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
 		state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
 	}
+	ret = 0;
 
-	return 0;
+return_value:
+	if (state->get_frontend_internal == 0)
+		DibReleaseLock(&state->demod_lock);
+	return ret;
 }
 
 static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
@@ -1912,6 +1976,10 @@
 		dprintk("dib9000: must specify bandwidth ");
 		return 0;
 	}
+
+	state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
+	DibAcquireLock(&state->demod_lock);
+
 	fe->dtv_property_cache.delivery_system = SYS_DVBT;
 
 	/* set the master status */
@@ -1974,13 +2042,18 @@
 	/* check the tune result */
 	if (exit_condition == 1) {	/* tune failed */
 		dprintk("tune failed");
+		DibReleaseLock(&state->demod_lock);
+		/* tune failed; put all the pid filtering cmd to junk */
+		state->pid_ctrl_index = -1;
 		return 0;
 	}
 
 	dprintk("tune success on frontend%i", index_frontend_success);
 
 	/* synchronize all the channel cache */
+	state->get_frontend_internal = 1;
 	dib9000_get_frontend(state->fe[0], fep);
+	state->get_frontend_internal = 0;
 
 	/* retune the other frontends with the found channel */
 	channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
@@ -2025,6 +2098,28 @@
 	/* turn off the diversity for the last frontend */
 	dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
 
+	DibReleaseLock(&state->demod_lock);
+	if (state->pid_ctrl_index >= 0) {
+		u8 index_pid_filter_cmd;
+		u8 pid_ctrl_index = state->pid_ctrl_index;
+
+		state->pid_ctrl_index = -2;
+		for (index_pid_filter_cmd = 0;
+				index_pid_filter_cmd <= pid_ctrl_index;
+				index_pid_filter_cmd++) {
+			if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
+				dib9000_fw_pid_filter_ctrl(state->fe[0],
+						state->pid_ctrl[index_pid_filter_cmd].onoff);
+			else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
+				dib9000_fw_pid_filter(state->fe[0],
+						state->pid_ctrl[index_pid_filter_cmd].id,
+						state->pid_ctrl[index_pid_filter_cmd].pid,
+						state->pid_ctrl[index_pid_filter_cmd].onoff);
+		}
+	}
+	/* do not postpone any more the pid filtering */
+	state->pid_ctrl_index = -2;
+
 	return 0;
 }
 
@@ -2041,6 +2136,7 @@
 	u8 index_frontend;
 	u16 lock = 0, lock_slave = 0;
 
+	DibAcquireLock(&state->demod_lock);
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
 		lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
 
@@ -2059,6 +2155,8 @@
 	if ((lock & 0x0008) || (lock_slave & 0x0008))
 		*stat |= FE_HAS_LOCK;
 
+	DibReleaseLock(&state->demod_lock);
+
 	return 0;
 }
 
@@ -2066,10 +2164,14 @@
 {
 	struct dib9000_state *state = fe->demodulator_priv;
 	u16 *c;
+	int ret = 0;
 
+	DibAcquireLock(&state->demod_lock);
 	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-		return -EIO;
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		ret = -EIO;
+		goto error;
+	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
 			state->i2c_read_buffer, 16 * 2);
 	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
@@ -2077,7 +2179,10 @@
 	c = (u16 *)state->i2c_read_buffer;
 
 	*ber = c[10] << 16 | c[11];
-	return 0;
+
+error:
+	DibReleaseLock(&state->demod_lock);
+	return ret;
 }
 
 static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
@@ -2086,7 +2191,9 @@
 	u8 index_frontend;
 	u16 *c = (u16 *)state->i2c_read_buffer;
 	u16 val;
+	int ret = 0;
 
+	DibAcquireLock(&state->demod_lock);
 	*strength = 0;
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
@@ -2097,8 +2204,10 @@
 	}
 
 	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-		return -EIO;
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		ret = -EIO;
+		goto error;
+	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
 	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
@@ -2107,7 +2216,10 @@
 		*strength = 65535;
 	else
 		*strength += val;
-	return 0;
+
+error:
+	DibReleaseLock(&state->demod_lock);
+	return ret;
 }
 
 static u32 dib9000_get_snr(struct dvb_frontend *fe)
@@ -2151,6 +2263,7 @@
 	u8 index_frontend;
 	u32 snr_master;
 
+	DibAcquireLock(&state->demod_lock);
 	snr_master = dib9000_get_snr(fe);
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
 		snr_master += dib9000_get_snr(state->fe[index_frontend]);
@@ -2161,6 +2274,8 @@
 	} else
 		*snr = 0;
 
+	DibReleaseLock(&state->demod_lock);
+
 	return 0;
 }
 
@@ -2168,15 +2283,22 @@
 {
 	struct dib9000_state *state = fe->demodulator_priv;
 	u16 *c = (u16 *)state->i2c_read_buffer;
+	int ret = 0;
 
+	DibAcquireLock(&state->demod_lock);
 	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-		return -EIO;
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		ret = -EIO;
+		goto error;
+	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
 	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
 	*unc = c[12];
-	return 0;
+
+error:
+	DibReleaseLock(&state->demod_lock);
+	return ret;
 }
 
 int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
@@ -2322,6 +2444,10 @@
 	DibInitLock(&st->platform.risc.mbx_lock);
 	DibInitLock(&st->platform.risc.mem_lock);
 	DibInitLock(&st->platform.risc.mem_mbx_lock);
+	DibInitLock(&st->demod_lock);
+	st->get_frontend_internal = 0;
+
+	st->pid_ctrl_index = -2;
 
 	st->fe[0] = fe;
 	fe->demodulator_priv = st;
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index dc5d17a..774d507 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -1,4 +1,5 @@
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 #include "dibx000_common.h"
 
@@ -10,6 +11,13 @@
 
 static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
 {
+	int ret;
+
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
 	mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
 	mst->i2c_write_buffer[1] = reg & 0xff;
 	mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
@@ -21,11 +29,21 @@
 	mst->msg[0].buf = mst->i2c_write_buffer;
 	mst->msg[0].len = 4;
 
-	return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
+	ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
+	mutex_unlock(&mst->i2c_buffer_lock);
+
+	return ret;
 }
 
 static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
 {
+	u16 ret;
+
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
 	mst->i2c_write_buffer[0] = reg >> 8;
 	mst->i2c_write_buffer[1] = reg & 0xff;
 
@@ -42,7 +60,10 @@
 	if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
 		dprintk("i2c read error on %d", reg);
 
-	return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
+	ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
+	mutex_unlock(&mst->i2c_buffer_lock);
+
+	return ret;
 }
 
 static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
@@ -257,6 +278,7 @@
 					struct i2c_msg msg[], int num)
 {
 	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+	int ret;
 
 	if (num > 32) {
 		dprintk("%s: too much I2C message to be transmitted (%i).\
@@ -264,10 +286,15 @@
 		return -ENOMEM;
 	}
 
-	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
-
 	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
 
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+
 	/* open the gate */
 	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
 	mst->msg[0].addr = mst->i2c_addr;
@@ -282,7 +309,11 @@
 	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
 	mst->msg[num + 1].len = 4;
 
-	return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
+	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
+			num : -EIO);
+
+	mutex_unlock(&mst->i2c_buffer_lock);
+	return ret;
 }
 
 static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
@@ -294,6 +325,7 @@
 					struct i2c_msg msg[], int num)
 {
 	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+	int ret;
 
 	if (num > 32) {
 		dprintk("%s: too much I2C message to be transmitted (%i).\
@@ -301,10 +333,14 @@
 		return -ENOMEM;
 	}
 
-	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
-
 	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
 
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+
 	/* open the gate */
 	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
 	mst->msg[0].addr = mst->i2c_addr;
@@ -319,7 +355,10 @@
 	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
 	mst->msg[num + 1].len = 4;
 
-	return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
+	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
+			num : -EIO);
+	mutex_unlock(&mst->i2c_buffer_lock);
+	return ret;
 }
 
 static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
@@ -390,8 +429,18 @@
 int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
 				struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
-	u8 tx[4];
-	struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
+	int ret;
+
+	mutex_init(&mst->i2c_buffer_lock);
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+	memset(mst->msg, 0, sizeof(struct i2c_msg));
+	mst->msg[0].addr = i2c_addr >> 1;
+	mst->msg[0].flags = 0;
+	mst->msg[0].buf = mst->i2c_write_buffer;
+	mst->msg[0].len = 4;
 
 	mst->device_rev = device_rev;
 	mst->i2c_adap = i2c_adap;
@@ -431,9 +480,12 @@
 				"DiBX000: could not initialize the master i2c_adapter\n");
 
 	/* initialize the i2c-master by closing the gate */
-	dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
+	dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
 
-	return i2c_transfer(i2c_adap, &m, 1) == 1;
+	ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
+	mutex_unlock(&mst->i2c_buffer_lock);
+
+	return ret;
 }
 
 EXPORT_SYMBOL(dibx000_init_i2c_master);
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index f031165..5e01147 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -33,6 +33,7 @@
 	struct i2c_msg msg[34];
 	u8 i2c_write_buffer[8];
 	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
 };
 
 extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 476300c..ab732b2 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -1879,6 +1879,7 @@
 
 	switch (opcode) {
 	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
+	case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
 		hci_cc_fm_enable_rsp(hdev, skb);
 		break;
 	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
@@ -1886,6 +1887,7 @@
 		break;
 
 	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
+	case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
 		hci_cc_fm_disable_rsp(hdev, skb);
 		break;
 
@@ -1900,8 +1902,6 @@
 	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
 	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
 	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_CH_DET_THRESHOLD):
-	case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
-	case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
 	case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
 	case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
 	case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
@@ -2609,7 +2609,7 @@
 
 		} else
 			retval = -EINVAL;
-
+		break;
 	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
 		if (retval < 0) {
@@ -3356,12 +3356,7 @@
 					struct v4l2_hw_freq_seek *seek)
 {
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
-	int dir;
-	if (seek->seek_upward)
-		dir = SRCH_DIR_UP;
-	else
-		dir = SRCH_DIR_DOWN;
-	return iris_search(radio, CTRL_ON, dir);
+	return iris_search(radio, CTRL_ON, seek->seek_upward);
 }
 
 static int iris_vidioc_querycap(struct file *file, void *priv,
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 1c4f616..212e5d5 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -92,6 +92,7 @@
 	/* synchrnous xfr data */
 	unsigned char sync_xfr_regs[XFR_REG_NUM];
 	struct completion sync_xfr_start;
+	struct completion shutdown_done;
 	struct completion sync_req_done;
 	int tune_req;
 	/* internal register status */
@@ -1073,6 +1074,19 @@
 	tavarua_handle_interrupts(radio);
 }
 
+static void fm_shutdown(struct work_struct *work)
+{
+	struct tavarua_device *radio = container_of(work,
+					struct tavarua_device, work.work);
+	FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
+	if (radio->pdata->config_i2s_gpio != NULL)
+		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
+	FMDERR("%s: Shutting down FM SOC\n", __func__);
+	radio->pdata->fm_shutdown(radio->pdata);
+	complete(&radio->shutdown_done);
+}
+
+
 /*************************************************************************
  * irq helper functions
  ************************************************************************/
@@ -1100,9 +1114,6 @@
    * is limited to ten characters; it is only used for generating the "command"
    * for the kernel thread(s) (which can be seen in ps or top).
    */
-	radio->wqueue  = create_singlethread_workqueue("kfmradio");
-	if (!radio->wqueue)
-		return -ENOMEM;
   /* allocate an interrupt line */
   /* On success, request_irq() returns 0 if everything goes  as
      planned.  Your interrupt handler will start receiving its
@@ -1156,10 +1167,9 @@
 		return -EINVAL;
 	irq = radio->pdata->irq;
 	disable_irq_wake(irq);
+	free_irq(irq, radio);
 	cancel_delayed_work_sync(&radio->work);
 	flush_workqueue(radio->wqueue);
-	free_irq(irq, radio);
-	destroy_workqueue(radio->wqueue);
 	return 0;
 }
 
@@ -1805,6 +1815,7 @@
 	char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
 	int bahama_present = -ENODEV;
 
+	INIT_DELAYED_WORK(&radio->work, read_int_stat);
 	if (!atomic_dec_and_test(&radio->users)) {
 		pr_err("%s: Device already in use."
 			"Try again later", __func__);
@@ -2037,10 +2048,7 @@
 
 	FMDBG("In %s", __func__);
 
-	/* disable radio ctrl */
-	retval = tavarua_write_register(radio, RDCTRL, 0x00);
-
-	FMDBG("%s, Disable IRQs\n", __func__);
+	FMDBG("%s, Disabling the IRQs\n", __func__);
 	/* disable irq */
 	retval = tavarua_disable_irq(radio);
 	if (retval < 0) {
@@ -2048,11 +2056,22 @@
 		return retval;
 	}
 
+	/* disable radio ctrl */
+	retval = tavarua_write_register(radio, RDCTRL, 0x00);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: failed to disable FM\n", __func__);
+		return retval;
+	}
+
+	init_completion(&radio->shutdown_done);
+
 	bahama_present = is_bahama();
 
 	if (bahama_present == -ENODEV)
 		return -ENODEV;
 
+	INIT_DELAYED_WORK(&radio->work, fm_shutdown);
+
 	if (bahama_present)	{
 		/*Write first sequence of bytes to FM_CTL0*/
 		for (i = 0; i < 1; i++) {
@@ -2131,15 +2150,15 @@
 	}
 exit:
 	FMDBG("%s, Calling fm_shutdown\n", __func__);
+	queue_delayed_work(radio->wqueue, &radio->work,
+				msecs_to_jiffies(TAVARUA_DELAY/2));
 	/* teardown gpio and pmic */
-
 	marimba_set_fm_status(radio->marimba, false);
-	radio->pdata->fm_shutdown(radio->pdata);
-	if (radio->pdata->config_i2s_gpio != NULL)
-		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
+	wait_for_completion(&radio->shutdown_done);
 	radio->handle_irq = 1;
 	atomic_inc(&radio->users);
 	radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+	flush_workqueue(radio->wqueue);
 	return retval;
 }
 
@@ -2582,6 +2601,7 @@
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
 	int retval = 0;
+	int cnt = 0;
 	unsigned char xfr_buf[XFR_REG_NUM];
 	signed char cRmssiThreshold;
 	signed char ioc;
@@ -2712,6 +2732,69 @@
 		ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
 			IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
 		break;
+	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
+		size = 0x04;
+		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+		xfr_buf[1] = ON_CHANNEL_TH_MSB;
+		xfr_buf[2] = ON_CHANNEL_TH_LSB;
+		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+		if (retval < 0) {
+			pr_err("%s: Failed to write\n", __func__);
+			return retval;
+		}
+		/*Wait for the XFR interrupt */
+		msleep(TAVARUA_DELAY*10);
+		retval = tavarua_read_registers(radio, XFRDAT0, 4);
+		if (retval < 0) {
+			pr_err("%s: On Ch. DET: Read failure\n", __func__);
+			return retval;
+		}
+		for (cnt = 0; cnt < 4; cnt++)
+			FMDBG("On-Channel data set is : 0x%x\t",
+				(int)radio->registers[XFRDAT0+cnt]);
+
+		ctrl->value =	LSH_DATA(radio->registers[XFRDAT0],   24) |
+				LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+				LSH_DATA(radio->registers[XFRDAT0+2],  8) |
+				(radio->registers[XFRDAT0+3]);
+		FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
+		break;
+	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
+		size = 0x04;
+		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+		xfr_buf[1] = OFF_CHANNEL_TH_MSB;
+		xfr_buf[2] = OFF_CHANNEL_TH_LSB;
+		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+		if (retval < 0) {
+			pr_err("%s: Failed to write\n", __func__);
+			return retval;
+		}
+		/*Wait for the XFR interrupt */
+		msleep(TAVARUA_DELAY*10);
+		retval = tavarua_read_registers(radio, XFRDAT0, 4);
+		if (retval < 0) {
+			pr_err("%s: Off Ch. DET: Read failure\n", __func__);
+			return retval;
+		}
+		for (cnt = 0; cnt < 4; cnt++)
+			FMDBG("Off-channel data set is : 0x%x\t",
+				(int)radio->registers[XFRDAT0+cnt]);
+
+		ctrl->value =	LSH_DATA(radio->registers[XFRDAT0],   24) |
+				LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+				LSH_DATA(radio->registers[XFRDAT0+2],  8) |
+				(radio->registers[XFRDAT0+3]);
+		FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
+		break;
+	/*
+	 * These IOCTL's are place holders to keep the
+	 * driver compatible with change in frame works for IRIS
+	 */
+	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+	case V4L2_CID_PRIVATE_SINR_SAMPLES:
+	case V4L2_CID_PRIVATE_IRIS_GET_SINR:
+		retval = 0;
+		break;
 	default:
 		retval = -EINVAL;
 	}
@@ -2916,7 +2999,7 @@
 		}
 		/* check if off */
 		else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
-			FMDBG("turning off...\n");
+			FMDBG("%s: turning off...\n", __func__);
 			tavarua_write_register(radio, RDCTRL, ctrl->value);
 			/* flush the event and work queues */
 			kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
@@ -2925,7 +3008,7 @@
 			 * queue the READY event from the host side
 			 * in case of FM off
 			 */
-			tavarua_q_event(radio, TAVARUA_EVT_RADIO_READY);
+			tavarua_q_event(radio, TAVARUA_EVT_RADIO_DISABLED);
 
 			FMDBG("%s, Disable All Interrupts\n", __func__);
 			/* disable irq */
@@ -3090,7 +3173,7 @@
 		SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
 					IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
 		break;
-	case V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD:
+	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
 		size = 0x04;
 		/* Poking the value of ON Channel Threshold value */
 		xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3110,39 +3193,13 @@
 		retval = tavarua_write_registers(radio, XFRCTRL,
 				xfr_buf, size+3);
 		if (retval < 0) {
-			FMDBG("Failed to write\n");
-			return retval;
-		}
-		/*Wait for the XFR interrupt */
-		msleep(TAVARUA_DELAY*15);
-
-		for (cnt = 0; cnt < 5; cnt++) {
-			xfr_buf[cnt] = 0;
-			radio->registers[XFRDAT0+cnt] = 0x0;
-		}
-
-		/* Peeking Regs 0x88C2-0x88C4 */
-		size = 0x04;
-		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
-		xfr_buf[1] = ON_CHANNEL_TH_MSB;
-		xfr_buf[2] = ON_CHANNEL_TH_LSB;
-		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
-		if (retval < 0) {
 			pr_err("%s: Failed to write\n", __func__);
 			return retval;
 		}
 		/*Wait for the XFR interrupt */
 		msleep(TAVARUA_DELAY*10);
-		retval = tavarua_read_registers(radio, XFRDAT0, 4);
-		if (retval < 0) {
-			pr_err("%s: On Ch. DET: Read failure\n", __func__);
-			return retval;
-		}
-		for (cnt = 0; cnt < 4; cnt++)
-			FMDBG("On-Channel data set is : 0x%x\t",
-				(int)radio->registers[XFRDAT0+cnt]);
 		break;
-	case V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD:
+	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
 		size = 0x04;
 		/* Poking the value of OFF Channel Threshold value */
 		xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3167,32 +3224,6 @@
 		}
 		/*Wait for the XFR interrupt */
 		msleep(TAVARUA_DELAY*10);
-
-		for (cnt = 0; cnt < 5; cnt++) {
-			xfr_buf[cnt] = 0;
-			radio->registers[XFRDAT0+cnt] = 0x0;
-		}
-
-		/* Peeking Regs 0x88C2-0x88C4 */
-		size = 0x04;
-		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
-		xfr_buf[1] = OFF_CHANNEL_TH_MSB;
-		xfr_buf[2] = OFF_CHANNEL_TH_LSB;
-		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
-		if (retval < 0) {
-			pr_err("%s: Failed to write\n", __func__);
-			return retval;
-		}
-		/*Wait for the XFR interrupt */
-		msleep(TAVARUA_DELAY*10);
-		retval = tavarua_read_registers(radio, XFRDAT0, 4);
-		if (retval < 0) {
-			pr_err("%s: Off Ch. DET: Read failure\n", __func__);
-			return retval;
-		}
-		for (cnt = 0; cnt < 4; cnt++)
-			FMDBG("Off-channel data set is : 0x%x\t",
-				(int)radio->registers[XFRDAT0+cnt]);
 		break;
 	/* TX Controls */
 
@@ -3264,6 +3295,8 @@
 	case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
 	case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
 	case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
+	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+	case V4L2_CID_PRIVATE_SINR_SAMPLES:
 		retval = 0;
 		break;
 	default:
@@ -3598,13 +3631,8 @@
 					struct v4l2_hw_freq_seek *seek)
 {
 	struct tavarua_device  *radio = video_get_drvdata(video_devdata(file));
-	int dir;
-	if (seek->seek_upward)
-		dir = SRCH_DIR_UP;
-	else
-		dir = SRCH_DIR_DOWN;
 	FMDBG("starting search\n");
-	return tavarua_search(radio, CTRL_ON, dir);
+	return tavarua_search(radio, CTRL_ON, seek->seek_upward);
 }
 
 /*
@@ -4014,7 +4042,9 @@
 	video_set_drvdata(radio->videodev, radio);
     /*Start the worker thread for event handling and register read_int_stat
 	as worker function*/
-	INIT_DELAYED_WORK(&radio->work, read_int_stat);
+	radio->wqueue  = create_singlethread_workqueue("kfmradio");
+	if (!radio->wqueue)
+		return -ENOMEM;
 
 	/* register video device */
 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
@@ -4054,6 +4084,8 @@
 	/* disable irq */
 	tavarua_disable_irq(radio);
 
+	destroy_workqueue(radio->wqueue);
+
 	video_unregister_device(radio->videodev);
 
 	/* free internal buffers */
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index a9b8e40..6744479 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -21,27 +21,22 @@
 #include <media/rc-core.h>
 #include <media/gpio-ir-recv.h>
 
-#define TSOP_DRIVER_NAME	"gpio-rc-recv"
-#define TSOP_DEVICE_NAME	"gpio_ir_recv"
+#define GPIO_IR_DRIVER_NAME	"gpio-rc-recv"
+#define GPIO_IR_DEVICE_NAME	"gpio_ir_recv"
 
 struct gpio_rc_dev {
 	struct rc_dev *rcdev;
-	struct mutex lock;
 	unsigned int gpio_nr;
 	bool active_low;
-	bool can_wakeup;
-	struct work_struct work;
 };
 
-static void ir_decoder_work(struct work_struct *work)
+static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
 {
-	struct gpio_rc_dev *gpio_dev = container_of(work,
-			struct gpio_rc_dev, work);
+	struct gpio_rc_dev *gpio_dev = dev_id;
 	unsigned int gval;
 	int rc = 0;
 	enum raw_event_type type = IR_SPACE;
 
-	mutex_lock(&gpio_dev->lock);
 	gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
 
 	if (gval < 0)
@@ -60,15 +55,6 @@
 	ir_raw_event_handle(gpio_dev->rcdev);
 
 err_get_value:
-	mutex_unlock(&gpio_dev->lock);
-}
-
-static irqreturn_t gpio_ir_recv_irq_handler(int irq, void *data)
-{
-	struct gpio_rc_dev *gpio_dev = data;
-
-	schedule_work(&gpio_dev->work);
-
 	return IRQ_HANDLED;
 }
 
@@ -78,7 +64,7 @@
 	struct rc_dev *rcdev;
 	const struct gpio_ir_recv_platform_data *pdata =
 					pdev->dev.platform_data;
-	int rc = 0;
+	int rc;
 
 	if (!pdata)
 		return -EINVAL;
@@ -90,8 +76,6 @@
 	if (!gpio_dev)
 		return -ENOMEM;
 
-	mutex_init(&gpio_dev->lock);
-
 	rcdev = rc_allocate_device();
 	if (!rcdev) {
 		rc = -ENOMEM;
@@ -99,18 +83,15 @@
 	}
 
 	rcdev->driver_type = RC_DRIVER_IR_RAW;
-	rcdev->allowed_protos = RC_TYPE_NEC;
-	rcdev->input_name = TSOP_DEVICE_NAME;
+	rcdev->allowed_protos = RC_TYPE_ALL;
+	rcdev->input_name = GPIO_IR_DEVICE_NAME;
 	rcdev->input_id.bustype = BUS_HOST;
-	rcdev->driver_name = TSOP_DRIVER_NAME;
-	rcdev->map_name = RC_MAP_SAMSUNG_NECX;
+	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
+	rcdev->map_name = RC_MAP_EMPTY;
 
 	gpio_dev->rcdev = rcdev;
 	gpio_dev->gpio_nr = pdata->gpio_nr;
 	gpio_dev->active_low = pdata->active_low;
-	gpio_dev->can_wakeup = pdata->can_wakeup;
-
-	INIT_WORK(&gpio_dev->work, ir_decoder_work);
 
 	rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
 	if (rc < 0)
@@ -127,22 +108,15 @@
 
 	platform_set_drvdata(pdev, gpio_dev);
 
-	rc = request_irq(gpio_to_irq(pdata->gpio_nr), gpio_ir_recv_irq_handler,
+	rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
+				gpio_ir_recv_irq,
 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-			"gpio-ir-recv-irq", gpio_dev);
+					"gpio-ir-recv-irq", gpio_dev);
 	if (rc < 0)
 		goto err_request_irq;
 
-	if (pdata->can_wakeup == true) {
-		rc = enable_irq_wake(gpio_to_irq(pdata->gpio_nr));
-		if (rc < 0)
-			goto err_enable_irq_wake;
-	}
-
 	return 0;
 
-err_enable_irq_wake:
-	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
 err_request_irq:
 	platform_set_drvdata(pdev, NULL);
 	rc_unregister_device(rcdev);
@@ -153,7 +127,6 @@
 	rc_free_device(rcdev);
 	rcdev = NULL;
 err_allocate_device:
-	mutex_destroy(&gpio_dev->lock);
 	kfree(gpio_dev);
 	return rc;
 }
@@ -162,24 +135,57 @@
 {
 	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 
-	flush_work_sync(&gpio_dev->work);
-	disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
 	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
 	platform_set_drvdata(pdev, NULL);
 	rc_unregister_device(gpio_dev->rcdev);
 	gpio_free(gpio_dev->gpio_nr);
 	rc_free_device(gpio_dev->rcdev);
-	mutex_destroy(&gpio_dev->lock);
 	kfree(gpio_dev);
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int gpio_ir_recv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+	else
+		disable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+	return 0;
+}
+
+static int gpio_ir_recv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+	else
+		enable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+	return 0;
+}
+
+static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
+	.suspend        = gpio_ir_recv_suspend,
+	.resume         = gpio_ir_recv_resume,
+};
+#endif
+
 static struct platform_driver gpio_ir_recv_driver = {
 	.probe  = gpio_ir_recv_probe,
 	.remove = __devexit_p(gpio_ir_recv_remove),
 	.driver = {
-		.name   = TSOP_DRIVER_NAME,
+		.name   = GPIO_IR_DRIVER_NAME,
 		.owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &gpio_ir_recv_pm_ops,
+#endif
 	},
 };
 
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 3c315f9..2b5cd21 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -843,7 +843,7 @@
 			static struct xc2028_ctrl ctl = {
 				.fname   = XC3028L_DEFAULT_FIRMWARE,
 				.max_len = 64,
-				.demod   = 5000,
+				.demod   = XC3028_FE_DIBCOM52,
 				/* This is true for all demods with
 					v36 firmware? */
 				.type    = XC2028_D2633,
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index e70a0a5..ec034b1 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -48,9 +48,16 @@
 	depends on MSM_CAMERA
 	---help---
 	  OV 5M Bayer Sensor with AutoFocus
+
+config AD5046_ACT
+	bool "Lens actuator ad5046"
+	depends on MSM_CAMERA && OV5647
+	---help---
+	  ad5046 lens actuator driver for ov5647.
+	  Say Y here if this is msm7627A variant platform.
 config WEBCAM_OV7692_QRD
 	bool "Sensor OV7692 QRD(VGA YUV)"
-	depends on MSM_CAMERA && ARCH_MSM7X27A && !MSM_CAMERA_V4L2
+	depends on MSM_CAMERA && ARCH_MSM7X27A
 	default n
 	---help---
 	  Omni Vision VGA YUV Sensor for QRD Devices
@@ -237,3 +244,18 @@
 		4 mipi lanes, preview config = 1984 * 1508 at 30 fps,
 		snapshot config = 4000 * 3000 at 20 fps,
 		hfr video at 60, 90 and 120 fps.
+
+config IMX091
+        bool "Sensor imx091 (Sony 13MP)"
+        depends on MSM_CAMERA
+	---help---
+	  Sony 13MP sensor back camera that uses 4 mipi lanes,
+	  runs at 30 fps preview and 14 fps snapshot
+
+config MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	tristate "Qualcomm MSM V4l2 video overlay device"
+	---help---
+	  Enables support for the MSM V4L2 video
+	  overlay driver. This allows video rendering
+	  apps to render overlaid video using Video4Linux2
+	  APIs, by using /dev/videoX device
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 8703669..f817561 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -39,17 +39,17 @@
   obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
   obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
   obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
+  obj-$(CONFIG_OV5647) += ov5647.o ov5647_reg.o
   obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.o
+  obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o
+  obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd.o
 endif
 obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o
 obj-$(CONFIG_VB6801) += vb6801.o
 obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o
-obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
-obj-$(CONFIG_OV5647) += ov5647.o ov5647_reg.o
-obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o
-obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd.o
 obj-$(CONFIG_OV5640) += ov5640.o
 obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o
 
 obj-$(CONFIG_MT9D113) += mt9d113.o mt9d113_reg.o
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += wfd/
+obj-$(CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE) += msm_v4l2_video.o
diff --git a/drivers/media/video/msm/actuators/Makefile b/drivers/media/video/msm/actuators/Makefile
index f0a0c69..d492155 100644
--- a/drivers/media/video/msm/actuators/Makefile
+++ b/drivers/media/video/msm/actuators/Makefile
@@ -4,3 +4,4 @@
 obj-$(CONFIG_MSM_ACTUATOR) += msm_actuator.o
 obj-$(CONFIG_IMX074_ACT) += imx074_act.o
 obj-$(CONFIG_DW9712_ACT) += dw9712_act.o
+obj-$(CONFIG_AD5046_ACT) += ad5046_act.o
diff --git a/drivers/media/video/msm/actuators/ad5046_act.c b/drivers/media/video/msm/actuators/ad5046_act.c
new file mode 100644
index 0000000..d99774b
--- /dev/null
+++ b/drivers/media/video/msm/actuators/ad5046_act.c
@@ -0,0 +1,315 @@
+/* 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_actuator.h"
+#include "msm_camera_i2c.h"
+
+#define	AD5046_TOTAL_STEPS_NEAR_TO_FAR			32
+static uint8_t  mode_mask = 0x09;
+DEFINE_MUTEX(ad5046_act_mutex);
+static struct msm_actuator_ctrl_t ad5046_act_t;
+
+static struct region_params_t g_regions[] = {
+	/* step_bound[0] - macro side boundary
+	 * step_bound[1] - infinity side boundary
+	 */
+	/* Region 1 */
+	{
+		.step_bound = {AD5046_TOTAL_STEPS_NEAR_TO_FAR, 0},
+		.code_per_step = 2,
+	},
+};
+
+static uint16_t g_scenario[] = {
+	/* MOVE_NEAR and MOVE_FAR dir*/
+	AD5046_TOTAL_STEPS_NEAR_TO_FAR,
+};
+
+static int32_t ad5046_af_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length,
+				struct msm_actuator_ctrl_t *a_ctrl)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(a_ctrl->i2c_client.client->adapter, msg, 1) < 0) {
+		pr_err("ad5046_af_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t ad5046_af_i2c_write_b_sensor(struct msm_actuator_ctrl_t *a_ctrl,
+			      uint8_t waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = bdata;
+	rc = ad5046_af_i2c_txdata(a_ctrl->i2c_addr, buf, 2, a_ctrl);
+	if (rc < 0)
+		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+				waddr, bdata);
+
+	return rc;
+}
+
+static int32_t ad5046_wrapper_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
+	int16_t next_lens_position, void *params)
+{
+	uint8_t msb, lsb;
+
+	msb = (next_lens_position & 0xFF00) >> 8;
+	lsb = next_lens_position & 0xFF;
+	ad5046_af_i2c_write_b_sensor(a_ctrl, msb, lsb);
+
+	return 0;
+}
+
+int32_t msm_ad5046_act_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	int dir,
+	int32_t num_steps)
+{
+	int32_t rc = 0;
+	int8_t sign_dir = 0;
+	int16_t dest_step_pos = 0;
+	uint8_t code_val_msb, code_val_lsb;
+
+	CDBG("%s called, dir %d, num_steps %d\n",
+		__func__,
+		dir,
+		num_steps);
+
+	/* Determine sign direction */
+	if (dir == MOVE_NEAR)
+		sign_dir = 20;
+	else if (dir == MOVE_FAR)
+		sign_dir = -20;
+	else {
+		pr_err("Illegal focus direction\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	/* Determine destination step position */
+	dest_step_pos = a_ctrl->curr_step_pos +
+		(sign_dir * num_steps);
+
+	if (dest_step_pos < 0)
+		dest_step_pos = 0;
+	else if (dest_step_pos > 1023)
+		dest_step_pos = 1023;
+
+	if (dest_step_pos == a_ctrl->curr_step_pos)
+		return rc;
+
+	a_ctrl->curr_step_pos = dest_step_pos;
+
+	code_val_msb = (uint8_t)((dest_step_pos & 0x03FF) >> 4);
+	code_val_lsb = (uint8_t)((dest_step_pos & 0x000F) << 4);
+	code_val_lsb |= mode_mask;
+
+	rc = ad5046_af_i2c_write_b_sensor(a_ctrl, code_val_msb, code_val_lsb);
+	/* DAC Setting */
+	if (rc != 0) {
+		CDBG(KERN_ERR "%s: WRITE ERROR lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+	} else {
+		CDBG(KERN_ERR "%s: Successful lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+		/* delay may set based on the steps moved
+		when I2C write successful */
+		msleep(100);
+	}
+	return 0;
+}
+
+static int32_t ad5046_set_default_focus(
+	struct msm_actuator_ctrl_t *a_ctrl)
+{
+	uint8_t  code_val_msb = 0;
+	uint8_t  code_val_lsb = 0;
+	int rc = 0;
+
+	CDBG("ad5046_set_default_focus called\n");
+
+	if (!a_ctrl->step_position_table)
+		a_ctrl->func_tbl.actuator_init_table(a_ctrl);
+
+	a_ctrl->curr_step_pos = 200;
+
+	code_val_msb = (a_ctrl->curr_step_pos & 0x03FF) >> 4;
+	code_val_lsb = (a_ctrl->curr_step_pos & 0x000F) << 4;
+	code_val_lsb |= mode_mask;
+
+	CDBG(KERN_ERR "ad5046_set_default_focus:lens pos = %d",
+		 a_ctrl->curr_step_pos);
+	rc = ad5046_af_i2c_write_b_sensor(a_ctrl, code_val_msb, code_val_lsb);
+	/* DAC Setting */
+	if (rc != 0)
+		CDBG(KERN_ERR "%s: WRITE ERROR lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+	else
+		CDBG(KERN_ERR "%s: WRITE successful lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+
+	usleep_range(10000, 11000);
+	return 0;
+}
+
+static const struct i2c_device_id ad5046_act_i2c_id[] = {
+	{"ad5046_act", (kernel_ulong_t)&ad5046_act_t},
+	{ }
+};
+
+static int ad5046_act_config(void __user *argp)
+{
+	LINFO("%s called\n", __func__);
+	return (int) msm_actuator_config(&ad5046_act_t, argp);
+}
+
+static int ad5046_i2c_add_driver_table(void)
+{
+	LINFO("%s called\n", __func__);
+	return (int) msm_actuator_init_table(&ad5046_act_t);
+}
+
+int32_t ad5046_act_i2c_probe(
+	struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int32_t rc = 0;
+
+	rc = msm_actuator_i2c_probe(client, id);
+
+	msleep(50);
+
+	return rc;
+}
+static struct i2c_driver ad5046_act_i2c_driver = {
+	.id_table = ad5046_act_i2c_id,
+	.probe  = ad5046_act_i2c_probe,
+	.remove = __exit_p(ad5046_act_i2c_remove),
+	.driver = {
+		.name = "ad5046_act",
+	},
+};
+
+static int __init ad5046_i2c_add_driver(void)
+{
+	int rc = 0;
+
+	LINFO("%s called :%x\n", __func__, ad5046_act_t.i2c_addr);
+	rc = i2c_add_driver(ad5046_act_t.i2c_driver);
+	LINFO("%s called:%d %x\n", __func__, rc, ad5046_act_t.i2c_addr);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops ad5046_act_subdev_core_ops;
+
+static struct v4l2_subdev_ops ad5046_act_subdev_ops = {
+	.core = &ad5046_act_subdev_core_ops,
+};
+
+static int32_t ad5046_act_create_subdevice(
+	void *board_info,
+	void *sdev)
+{
+	int rc = 0;
+
+	struct msm_actuator_info *ptr;
+	LINFO("%s called\n", __func__);
+
+	ptr = board_info;
+	ad5046_act_t.vcm_pwd = ptr->vcm_pwd;
+	ad5046_act_t.vcm_enable = ptr->vcm_enable;
+	LINFO("vcm info: %x %x\n", ad5046_act_t.vcm_pwd,
+				ad5046_act_t.vcm_enable);
+	if (ad5046_act_t.vcm_enable) {
+		rc = gpio_request(ad5046_act_t.vcm_pwd, "ov5647_af");
+		if (!rc) {
+			LINFO("Enable VCM PWD\n");
+			gpio_direction_output(ad5046_act_t.vcm_pwd, 1);
+		}
+		msleep(20);
+
+	}
+	return (int) msm_actuator_create_subdevice(&ad5046_act_t,
+		ptr->board_info,
+		(struct v4l2_subdev *)sdev);
+}
+
+static struct msm_actuator_ctrl_t ad5046_act_t = {
+	.i2c_driver = &ad5046_act_i2c_driver,
+	.i2c_addr = 0x18>>1,
+	.act_v4l2_subdev_ops = &ad5046_act_subdev_ops,
+	.actuator_ext_ctrl = {
+		.a_init_table = ad5046_i2c_add_driver_table,
+		.a_create_subdevice = ad5046_act_create_subdevice,
+		.a_config = ad5046_act_config,
+	},
+
+	.i2c_client = {
+		.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+	},
+
+	.set_info = {
+		.total_steps = AD5046_TOTAL_STEPS_NEAR_TO_FAR,
+	},
+
+	.curr_step_pos = 0,
+	.curr_region_index = 0,
+	.initial_code = 0x0,
+	.actuator_mutex = &ad5046_act_mutex,
+
+	.func_tbl = {
+		.actuator_init_table = msm_actuator_init_table,
+		.actuator_move_focus = msm_ad5046_act_move_focus,
+		.actuator_set_default_focus = ad5046_set_default_focus,
+		.actuator_i2c_write = ad5046_wrapper_i2c_write,
+	},
+
+	.get_info = {
+		.focal_length_num = 46,
+		.focal_length_den = 10,
+		.f_number_num = 265,
+		.f_number_den = 100,
+		.f_pix_num = 14,
+		.f_pix_den = 10,
+		.total_f_dist_num = 197681,
+		.total_f_dist_den = 1000,
+	},
+
+	/* Initialize scenario */
+	.ringing_scenario[MOVE_NEAR] = g_scenario,
+	.scenario_size[MOVE_NEAR] = ARRAY_SIZE(g_scenario),
+	.ringing_scenario[MOVE_FAR] = g_scenario,
+	.scenario_size[MOVE_FAR] = ARRAY_SIZE(g_scenario),
+
+	/* Initialize region params */
+	.region_params = g_regions,
+	.region_size = ARRAY_SIZE(g_regions),
+};
+
+subsys_initcall(ad5046_i2c_add_driver);
+MODULE_DESCRIPTION("AD5046 actuator");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/actuators/dw9712_act.c b/drivers/media/video/msm/actuators/dw9712_act.c
index 562290f..546cffa 100644
--- a/drivers/media/video/msm/actuators/dw9712_act.c
+++ b/drivers/media/video/msm/actuators/dw9712_act.c
@@ -101,9 +101,9 @@
 
 	/* Determine sign direction */
 	if (dir == MOVE_NEAR)
-		sign_dir = 1;
+		sign_dir = 16;
 	else if (dir == MOVE_FAR)
-		sign_dir = -1;
+		sign_dir = -16;
 	else {
 		pr_err("Illegal focus direction\n");
 		rc = -EINVAL;
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index fab3a21..aa6f966 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -90,6 +90,42 @@
 	return rc;
 }
 
+int32_t imx074_act_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	int dir,
+	int32_t num_steps)
+{
+	int32_t step_direction, dest_step_position, bit_mask;
+	int32_t rc = 0;
+
+	if (num_steps == 0)
+		return rc;
+
+	if (dir == MOVE_NEAR) {
+		step_direction = 1;
+		bit_mask = 0x80;
+	} else if (dir == MOVE_FAR) {
+		step_direction = -1;
+		bit_mask = 0x00;
+	} else {
+		CDBG("imx074_move_focus: Illegal focus direction");
+		return -EINVAL;
+	}
+	dest_step_position = a_ctrl->curr_step_pos +
+		(step_direction * num_steps);
+	if (dest_step_position < 0)
+		dest_step_position = 0;
+	else if (dest_step_position > IMX074_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = IMX074_TOTAL_STEPS_NEAR_TO_FAR;
+
+	msm_camera_i2c_write(&a_ctrl->i2c_client,
+		0x00,
+		((num_steps * g_regions[0].code_per_step) | bit_mask),
+		MSM_CAMERA_I2C_BYTE_DATA);
+	a_ctrl->curr_step_pos = dest_step_position;
+	return rc;
+}
+
 static int32_t imx074_set_default_focus(
 	struct msm_actuator_ctrl_t *a_ctrl)
 {
@@ -228,7 +264,7 @@
 
 	.func_tbl = {
 		.actuator_init_table = msm_actuator_init_table,
-		.actuator_move_focus = msm_actuator_move_focus,
+		.actuator_move_focus = imx074_act_move_focus,
 		.actuator_write_focus = imx074_act_write_focus,
 		.actuator_set_default_focus = imx074_set_default_focus,
 		.actuator_init_focus = imx074_act_init_focus,
@@ -244,6 +280,10 @@
 		.f_pix_den = 10,
 		.total_f_dist_num = 197681,
 		.total_f_dist_den = 1000,
+		.hor_view_angle_num = 548,
+		.hor_view_angle_den = 10,
+		.ver_view_angle_num = 425,
+		.ver_view_angle_den = 10,
 	},
 
 	/* Initialize scenario */
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index 476615d..3a642c7 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -142,6 +142,7 @@
 	struct csic_device *csic_dev;
 	struct msm_camera_csi_params *csic_params;
 	void __iomem *csicbase;
+	int i;
 
 	csic_dev = v4l2_get_subdevdata(cfg_params->subdev);
 	csicbase = csic_dev->base;
@@ -163,24 +164,14 @@
 	CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
 	msm_io_w(val, csicbase + MIPI_PROTOCOL_CONTROL);
 
-	val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
-		(0x1 <<
-		MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
-		(0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
-		(0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
-	CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
-	msm_io_w(val, csicbase + MIPI_CALIBRATION_CONTROL);
-
 	val = (csic_params->settle_cnt <<
 		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
 		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
 		(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
 		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
 	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
-	msm_io_w(val, csicbase + MIPI_PHY_D0_CONTROL2);
-	msm_io_w(val, csicbase + MIPI_PHY_D1_CONTROL2);
-	msm_io_w(val, csicbase + MIPI_PHY_D2_CONTROL2);
-	msm_io_w(val, csicbase + MIPI_PHY_D3_CONTROL2);
+	for (i = 0; i < csic_params->lane_cnt; i++)
+		msm_io_w(val, csicbase + MIPI_PHY_D0_CONTROL2 + i * 4);
 
 
 	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
@@ -233,7 +224,9 @@
 
 	pr_info("msm_csic_irq: %x\n", (unsigned int)csic_dev->base);
 	irq = msm_io_r(csic_dev->base + MIPI_INTERRUPT_STATUS);
-	pr_info("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
+	pr_info("%s MIPI_INTERRUPT_STATUS = 0x%x 0x%x\n",
+			__func__, irq,
+			msm_io_r(csic_dev->base + MIPI_PROTOCOL_CONTROL));
 	msm_io_w(irq, csic_dev->base + MIPI_INTERRUPT_STATUS);
 
 	/* TODO: Needs to send this info to upper layers */
@@ -372,7 +365,7 @@
 	}
 
 	rc = request_irq(new_csic_dev->irq->start, msm_csic_irq,
-		IRQF_TRIGGER_RISING, "csic", new_csic_dev);
+			IRQF_TRIGGER_HIGH, "csic", new_csic_dev);
 	if (rc < 0) {
 		release_mem_region(new_csic_dev->mem->start,
 			resource_size(new_csic_dev->mem));
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 7a0ee4d..e531089 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -51,8 +51,8 @@
 #define CSID_TG_DT_n_CFG_1_ADDR                     0xAC
 #define CSID_TG_DT_n_CFG_2_ADDR                     0xB0
 #define CSID_TG_DT_n_CFG_3_ADDR                     0xD8
-
-#define DBG_CSID 0
+#define CSID_RST_DONE_IRQ_BITSHIFT                  11
+#define CSID_RST_STB_ALL                            0x7FFF
 
 static int msm_csid_cid_lut(
 	struct msm_camera_csid_lut_params *csid_lut_params,
@@ -92,6 +92,7 @@
 	csid_dev = v4l2_get_subdevdata(cfg_params->subdev);
 	csidbase = csid_dev->base;
 	csid_params = cfg_params->parms;
+
 	val = csid_params->lane_cnt - 1;
 	val |= csid_params->lane_assign << 2;
 	val |= 0x1 << 10;
@@ -105,8 +106,9 @@
 	if (rc < 0)
 		return rc;
 
-	msm_io_w(0x7fF10800, csidbase + CSID_IRQ_MASK_ADDR);
-	msm_io_w(0x7fF10800, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
+	val = ((1 << csid_params->lane_cnt) - 1) << 20;
+	msm_io_w(0x7f010800 | val, csidbase + CSID_IRQ_MASK_ADDR);
+	msm_io_w(0x7f010800 | val, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
 
 	msleep(20);
 	return rc;
@@ -117,11 +119,21 @@
 	uint32_t irq;
 	struct csid_device *csid_dev = data;
 	irq = msm_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
-	CDBG("%s CSID_IRQ_STATUS_ADDR = 0x%x\n", __func__, irq);
+	CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
+		 __func__, csid_dev->pdev->id, irq);
+	if (irq & (0x1 << CSID_RST_DONE_IRQ_BITSHIFT))
+			complete(&csid_dev->reset_complete);
 	msm_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
 	return IRQ_HANDLED;
 }
 
+static void msm_csid_reset(struct csid_device *csid_dev)
+{
+	msm_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
+	wait_for_completion_interruptible(&csid_dev->reset_complete);
+	return;
+}
+
 static int msm_csid_subdev_g_chip_ident(struct v4l2_subdev *sd,
 			struct v4l2_dbg_chip_ident *chip)
 {
@@ -138,6 +150,10 @@
 	{"csi_pclk", -1},
 };
 
+static struct camera_vreg_t csid_vreg_info[] = {
+	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
+};
+
 static int msm_csid_init(struct v4l2_subdev *sd, uint32_t *csid_version)
 {
 	int rc = 0;
@@ -155,20 +171,47 @@
 		return rc;
 	}
 
+	rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
+	if (rc < 0) {
+		pr_err("%s: regulator on failed\n", __func__);
+		goto vreg_config_failed;
+	}
+
+	rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
+	if (rc < 0) {
+		pr_err("%s: regulator enable failed\n", __func__);
+		goto vreg_enable_failed;
+	}
+
 	rc = msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
 		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 1);
 	if (rc < 0) {
-		iounmap(csid_dev->base);
-		return rc;
+		pr_err("%s: regulator enable failed\n", __func__);
+		goto clk_enable_failed;
 	}
 
-#if DBG_CSID
-	enable_irq(csid_dev->irq->start);
-#endif
-
+	csid_dev->hw_version =
+		msm_io_r(csid_dev->base + CSID_HW_VERSION_ADDR);
 	*csid_version = csid_dev->hw_version;
 
+	init_completion(&csid_dev->reset_complete);
+
+	enable_irq(csid_dev->irq->start);
+
+	msm_csid_reset(csid_dev);
 	return 0;
+
+clk_enable_failed:
+	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+vreg_enable_failed:
+	msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+vreg_config_failed:
+	iounmap(csid_dev->base);
+	return rc;
 }
 
 static int msm_csid_release(struct v4l2_subdev *sd)
@@ -176,13 +219,17 @@
 	struct csid_device *csid_dev;
 	csid_dev = v4l2_get_subdevdata(sd);
 
-#if DBG_CSID
 	disable_irq(csid_dev->irq->start);
-#endif
 
 	msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
 		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
 
+	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+
+	msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+
 	iounmap(csid_dev->base);
 	return 0;
 }
@@ -190,19 +237,27 @@
 static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int cmd, void *arg)
 {
+	int rc = -ENOIOCTLCMD;
 	struct csid_cfg_params cfg_params;
+	struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
+	mutex_lock(&csid_dev->mutex);
 	switch (cmd) {
 	case VIDIOC_MSM_CSID_CFG:
 		cfg_params.subdev = sd;
 		cfg_params.parms = arg;
-		return msm_csid_config((struct csid_cfg_params *)&cfg_params);
+		rc = msm_csid_config((struct csid_cfg_params *)&cfg_params);
+		break;
 	case VIDIOC_MSM_CSID_INIT:
-		return msm_csid_init(sd, (uint32_t *)arg);
+		rc = msm_csid_init(sd, (uint32_t *)arg);
+		break;
 	case VIDIOC_MSM_CSID_RELEASE:
-		return msm_csid_release(sd);
+		rc = msm_csid_release(sd);
+		break;
 	default:
-		return -ENOIOCTLCMD;
+		pr_err("%s: command not found\n", __func__);
 	}
+	mutex_unlock(&csid_dev->mutex);
+	return rc;
 }
 
 static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = {
@@ -263,17 +318,6 @@
 	}
 	disable_irq(new_csid_dev->irq->start);
 
-	new_csid_dev->base = ioremap(new_csid_dev->mem->start,
-		resource_size(new_csid_dev->mem));
-	if (!new_csid_dev->base) {
-		rc = -ENOMEM;
-		goto csid_no_resource;
-	}
-
-	new_csid_dev->hw_version =
-		msm_io_r(new_csid_dev->base + CSID_HW_VERSION_ADDR);
-	iounmap(new_csid_dev->base);
-
 	new_csid_dev->pdev = pdev;
 	return 0;
 
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index f90abf2..2eae49c 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -23,8 +23,10 @@
 	struct resource *mem;
 	struct resource *irq;
 	struct resource *io;
+	struct regulator *csi_vdd;
 	void __iomem *base;
 	struct mutex mutex;
+	struct completion reset_complete;
 	uint32_t hw_version;
 
 	struct clk *csid_clk[5];
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index 315cca7..0c1e0a4 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -38,6 +38,8 @@
 #define MIPI_CSIPHY_LNCK_MISC1_ADDR              0x128
 #define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR        0x1E0
 #define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR           0x1E8
+#define MIPI_CSIPHY_T_WAKEUP_CFG1_ADDR           0x1EC
+#define MIPI_CSIPHY_GLBL_RESET_ADDR             0x0140
 #define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR           0x0144
 #define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR      0x0180
 #define MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR      0x0184
@@ -58,14 +60,17 @@
 int msm_csiphy_config(struct csiphy_cfg_params *cfg_params)
 {
 	int rc = 0;
-	int i = 0;
+	int j = 0;
 	uint32_t val = 0;
+	uint8_t lane_cnt = 0, lane_mask = 0;
 	struct csiphy_device *csiphy_dev;
 	struct msm_camera_csiphy_params *csiphy_params;
 	void __iomem *csiphybase;
 	csiphy_dev = v4l2_get_subdevdata(cfg_params->subdev);
 	csiphybase = csiphy_dev->base;
 	csiphy_params = cfg_params->parms;
+	lane_mask = csiphy_params->lane_mask;
+	lane_cnt = csiphy_params->lane_cnt;
 	if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
 		CDBG("%s: unsupported lane cnt %d\n",
 			__func__, csiphy_params->lane_cnt);
@@ -73,15 +78,28 @@
 	}
 
 	val = 0x3;
-	msm_io_w((((1 << csiphy_params->lane_cnt) - 1) << 2) | val,
-			 csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
+	msm_io_w((csiphy_params->lane_mask << 2) | val,
+			csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
 	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
 	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
 
-	for (i = 0; i < csiphy_params->lane_cnt; i++) {
-		msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
+	while (lane_mask & 0xf) {
+		if (!(lane_mask & 0x1)) {
+			j++;
+			lane_mask >>= 1;
+			continue;
+		}
+		msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*j);
 		msm_io_w(csiphy_params->settle_cnt,
-			csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*i);
+			csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*j);
+		msm_io_w(0x6F,
+			csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR +
+				0x4*(j+1));
+		msm_io_w(0x6F,
+			csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR +
+				0x4*(j+1));
+		j++;
+		lane_mask >>= 1;
 	}
 
 	msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNCK_CFG2_ADDR);
@@ -92,13 +110,6 @@
 		csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR);
 	msm_io_w(0x24,
 		csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
-
-	for (i = 1; i <= csiphy_params->lane_cnt; i++) {
-		msm_io_w(0x6F,
-			csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR + 0x4*i);
-		msm_io_w(0x6F,
-			csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
-	}
 	return rc;
 }
 
@@ -108,24 +119,36 @@
 	struct csiphy_device *csiphy_dev = data;
 	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
 	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
+	CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS0 = 0x%x\n",
+		 __func__, csiphy_dev->pdev->id, irq);
 	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR);
 	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS1 = 0x%x\n", __func__, irq);
+	CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS1 = 0x%x\n",
+		__func__, csiphy_dev->pdev->id, irq);
 	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR);
 	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS2 = 0x%x\n", __func__, irq);
+	CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS2 = 0x%x\n",
+		__func__, csiphy_dev->pdev->id, irq);
 	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR);
 	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS3 = 0x%x\n", __func__, irq);
+	CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS3 = 0x%x\n",
+		__func__, csiphy_dev->pdev->id, irq);
 	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR);
 	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS4 = 0x%x\n", __func__, irq);
+	CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS4 = 0x%x\n",
+		__func__, csiphy_dev->pdev->id, irq);
 	msm_io_w(0x1, csiphy_dev->base + 0x164);
 	msm_io_w(0x0, csiphy_dev->base + 0x164);
 	return IRQ_HANDLED;
 }
 
+static void msm_csiphy_reset(struct csiphy_device *csiphy_dev)
+{
+	msm_io_w(0x1, csiphy_dev->base + MIPI_CSIPHY_GLBL_RESET_ADDR);
+	usleep_range(5000, 8000);
+	msm_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_RESET_ADDR);
+}
+
 static int msm_csiphy_subdev_g_chip_ident(struct v4l2_subdev *sd,
 			struct v4l2_dbg_chip_ident *chip)
 {
@@ -168,6 +191,7 @@
 #if DBG_CSIPHY
 	enable_irq(csiphy_dev->irq->start);
 #endif
+	msm_csiphy_reset(csiphy_dev);
 
 	return 0;
 }
@@ -184,12 +208,12 @@
 	msm_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_LNCK_CFG2_ADDR);
 	msm_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
 
-	msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
-		csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 0);
-
 #if DBG_CSIPHY
 	disable_irq(csiphy_dev->irq->start);
 #endif
+	msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
+		csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 0);
+
 	iounmap(csiphy_dev->base);
 	return 0;
 }
@@ -197,20 +221,28 @@
 static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int cmd, void *arg)
 {
+	int rc = -ENOIOCTLCMD;
 	struct csiphy_cfg_params cfg_params;
+	struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd);
+	mutex_lock(&csiphy_dev->mutex);
 	switch (cmd) {
 	case VIDIOC_MSM_CSIPHY_CFG:
 		cfg_params.subdev = sd;
 		cfg_params.parms = arg;
-		return msm_csiphy_config(
+		rc = msm_csiphy_config(
 			(struct csiphy_cfg_params *)&cfg_params);
+		break;
 	case VIDIOC_MSM_CSIPHY_INIT:
-		return msm_csiphy_init(sd);
+		rc = msm_csiphy_init(sd);
+		break;
 	case VIDIOC_MSM_CSIPHY_RELEASE:
-		return msm_csiphy_release(sd);
+		rc = msm_csiphy_release(sd);
+		break;
 	default:
-		return -ENOIOCTLCMD;
+		pr_err("%s: command not found\n", __func__);
 	}
+	mutex_unlock(&csiphy_dev->mutex);
+	return rc;
 }
 
 static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = {
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index 86d62c9..f4dde2a 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -525,16 +525,16 @@
 	struct ispif_device *ispif =
 			(struct ispif_device *)v4l2_get_subdevdata(sd);
 
+	CDBG("%s, free_irq\n", __func__);
+	free_irq(ispif->irq->start, 0);
+	tasklet_kill(&ispif_tasklet);
+
 	if (ispif->csid_version == CSID_VERSION_V2)
 		msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
 			ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), 0);
 	else
 		msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
 			ispif->ispif_clk, 2, 0);
-
-	CDBG("%s, free_irq\n", __func__);
-	free_irq(ispif->irq->start, 0);
-	tasklet_kill(&ispif_tasklet);
 }
 
 void msm_ispif_vfe_get_cid(uint8_t intftype, char *cids, int *num)
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index 6985f3c..a86e5c4 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -212,6 +212,66 @@
 #endif /* CONFIG_LEDS_PMIC8058 */
 	return rc;
 }
+
+int msm_camera_flash_led(
+		struct msm_camera_sensor_flash_external *external,
+		unsigned led_state)
+{
+	int rc = 0;
+
+	CDBG("msm_camera_flash_led: %d\n", led_state);
+	switch (led_state) {
+	case MSM_CAMERA_LED_INIT:
+		rc = gpio_request(external->led_en, "sgm3141");
+		CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
+				external->led_en, rc);
+		if (!rc)
+			gpio_direction_output(external->led_en, 0);
+		else
+			return 0;
+
+		rc = gpio_request(external->led_flash_en, "sgm3141");
+		CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
+				external->led_flash_en, rc);
+		if (!rc)
+			gpio_direction_output(external->led_flash_en, 0);
+
+			break;
+
+	case MSM_CAMERA_LED_RELEASE:
+		CDBG("MSM_CAMERA_LED_RELEASE\n");
+		gpio_set_value_cansleep(external->led_en, 0);
+		gpio_free(external->led_en);
+		gpio_set_value_cansleep(external->led_flash_en, 0);
+		gpio_free(external->led_flash_en);
+		break;
+
+	case MSM_CAMERA_LED_OFF:
+		CDBG("MSM_CAMERA_LED_OFF\n");
+		gpio_set_value_cansleep(external->led_en, 0);
+		gpio_set_value_cansleep(external->led_flash_en, 0);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		CDBG("MSM_CAMERA_LED_LOW\n");
+		gpio_set_value_cansleep(external->led_en, 1);
+		gpio_set_value_cansleep(external->led_flash_en, 1);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		CDBG("MSM_CAMERA_LED_HIGH\n");
+		gpio_set_value_cansleep(external->led_en, 1);
+		gpio_set_value_cansleep(external->led_flash_en, 1);
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	return rc;
+}
+
 int msm_camera_flash_external(
 	struct msm_camera_sensor_flash_external *external,
 	unsigned led_state)
@@ -439,6 +499,12 @@
 			led_state);
 		break;
 
+	case MSM_CAMERA_FLASH_SRC_LED1:
+		rc = msm_camera_flash_led(
+				&fdata->flash_src->_fsrc.ext_driver_src,
+				led_state);
+		break;
+
 	default:
 		rc = -ENODEV;
 		break;
diff --git a/drivers/media/video/msm/gemini/msm_gemini_core.c b/drivers/media/video/msm/gemini/msm_gemini_core.c
index 480500b..45d3937 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_core.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_core.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
@@ -71,7 +71,6 @@
 	for (i = 0; i < 2; i++) {
 		if (we_pingpong_buf.buf_status[i] && release_buf)
 			msm_gemini_platform_p2v(we_pingpong_buf.buf[i].file,
-					&we_pingpong_buf.buf[i].msm_buffer,
 					&we_pingpong_buf.buf[i].handle);
 		we_pingpong_buf.buf_status[i] = 0;
 	}
diff --git a/drivers/media/video/msm/gemini/msm_gemini_hw.h b/drivers/media/video/msm/gemini/msm_gemini_hw.h
index 3c2fc6a..e1702a5 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_hw.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_hw.h
@@ -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
@@ -27,8 +27,6 @@
 	uint32_t cbcr_buffer_addr;
 	uint32_t cbcr_len;
 	uint32_t num_of_mcu_rows;
-	struct msm_mapped_buffer *msm_buffer;
-	int *subsystem_id;
 	struct ion_handle *handle;
 };
 
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index e81215e..ee0ff2f 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.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
@@ -28,14 +28,10 @@
 struct ion_client *gemini_client;
 
 void msm_gemini_platform_p2v(struct file  *file,
-				struct msm_mapped_buffer **msm_buffer,
 				struct ion_handle **ionhandle)
 {
-	if (msm_subsystem_unmap_buffer(
-		(struct msm_mapped_buffer *)*msm_buffer) < 0)
-		pr_err("%s: umapped stat memory\n",  __func__);
-	*msm_buffer = NULL;
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL);
 	ion_free(gemini_client, *ionhandle);
 	*ionhandle = NULL;
 #elif CONFIG_ANDROID_PMEM
@@ -44,18 +40,18 @@
 }
 
 uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
-				struct msm_mapped_buffer **msm_buffer,
-				int *subsys_id, struct ion_handle **ionhandle)
+				struct ion_handle **ionhandle)
 {
 	unsigned long paddr;
 	unsigned long size;
 	int rc;
-	int flags;
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	*ionhandle = ion_import_fd(gemini_client, fd);
 	if (IS_ERR_OR_NULL(*ionhandle))
 		return 0;
-	rc = ion_phys(gemini_client, *ionhandle, &paddr, (size_t *)&size);
+
+	rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
+			SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
 #elif CONFIG_ANDROID_PMEM
 	unsigned long kvstart;
 	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
@@ -67,31 +63,21 @@
 	if (rc < 0) {
 		GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
 			rc);
-		return 0;
+		goto error1;
 	}
 
 	/* validate user input */
 	if (len > size) {
 		GMN_PR_ERR("%s: invalid offset + len\n", __func__);
-		return 0;
+		goto error1;
 	}
 
-	flags = MSM_SUBSYSTEM_MAP_IOVA;
-	*subsys_id = MSM_SUBSYSTEM_CAMERA;
-	*msm_buffer = msm_subsystem_map_buffer(paddr, size,
-					flags, subsys_id, 1);
-	if (IS_ERR((void *)*msm_buffer)) {
-		pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		ion_free(gemini_client, *ionhandle);
-		*ionhandle = NULL;
-#elif CONFIG_ANDROID_PMEM
-		put_pmem_file(*file_p);
-#endif
-		return 0;
-	}
-	paddr = ((struct msm_mapped_buffer *)*msm_buffer)->iova[0];
 	return paddr;
+error1:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_free(gemini_client, *ionhandle);
+#endif
+	return 0;
 }
 
 int msm_gemini_platform_init(struct platform_device *pdev,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.h b/drivers/media/video/msm/gemini/msm_gemini_platform.h
index c54d7df..4542129 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.h
@@ -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
@@ -17,11 +17,9 @@
 #include <linux/platform_device.h>
 #include <linux/ion.h>
 void msm_gemini_platform_p2v(struct file  *file,
-				struct msm_mapped_buffer **msm_buffer,
 				struct ion_handle **ionhandle);
 uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
-				struct msm_mapped_buffer **msm_buffer,
-				int *subsys_id, struct ion_handle **ionhandle);
+				struct ion_handle **ionhandle);
 
 int msm_gemini_platform_clk_enable(void);
 int msm_gemini_platform_clk_disable(void);
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index 0f0bd67..fe7c99f 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.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
@@ -151,9 +151,8 @@
 		buf_p = msm_gemini_q_out(q_p);
 		if (buf_p) {
 			msm_gemini_platform_p2v(buf_p->file,
-				&buf_p->msm_buffer, &buf_p->handle);
+				&buf_p->handle);
 			GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
-			kfree(buf_p->subsystem_id);
 			kfree(buf_p);
 		}
 	} while (buf_p);
@@ -317,9 +316,7 @@
 	}
 
 	buf_cmd = buf_p->vbuf;
-	msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
-				&buf_p->handle);
-	kfree(buf_p->subsystem_id);
+	msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
 	kfree(buf_p);
 
 	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
@@ -361,18 +358,10 @@
 	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, (int) buf_cmd.vaddr,
 		buf_cmd.y_len);
 
-	buf_p->subsystem_id = kmalloc(sizeof(int), GFP_ATOMIC);
-	if (!buf_p->subsystem_id) {
-		GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
-		kfree(buf_p);
-		return -ENOMEM;
-	}
 	buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
-		buf_cmd.y_len, &buf_p->file, &buf_p->msm_buffer,
-		buf_p->subsystem_id, &buf_p->handle);
+		buf_cmd.y_len, &buf_p->file, &buf_p->handle);
 	if (!buf_p->y_buffer_addr) {
 		GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
-		kfree(buf_p->subsystem_id);
 		kfree(buf_p);
 		return -1;
 	}
@@ -435,9 +424,10 @@
 	}
 
 	buf_cmd = buf_p->vbuf;
-	msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
-				&buf_p->handle);
-	kfree(buf_p->subsystem_id);
+	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ENCODE ||
+		pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ROTATION) {
+		msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
+	}
 	kfree(buf_p);
 
 	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
@@ -478,26 +468,25 @@
 	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
 		(int) buf_cmd.vaddr, buf_cmd.y_len);
 
-	buf_p->subsystem_id = kmalloc(sizeof(int), GFP_ATOMIC);
-	if (!buf_p->subsystem_id) {
-		GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
-		kfree(buf_p);
-		return -ENOMEM;
-	}
+	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+		buf_p->y_buffer_addr    = buf_cmd.y_off;
+	} else {
 	buf_p->y_buffer_addr    = msm_gemini_platform_v2p(buf_cmd.fd,
 		buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
-			&buf_p->msm_buffer, buf_p->subsystem_id, &buf_p->handle)
-			+ buf_cmd.offset;
+		&buf_p->handle)	+ buf_cmd.offset;
+	}
 	buf_p->y_len          = buf_cmd.y_len;
 
 	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
 	buf_p->cbcr_len       = buf_cmd.cbcr_len;
 
 	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+	GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
+		buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
+		buf_p->cbcr_len);
 
 	if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
 		GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
-		kfree(buf_p->subsystem_id);
 		kfree(buf_p);
 		return -1;
 	}
diff --git a/drivers/media/video/msm/io/msm_io_util.c b/drivers/media/video/msm/io/msm_io_util.c
index 207f8be..a04d6fd 100644
--- a/drivers/media/video/msm/io/msm_io_util.c
+++ b/drivers/media/video/msm/io/msm_io_util.c
@@ -95,32 +95,33 @@
 				curr_vreg->reg_name);
 			if (IS_ERR(reg_ptr[i])) {
 				pr_err("%s: %s get failed\n",
-				 __func__,
-				 curr_vreg->reg_name);
+					 __func__,
+					 curr_vreg->reg_name);
 				reg_ptr[i] = NULL;
 				goto vreg_get_fail;
 			}
 			if (curr_vreg->type == REG_LDO) {
 				rc = regulator_set_voltage(
-				reg_ptr[i],
-				curr_vreg->min_voltage,
-				curr_vreg->max_voltage);
+					reg_ptr[i],
+					curr_vreg->min_voltage,
+					curr_vreg->max_voltage);
 				if (rc < 0) {
-					pr_err(
-					"%s: %s set voltage failed\n",
-					__func__,
-					curr_vreg->reg_name);
+					pr_err("%s: %s set voltage failed\n",
+						__func__,
+						curr_vreg->reg_name);
 					goto vreg_set_voltage_fail;
 				}
-				rc = regulator_set_optimum_mode(
-					reg_ptr[i],
-					curr_vreg->op_mode);
-				if (rc < 0) {
-					pr_err(
-					"%s: %s set optimum mode failed\n",
-					__func__,
-					curr_vreg->reg_name);
-					goto vreg_set_opt_mode_fail;
+				if (curr_vreg->op_mode) {
+					rc = regulator_set_optimum_mode(
+						reg_ptr[i],
+						curr_vreg->op_mode);
+					if (rc < 0) {
+						pr_err("%s: %s set optimum"
+							"mode failed\n",
+							__func__,
+							curr_vreg->reg_name);
+						goto vreg_set_opt_mode_fail;
+					}
 				}
 			}
 		}
@@ -129,11 +130,12 @@
 			curr_vreg = &cam_vreg[i];
 			if (reg_ptr[i]) {
 				if (curr_vreg->type == REG_LDO) {
-					regulator_set_optimum_mode(
-						reg_ptr[i], 0);
+					if (curr_vreg->op_mode)
+						regulator_set_optimum_mode(
+							reg_ptr[i], 0);
 					regulator_set_voltage(
-						reg_ptr[i],
-						0, curr_vreg->max_voltage);
+						reg_ptr[i], 0, curr_vreg->
+						max_voltage);
 				}
 				regulator_put(reg_ptr[i]);
 				reg_ptr[i] = NULL;
@@ -171,13 +173,13 @@
 		for (i = 0; i < num_vreg; i++) {
 			if (IS_ERR(reg_ptr[i])) {
 				pr_err("%s: %s null regulator\n",
-				__func__, cam_vreg[i].reg_name);
+					__func__, cam_vreg[i].reg_name);
 				goto disable_vreg;
 			}
 			rc = regulator_enable(reg_ptr[i]);
 			if (rc < 0) {
 				pr_err("%s: %s enable failed\n",
-				__func__, cam_vreg[i].reg_name);
+					__func__, cam_vreg[i].reg_name);
 				goto disable_vreg;
 			}
 		}
@@ -194,6 +196,30 @@
 	return rc;
 }
 
+static int config_gpio_table(struct msm_camera_gpio_conf *gpio)
+{
+	int rc = 0, i = 0;
+	uint32_t *table_on;
+	uint32_t *table_off;
+	uint32_t len;
+
+	table_on = gpio->camera_on_table;
+	table_off = gpio->camera_off_table;
+	len = gpio->camera_on_table_size;
+
+	for (i = 0; i < len; i++) {
+		rc = gpio_tlmm_config(table_on[i], GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s not able to get gpio\n", __func__);
+			for (i--; i >= 0; i--)
+				gpio_tlmm_config(table_off[i],
+					GPIO_CFG_ENABLE);
+			break;
+		}
+	}
+	return rc;
+}
+
 int msm_camera_request_gpio_table(struct msm_camera_sensor_info *sinfo,
 	int gpio_en)
 {
@@ -201,38 +227,49 @@
 	struct msm_camera_gpio_conf *gpio_conf =
 		sinfo->sensor_platform_info->gpio_conf;
 
-	if (gpio_conf->cam_gpio_req_tbl == NULL ||
-		gpio_conf->cam_gpio_common_tbl == NULL) {
-		pr_err("%s: NULL camera gpio table\n", __func__);
-		return -EFAULT;
+	if (!gpio_conf->gpio_no_mux) {
+		if (gpio_conf->cam_gpio_req_tbl == NULL ||
+			gpio_conf->cam_gpio_common_tbl == NULL) {
+			pr_err("%s: NULL camera gpio table\n", __func__);
+			return -EFAULT;
+		}
 	}
+	if (gpio_conf->gpio_no_mux)
+		config_gpio_table(gpio_conf);
 
 	if (gpio_en) {
-		if (gpio_conf->cam_gpiomux_conf_tbl != NULL) {
-			msm_gpiomux_install(
-				(struct msm_gpiomux_config *)gpio_conf->
-				cam_gpiomux_conf_tbl,
-				gpio_conf->cam_gpiomux_conf_tbl_size);
-		}
-		rc = gpio_request_array(gpio_conf->cam_gpio_common_tbl,
+		if (!gpio_conf->gpio_no_mux) {
+			if (gpio_conf->cam_gpiomux_conf_tbl != NULL) {
+				msm_gpiomux_install(
+					(struct msm_gpiomux_config *)
+					gpio_conf->cam_gpiomux_conf_tbl,
+					gpio_conf->cam_gpiomux_conf_tbl_size);
+			}
+			rc = gpio_request_array(gpio_conf->cam_gpio_common_tbl,
 				gpio_conf->cam_gpio_common_tbl_size);
-		if (rc < 0) {
-			pr_err("%s common gpio request failed\n", __func__);
-			return rc;
+			if (rc < 0) {
+				pr_err("%s common gpio request failed\n"
+						, __func__);
+				return rc;
+			}
 		}
-		rc = gpio_request_array(gpio_conf->cam_gpio_req_tbl,
+		if (gpio_conf->cam_gpio_req_tbl_size) {
+			rc = gpio_request_array(gpio_conf->cam_gpio_req_tbl,
 				gpio_conf->cam_gpio_req_tbl_size);
-		if (rc < 0) {
-			pr_err("%s camera gpio request failed\n", __func__);
-			gpio_free_array(gpio_conf->cam_gpio_common_tbl,
-				gpio_conf->cam_gpio_common_tbl_size);
-			return rc;
+			if (rc < 0) {
+				pr_err("%s camera gpio"
+					"request failed\n", __func__);
+				gpio_free_array(gpio_conf->cam_gpio_common_tbl,
+					gpio_conf->cam_gpio_common_tbl_size);
+				return rc;
+			}
 		}
 	} else {
 		gpio_free_array(gpio_conf->cam_gpio_req_tbl,
 				gpio_conf->cam_gpio_req_tbl_size);
-		gpio_free_array(gpio_conf->cam_gpio_common_tbl,
-			gpio_conf->cam_gpio_common_tbl_size);
+		if (!gpio_conf->gpio_no_mux)
+			gpio_free_array(gpio_conf->cam_gpio_common_tbl,
+				gpio_conf->cam_gpio_common_tbl_size);
 	}
 	return rc;
 }
@@ -252,7 +289,7 @@
 			usleep_range(gpio_conf->cam_gpio_set_tbl[i].delay,
 				gpio_conf->cam_gpio_set_tbl[i].delay + 1000);
 		}
-	} else {
+	} else if (!gpio_conf->gpio_no_mux) {
 		for (i = gpio_conf->cam_gpio_set_tbl_size - 1; i >= 0; i--) {
 			if (gpio_conf->cam_gpio_set_tbl[i].flags)
 				gpio_set_value_cansleep(
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 84d441d..8d59590 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__);
@@ -1359,6 +1366,14 @@
 		return rc;
 	}
 
+	/* The number of camera instance should be controlled by the
+		resource manager. Currently supporting one active instance
+		until multiple instances are supported */
+	if (atomic_read(&ps->number_pcam_active) > 0) {
+		pr_err("%s Cannot have more than one active camera %d\n",
+			__func__, atomic_read(&ps->number_pcam_active));
+		return -EINVAL;
+	}
 	/* book keeping this camera session*/
 	ps->pcam_active = pcam;
 	atomic_inc(&ps->number_pcam_active);
@@ -1404,6 +1419,9 @@
 {
 	int i;
 	int rc = -EINVAL;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	int ion_client_created = 0;
+#endif
 	/*struct msm_isp_ops *p_isp = 0;*/
 	/* get the video device */
 	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
@@ -1435,7 +1453,9 @@
 	pcam_inst->pcam = pcam;
 	pcam->dev_inst[i] = pcam_inst;
 
-	D("%s for %s\n", __func__, pcam->pdev->name);
+	D("%s index %d nodeid %d count %d\n", __func__,
+			pcam_inst->my_index,
+			pcam->vnode_id, pcam->use_count);
 	pcam->use_count++;
 	if (pcam->use_count == 1) {
 
@@ -1443,18 +1463,19 @@
 		if (rc < 0) {
 			pr_err("%s: cam_server_open_session failed %d\n",
 			__func__, rc);
-			mutex_unlock(&pcam->vid_lock);
-			return rc;
+			goto err;
 		}
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		pcam->mctl.client = msm_ion_client_create(-1, "camera");
+		kref_init(&pcam->mctl.refcount);
+		ion_client_created = 1;
 #endif
 		/* Should be set to sensor ops if any but right now its OK!! */
 		if (!pcam->mctl.mctl_open) {
 			D("%s: media contoller is not inited\n",
 				 __func__);
-			mutex_unlock(&pcam->vid_lock);
-			return -ENODEV;
+			rc = -ENODEV;
+			goto err;
 		}
 
 		/* Now we really have to activate the camera */
@@ -1462,9 +1483,8 @@
 		rc = pcam->mctl.mctl_open(&(pcam->mctl), MSM_APPS_ID_V4L2);
 
 		if (rc < 0) {
-			mutex_unlock(&pcam->vid_lock);
 			pr_err("%s: HW open failed rc = 0x%x\n",  __func__, rc);
-			return rc;
+			goto err;
 		}
 		pcam->mctl.sync.pcam_sync = pcam;
 
@@ -1472,24 +1492,21 @@
 		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
 					pcam->mctl.isp_sdev->sd);
 		if (rc < 0) {
-			mutex_unlock(&pcam->vid_lock);
 			pr_err("%s: v4l2_device_register_subdev failed rc = %d\n",
 				__func__, rc);
-			return rc;
+			goto err;
 		}
 		if (pcam->mctl.isp_sdev->sd_vpe) {
 			rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
 						pcam->mctl.isp_sdev->sd_vpe);
 			if (rc < 0) {
-				mutex_unlock(&pcam->vid_lock);
-				return rc;
+				goto err;
 			}
 		}
 		rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 							pcam->pvdev);
 		if (rc < 0) {
-			mutex_unlock(&pcam->vid_lock);
-			return rc;
+			goto err;
 		}
 	}
 	pcam_inst->vbqueue_initialized = 0;
@@ -1502,6 +1519,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);
@@ -1513,6 +1531,21 @@
 	D("%s: end", __func__);
 	/* rc = msm_cam_server_open_session(g_server_dev, pcam);*/
 	return rc;
+
+err:
+	if (pcam->use_count == 1) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		if (ion_client_created) {
+			pr_err("%s: destroy ion client", __func__);
+			kref_put(&pcam->mctl.refcount, msm_release_ion_client);
+		}
+#endif
+		pcam->dev_inst[i] = NULL;
+		pcam->use_count = 0;
+	}
+	mutex_unlock(&pcam->vid_lock);
+	kfree(pcam_inst);
+	return rc;
 }
 
 static int msm_addr_remap(struct msm_cam_v4l2_dev_inst *pcam_inst,
@@ -1573,6 +1606,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,20 +1622,32 @@
 	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);
+
+	if (pcam_inst->streamon) {
+		/*something went wrong since instance
+		is closing without streamoff*/
+		if (pcam->mctl.mctl_release) {
+			rc = pcam->mctl.mctl_release(&(pcam->mctl));
+			if (rc < 0)
+				pr_err("mctl_release fails %d\n", rc);
+		}
+		pcam->mctl.mctl_release = NULL;/*so that it isn't closed again*/
+	}
+
 	pcam_inst->streamon = 0;
 	pcam->use_count--;
 	pcam->dev_inst_map[pcam_inst->image_mode] = NULL;
 	if (pcam_inst->vbqueue_initialized)
 		vb2_queue_release(&pcam_inst->vid_bufq);
 	D("%s Closing down instance %p ", __func__, pcam_inst);
+	D("%s index %d nodeid %d count %d\n", __func__, pcam_inst->my_index,
+		pcam->vnode_id, pcam->use_count);
 	pcam->dev_inst[pcam_inst->my_index] = NULL;
 	if (pcam_inst->my_index == 0) {
 		v4l2_fh_del(&pcam_inst->eventHandle);
@@ -1610,17 +1663,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 +1936,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 +1967,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 +2228,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 +2259,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 +2268,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 +2386,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);
@@ -2337,6 +2430,13 @@
 		return rc;
 	}
 
+	strlcpy(pcam->mctl.media_dev.model, QCAMERA_NAME,
+			sizeof(pcam->mctl.media_dev.model));
+	pcam->mctl.media_dev.dev = &client->dev;
+	rc = media_device_register(&pcam->mctl.media_dev);
+	pvdev->v4l2_dev = &pcam->v4l2_dev;
+	pcam->v4l2_dev.mdev = &pcam->mctl.media_dev;
+
 	/* init video device's driver interface */
 	D("sensor name = %s, sizeof(pvdev->name)=%d\n",
 		pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
@@ -2351,6 +2451,10 @@
 	pvdev->minor	 = -1;
 	pvdev->vfl_type  = 1;
 
+	media_entity_init(&pvdev->entity, 0, NULL, 0);
+	pvdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+	pvdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
+
 	/* register v4l2 video device to kernel as /dev/videoXX */
 	D("video_register_device\n");
 	rc = video_register_device(pvdev,
@@ -2360,6 +2464,7 @@
 		pr_err("%s: video_register_device failed\n", __func__);
 		goto reg_fail;
 	}
+	pvdev->entity.name = video_device_node_name(pvdev);
 	D("%s: video device registered as /dev/video%d\n",
 		__func__, pvdev->num);
 
@@ -2545,12 +2650,21 @@
 		g_server_dev.mctl_node_info.mctl_node_name
 		[g_server_dev.mctl_node_info.num_mctl_nodes]);
 
+	/*Temporary solution to store info in media device structure
+	  until we can expand media device structure to support more
+	  device info*/
+	snprintf(pcam->mctl.media_dev.serial,
+			sizeof(pcam->mctl.media_dev.serial),
+			"%s-%d-%d", QCAMERA_NAME,
+			sdata->sensor_platform_info->mount_angle,
+			sdata->camera_type);
+
 	g_server_dev.camera_info.num_cameras++;
 	g_server_dev.mctl_node_info.num_mctl_nodes++;
 
 	D("%s done, rc = %d\n", __func__, rc);
 	D("%s number of sensors connected is %d\n", __func__,
-			g_server_dev.camera_info.num_cameras);
+		g_server_dev.camera_info.num_cameras);
 
 	/* register the subdevice, must be done for callbacks */
 	rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sensor_sd);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 55c0da1..dd65c01 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -218,6 +218,8 @@
 	/* most-frequently accessed manager object*/
 	struct msm_sync sync;
 
+	/*Media device node*/
+	struct media_device media_dev;
 
 	/* the following reflect the HW topology information*/
 	/*mandatory*/
@@ -239,6 +241,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 +412,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 +529,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_io_7x27a_v4l2.c b/drivers/media/video/msm/msm_io_7x27a_v4l2.c
index bee9f49..63547c8 100644
--- a/drivers/media/video/msm/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_io_7x27a_v4l2.c
@@ -97,33 +97,6 @@
 	clk_set_rate(clk, rate);
 }
 
-int msm_sensor_probe_on(struct device *dev)
-{
-	int rc = 0;
-	struct msm_camera_sensor_info *sinfo = dev->platform_data;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-	camio_clk = camdev->ioclk;
-
-	rc = camdev->camera_gpio_on();
-	if (rc < 0)
-		return rc;
-
-	rc = msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
-	if (rc < 0)
-		camdev->camera_gpio_off();
-
-	return rc;
-}
-
-int msm_sensor_probe_off(struct device *dev)
-{
-	struct msm_camera_sensor_info *sinfo = dev->platform_data;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-
-	camdev->camera_gpio_off();
-	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
-}
-
 void msm_camio_vfe_blk_reset(void)
 {
 	uint32_t val;
@@ -152,28 +125,6 @@
 	usleep_range(10000, 11000);
 }
 
-int msm_camio_probe_on(struct platform_device *pdev)
-{
-	int rc = 0;
-	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-	camio_clk = camdev->ioclk;
-
-	rc = camdev->camera_gpio_on();
-	if (rc < 0)
-		return rc;
-	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
-}
-
-int msm_camio_probe_off(struct platform_device *pdev)
-{
-	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-
-	camdev->camera_gpio_off();
-	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
-}
-
 void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
 {
 	switch (perf_setting) {
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index ea969cf..9bfc239 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -117,7 +117,7 @@
 	case CAMIO_JPEG_CLK:
 		camio_jpeg_clk =
 		clk = clk_get(NULL, "ijpeg_clk");
-		clk_set_rate(clk, 153600000);
+		clk_set_rate(clk, 228571000);
 		break;
 
 	case CAMIO_JPEG_PCLK:
@@ -191,6 +191,11 @@
 	if (rc < 0)
 		return rc;
 	rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_disable(CAMIO_IMEM_CLK);
+	if (rc < 0)
+		return rc;
 
 	if (fs_ijpeg) {
 		rc = regulator_disable(fs_ijpeg);
@@ -225,6 +230,10 @@
 	if (rc < 0)
 		return rc;
 
+	rc = msm_camio_clk_enable(CAMIO_IMEM_CLK);
+	if (rc < 0)
+		return rc;
+
 	CDBG("%s: exit %d\n", __func__, rc);
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index fdd1f0e..3e2ddee 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -90,6 +90,7 @@
 		case VFE_OUTPUTS_MAIN_AND_VIDEO:
 		case VFE_OUTPUTS_MAIN_AND_THUMB:
 		case VFE_OUTPUTS_RAW:
+		case VFE_OUTPUTS_JPEG_AND_THUMB:
 			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
 			break;
 		case VFE_OUTPUTS_THUMB_AND_MAIN:
@@ -123,6 +124,13 @@
 		case VFE_OUTPUTS_THUMB_AND_MAIN:
 			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
 			break;
+		case VFE_OUTPUTS_JPEG_AND_THUMB:
+			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
+			break;
+		case VFE_OUTPUTS_PREVIEW:
+		case VFE_OUTPUTS_VIDEO:
+			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+			break;
 		default:
 			image_mode = -1;
 			break;
@@ -200,16 +208,27 @@
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		break;
 	case VFE_MSG_V32_JPEG_CAPTURE:
+		D("%s:VFE_MSG_V32_JPEG_CAPTURE vdata->type %d\n", __func__,
+			vdata->type);
 		free_buf.num_planes = 1;
-		free_buf.ch_paddr[0] = IMEM_Y_OFFSET;
-		free_buf.ch_paddr[1] = IMEM_CBCR_OFFSET;
+		free_buf.ch_paddr[0] = IMEM_Y_PING_OFFSET;
+		free_buf.ch_paddr[1] = IMEM_CBCR_PING_OFFSET;
 		cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
 		cfgcmd.value = &vfe_id;
 		vfe_params.vfe_cfg = &cfgcmd;
 		vfe_params.data = (void *)&free_buf;
+		D("%s:VFE_MSG_V32_JPEG_CAPTURE y_ping=%x cbcr_ping=%x\n",
+			__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		/* Write the same buffer into PONG */
+		free_buf.ch_paddr[0] = IMEM_Y_PONG_OFFSET;
+		free_buf.ch_paddr[1] = IMEM_CBCR_PONG_OFFSET;
 		cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
+		cfgcmd.value = &vfe_id;
+		vfe_params.vfe_cfg = &cfgcmd;
+		vfe_params.data = (void *)&free_buf;
+		D("%s:VFE_MSG_V32_JPEG_CAPTURE y_pong=%x cbcr_pong=%x\n",
+			__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		break;
 	case VFE_MSG_OUTPUT_IRQ:
@@ -387,6 +406,8 @@
 			stats.cs.buff = stats.buffer;
 			stats.cs.fd = stats.fd;
 			break;
+		case MSG_ID_STATS_AWB_AEC:
+			break;
 		default:
 			pr_err("%s: Invalid msg type", __func__);
 			break;
@@ -707,6 +728,7 @@
 	case CMD_AXI_CFG_ZSL_ALL_CHNLS:
 	case CMD_RAW_PICT_AXI_CFG:
 	case CMD_AXI_CFG_PRIM:
+	case CMD_AXI_CFG_SEC:
 	case CMD_AXI_CFG_PRIM_ALL_CHNLS:
 	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC:
 	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS:
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 54458d1..001e02a 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -177,7 +177,7 @@
 	int rc = 0;
 	struct msm_camsensor_info info;
 	struct msm_camera_sensor_info *sdata;
-
+	struct msm_cam_v4l2_device *pcam = sync->pcam_sync;
 	if (copy_from_user(&info,
 			arg,
 			sizeof(struct msm_camsensor_info))) {
@@ -191,7 +191,12 @@
 	memcpy(&info.name[0], sdata->sensor_name, MAX_SENSOR_NAME);
 	info.flash_enabled = sdata->flash_data->flash_type !=
 					MSM_CAMERA_FLASH_NONE;
-
+	info.pxlcode = pcam->usr_fmts[0].pxlcode;
+	info.flashtype = sdata->flash_type; /* two flash_types here? */
+	info.camera_type = sdata->camera_type;
+	/* sensor_type needed to add YUV/SOC in probing */
+	info.sensor_type = sdata->sensor_type;
+	info.mount_angle = sdata->sensor_platform_info->mount_angle;
 	/* copy back to user space */
 	if (copy_to_user((void *)arg,
 				&info,
@@ -199,7 +204,6 @@
 		ERR_COPY_TO_USER();
 		rc = -EFAULT;
 	}
-
 	return rc;
 }
 
@@ -890,7 +894,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 +965,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/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 54b4efb..4f7e5d2 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -26,7 +26,6 @@
 #include <media/v4l2-device.h>
 
 #include <linux/android_pmem.h>
-#include <mach/msm_subsystem_map.h>
 
 #include "msm.h"
 
@@ -120,7 +119,6 @@
 	struct msm_pmem_info *info, struct ion_client *client)
 {
 	unsigned long paddr;
-	unsigned int flags;
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	unsigned long kvstart;
 	struct file *file;
@@ -137,7 +135,9 @@
 	region->handle = ion_import_fd(client, info->fd);
 	if (IS_ERR_OR_NULL(region->handle))
 		goto out1;
-	ion_phys(client, region->handle, &paddr, (size_t *)&len);
+	if (ion_map_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL,
+				  SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0)
+		goto out2;
 #elif CONFIG_ANDROID_PMEM
 	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
 	if (rc < 0) {
@@ -155,13 +155,13 @@
 		info->len = len;
 	rc = check_pmem_info(info, len);
 	if (rc < 0)
-		goto out2;
+		goto out3;
 	paddr += info->offset;
 	len = info->len;
 
 	if (check_overlap(ptype, paddr, len) < 0) {
 		rc = -EINVAL;
-		goto out2;
+		goto out3;
 	}
 
 	CDBG("%s: type %d, active flag %d, paddr 0x%lx, vaddr 0x%lx\n",
@@ -169,16 +169,6 @@
 		(unsigned long)info->vaddr);
 
 	INIT_HLIST_NODE(&region->list);
-	flags = MSM_SUBSYSTEM_MAP_IOVA;
-	region->subsys_id = MSM_SUBSYSTEM_CAMERA;
-	region->msm_buffer = msm_subsystem_map_buffer(paddr, len,
-					flags, &(region->subsys_id), 1);
-	if (IS_ERR((void *)region->msm_buffer)) {
-		pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
-		rc = PTR_ERR((void *)region->msm_buffer);
-		goto out2;
-	}
-	paddr = region->msm_buffer->iova[0];
 	region->paddr = paddr;
 	region->len = len;
 	memcpy(&region->info, info, sizeof(region->info));
@@ -188,8 +178,12 @@
 	hlist_add_head(&(region->list), ptype);
 
 	return 0;
-out2:
+out3:
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL);
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+out2:
 	ion_free(client, region->handle);
 #elif CONFIG_ANDROID_PMEM
 	put_pmem_file(region->file);
@@ -248,12 +242,9 @@
 				pinfo->vaddr == region->info.vaddr &&
 				pinfo->fd == region->info.fd) {
 				hlist_del(node);
-				if (msm_subsystem_unmap_buffer
-					(region->msm_buffer) < 0)
-					pr_err(
-					"%s: unmapped stat memory\n",
-				__func__);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+				ion_unmap_iommu(client, region->handle,
+					CAMERA_DOMAIN, GEN_POOL);
 				ion_free(client, region->handle);
 #else
 				put_pmem_file(region->file);
diff --git a/drivers/media/video/msm/msm_v4l2_video.c b/drivers/media/video/msm/msm_v4l2_video.c
new file mode 100644
index 0000000..c4e6c62
--- /dev/null
+++ b/drivers/media/video/msm/msm_v4l2_video.c
@@ -0,0 +1,947 @@
+/* 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/init.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/msm_mdp.h>
+#include <linux/sched.h>
+#include <linux/capability.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-dev.h>
+#include <media/msm_v4l2_overlay.h>
+
+#include <mach/board.h>
+#include <mach/msm_fb.h>
+
+#include "msm_v4l2_video.h"
+
+#define MSM_VIDEO -1
+
+static struct msm_v4l2_overlay_device	*saved_vout0;
+
+static struct mutex msmfb_lock;
+static char *v4l2_ram_phys;
+static unsigned int v4l2_ram_size;
+
+static int msm_v4l2_overlay_mapformat(uint32_t pixelformat);
+
+static int msm_v4l2_overlay_startstreaming(struct msm_v4l2_overlay_device *vout)
+{
+	vout->req.src.width = vout->pix.width;
+	vout->req.src.height = vout->pix.height;
+
+	vout->req.src_rect.x = vout->crop_rect.left;
+	vout->req.src_rect.y = vout->crop_rect.top;
+	vout->req.src_rect.w = vout->crop_rect.width;
+	vout->req.src_rect.h = vout->crop_rect.height;
+
+	vout->req.src.format =
+		msm_v4l2_overlay_mapformat(vout->pix.pixelformat);
+
+	vout->req.dst_rect.x = vout->win.w.left;
+	vout->req.dst_rect.y = vout->win.w.top;
+	vout->req.dst_rect.w = vout->win.w.width;
+	vout->req.dst_rect.h = vout->win.w.height;
+
+	vout->req.alpha = MDP_ALPHA_NOP;
+	vout->req.transp_mask = MDP_TRANSP_NOP;
+
+	pr_debug("msm_v4l2_overlay:startstreaming:enabling fb\n");
+	mutex_lock(&msmfb_lock);
+	msm_fb_v4l2_enable(&vout->req, true, &vout->par);
+	mutex_unlock(&msmfb_lock);
+
+	vout->streaming = 1;
+
+	return 0;
+}
+
+static int msm_v4l2_overlay_stopstreaming(struct msm_v4l2_overlay_device *vout)
+{
+	if (!vout->streaming)
+		return 0;
+
+	pr_debug("msm_v4l2_overlay:startstreaming:disabling fb\n");
+	mutex_lock(&msmfb_lock);
+	msm_fb_v4l2_enable(&vout->req, false, &vout->par);
+	mutex_unlock(&msmfb_lock);
+
+	vout->streaming = 0;
+
+	return 0;
+}
+
+static int msm_v4l2_overlay_mapformat(uint32_t pixelformat)
+{
+	int mdp_format;
+
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_RGB565:
+		mdp_format = MDP_RGB_565;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		mdp_format = MDP_ARGB_8888;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		mdp_format = MDP_RGB_888;
+		break;
+	case V4L2_PIX_FMT_NV12:
+		mdp_format = MDP_Y_CRCB_H2V2;
+		break;
+	case V4L2_PIX_FMT_NV21:
+		mdp_format = MDP_Y_CBCR_H2V2;
+		break;
+	case V4L2_PIX_FMT_YUV420:
+		mdp_format = MDP_Y_CR_CB_H2V2;
+		break;
+	default:
+		pr_err("%s:Unrecognized format %u\n", __func__, pixelformat);
+		mdp_format = MDP_Y_CBCR_H2V2;
+		break;
+	}
+
+	return mdp_format;
+}
+
+static int
+msm_v4l2_overlay_fb_update(struct msm_v4l2_overlay_device *vout,
+	struct v4l2_buffer *buffer)
+{
+	int ret;
+	unsigned long src_addr, src_size;
+	struct msm_v4l2_overlay_userptr_buffer up_buffer;
+
+	if (!buffer ||
+		(buffer->memory == V4L2_MEMORY_MMAP &&
+		 buffer->index >= vout->numbufs))
+		return -EINVAL;
+
+	mutex_lock(&msmfb_lock);
+	switch (buffer->memory) {
+	case V4L2_MEMORY_MMAP:
+		src_addr = (unsigned long)v4l2_ram_phys
+		+ vout->bufs[buffer->index].offset;
+		src_size = buffer->bytesused;
+		ret = msm_fb_v4l2_update(vout->par, src_addr, src_size,
+		0, 0, 0, 0);
+		break;
+	case V4L2_MEMORY_USERPTR:
+		if (copy_from_user(&up_buffer,
+		(void __user *)buffer->m.userptr,
+		sizeof(struct msm_v4l2_overlay_userptr_buffer))) {
+			mutex_unlock(&msmfb_lock);
+			return -EINVAL;
+		}
+		ret = msm_fb_v4l2_update(vout->par,
+		(unsigned long)up_buffer.base[0], up_buffer.length[0],
+		(unsigned long)up_buffer.base[1], up_buffer.length[1],
+		(unsigned long)up_buffer.base[2], up_buffer.length[2]);
+		break;
+	default:
+		mutex_unlock(&msmfb_lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&msmfb_lock);
+
+	if (buffer->memory == V4L2_MEMORY_MMAP) {
+		vout->bufs[buffer->index].queued = 1;
+		buffer->flags |= V4L2_BUF_FLAG_MAPPED;
+	}
+	buffer->flags |= V4L2_BUF_FLAG_QUEUED;
+
+	return ret;
+}
+
+static int
+msm_v4l2_overlay_vidioc_dqbuf(struct file *file,
+	struct msm_v4l2_overlay_fh *fh, void *arg)
+{
+	struct msm_v4l2_overlay_device *vout = fh->vout;
+	struct v4l2_buffer *buffer = arg;
+	int i;
+
+	if (!vout->streaming) {
+		pr_err("%s: Video Stream not enabled\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!buffer || buffer->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	if (buffer->memory == V4L2_MEMORY_MMAP) {
+		for (i = 0; i < vout->numbufs; i++) {
+			if (vout->bufs[i].queued == 1)  {
+				vout->bufs[i].queued = 0;
+				/* Call into fb to remove this buffer? */
+				break;
+			}
+		}
+
+		/*
+		 * This should actually block, unless O_NONBLOCK was
+		 *  specified in open, but fine for now, especially
+		 *  since this is not a capturing device
+		 */
+		if (i == vout->numbufs)
+			return -EAGAIN;
+	}
+
+	buffer->flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+	return 0;
+}
+
+
+static int
+msm_v4l2_overlay_vidioc_qbuf(struct file *file, struct msm_v4l2_overlay_fh* fh,
+	void *arg, bool bUserPtr)
+{
+	struct msm_v4l2_overlay_device *vout = fh->vout;
+	struct v4l2_buffer *buffer = arg;
+	int ret;
+
+	if (!bUserPtr && buffer->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (!vout->streaming) {
+		pr_err("%s: Video Stream not enabled\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!buffer || buffer->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	/* maybe allow only one qbuf at a time? */
+	ret =  msm_v4l2_overlay_fb_update(vout, buffer);
+
+	return 0;
+}
+
+static int
+msm_v4l2_overlay_vidioc_querycap(struct file *file, void *arg)
+{
+	struct v4l2_capability *buffer = arg;
+
+	memset(buffer, 0, sizeof(struct v4l2_capability));
+	strlcpy(buffer->driver, "msm_v4l2_video_overlay",
+		ARRAY_SIZE(buffer->driver));
+	strlcpy(buffer->card, "MSM MDP",
+		ARRAY_SIZE(buffer->card));
+	buffer->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT
+		| V4L2_CAP_VIDEO_OVERLAY;
+	return 0;
+}
+
+static int
+msm_v4l2_overlay_vidioc_fbuf(struct file *file,
+	struct msm_v4l2_overlay_device *vout, void *arg, bool get)
+{
+	struct v4l2_framebuffer *fb = arg;
+
+	if (fb == NULL)
+		return -EINVAL;
+
+	if (get) {
+		mutex_lock(&vout->update_lock);
+		memcpy(&fb->fmt, &vout->pix, sizeof(struct v4l2_pix_format));
+		mutex_unlock(&vout->update_lock);
+	}
+	/* The S_FBUF request does not store anything right now */
+	return 0;
+}
+
+static long msm_v4l2_overlay_calculate_bufsize(struct v4l2_pix_format *pix)
+{
+	int bpp;
+	long bufsize;
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_NV12:
+		bpp = 12;
+		break;
+
+	case V4L2_PIX_FMT_RGB565:
+		bpp = 16;
+		break;
+
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_YUV444:
+		bpp = 24;
+		break;
+
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+		bpp = 32;
+		break;
+	default:
+		pr_err("%s: Unrecognized format %u\n", __func__,
+		pix->pixelformat);
+		bpp = 0;
+	}
+
+	bufsize = (pix->width * pix->height * bpp)/8;
+
+	return bufsize;
+}
+
+static long
+msm_v4l2_overlay_vidioc_reqbufs(struct file *file,
+	struct msm_v4l2_overlay_device *vout, void *arg)
+
+{
+	struct v4l2_requestbuffers *rqb = arg;
+	long bufsize;
+	int i;
+
+	if (rqb == NULL || rqb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	if (rqb->memory == V4L2_MEMORY_MMAP) {
+		if (rqb->count == 0) {
+			/* Deallocate allocated buffers */
+			mutex_lock(&vout->update_lock);
+			vout->numbufs = 0;
+			kfree(vout->bufs);
+			/*
+			 * There should be a way to look at bufs[i]->mapped,
+			 * and prevent userspace from mmaping and directly
+			 * calling this ioctl without unmapping. Maybe kernel
+			 * handles for us, but needs to be checked out
+			 */
+			mutex_unlock(&vout->update_lock);
+		} else {
+			/*
+			 * Keep it simple for now - need to deallocate
+			 * before reallocate
+			 */
+			if (vout->bufs)
+				return -EINVAL;
+
+			mutex_lock(&vout->update_lock);
+			bufsize =
+				msm_v4l2_overlay_calculate_bufsize(&vout->pix);
+			mutex_unlock(&vout->update_lock);
+
+			if (bufsize == 0
+				|| (bufsize * rqb->count) > v4l2_ram_size) {
+				pr_err("%s: Unsupported format or buffer size too large\n",
+				__func__);
+				pr_err("%s: bufsize %lu ram_size %u count %u\n",
+				__func__, bufsize, v4l2_ram_size, rqb->count);
+				return -EINVAL;
+			}
+
+			/*
+			 * We don't support multiple open of one vout,
+			 * but there are probably still some MT problems here,
+			 * (what if same fh is shared between two userspace
+			 * threads and they both call REQBUFS etc)
+			 */
+
+			mutex_lock(&vout->update_lock);
+			vout->numbufs = rqb->count;
+			vout->bufs =
+				kmalloc(rqb->count *
+					sizeof(struct msm_v4l2_overlay_buffer),
+					GFP_KERNEL);
+
+			for (i = 0; i < rqb->count; i++) {
+				struct msm_v4l2_overlay_buffer *b =
+				(struct msm_v4l2_overlay_buffer *)vout->bufs
+				+ i;
+				b->mapped = 0;
+				b->queued = 0;
+				b->offset = PAGE_ALIGN(bufsize*i);
+				b->bufsize = bufsize;
+			}
+
+			mutex_unlock(&vout->update_lock);
+
+		}
+	}
+
+	return 0;
+}
+
+static long
+msm_v4l2_overlay_vidioc_querybuf(struct file *file,
+				 struct msm_v4l2_overlay_device *vout,
+				 void *arg)
+{
+	struct v4l2_buffer *buf = arg;
+	struct msm_v4l2_overlay_buffer *mbuf;
+
+	if (buf == NULL || buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT
+			|| buf->memory == V4L2_MEMORY_USERPTR
+			|| buf->index >= vout->numbufs)
+		return -EINVAL;
+
+	mutex_lock(&vout->update_lock);
+
+	mbuf = (struct msm_v4l2_overlay_buffer *)vout->bufs + buf->index;
+	buf->flags = 0;
+	if (mbuf->mapped)
+		buf->flags |= V4L2_BUF_FLAG_MAPPED;
+	if (mbuf->queued)
+		buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->length = mbuf->bufsize;
+	buf->m.offset = mbuf->offset;
+
+	mutex_unlock(&vout->update_lock);
+
+	return 0;
+}
+
+static long
+msm_v4l2_overlay_do_ioctl(struct file *file,
+		       unsigned int cmd, void *arg)
+{
+	struct msm_v4l2_overlay_fh *fh = file->private_data;
+	struct msm_v4l2_overlay_device *vout = fh->vout;
+	int ret;
+
+	switch (cmd) {
+	case VIDIOC_QUERYCAP:
+		return msm_v4l2_overlay_vidioc_querycap(file, arg);
+
+	case VIDIOC_G_FBUF:
+		return msm_v4l2_overlay_vidioc_fbuf(file, vout, arg, true);
+
+	case VIDIOC_S_FBUF:
+		return msm_v4l2_overlay_vidioc_fbuf(file, vout, arg, false);
+
+	case VIDIOC_REQBUFS:
+		return msm_v4l2_overlay_vidioc_reqbufs(file, vout, arg);
+
+	case VIDIOC_QUERYBUF:
+		return msm_v4l2_overlay_vidioc_querybuf(file, vout, arg);
+
+	case VIDIOC_QBUF:
+		mutex_lock(&vout->update_lock);
+		ret = msm_v4l2_overlay_vidioc_qbuf(file, fh, arg, false);
+		mutex_unlock(&vout->update_lock);
+
+		return ret;
+
+	case VIDIOC_MSM_USERPTR_QBUF:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+
+		mutex_lock(&vout->update_lock);
+		ret = msm_v4l2_overlay_vidioc_qbuf(file, fh, arg, true);
+		mutex_unlock(&vout->update_lock);
+
+		return ret;
+
+	case VIDIOC_DQBUF:
+		mutex_lock(&vout->update_lock);
+		ret = msm_v4l2_overlay_vidioc_dqbuf(file, fh, arg);
+		mutex_unlock(&vout->update_lock);
+		break;
+
+	case VIDIOC_S_FMT: {
+		struct v4l2_format *f = arg;
+
+		switch (f->type) {
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			mutex_lock(&vout->update_lock);
+			memcpy(&vout->win, &f->fmt.win,
+				sizeof(struct v4l2_window));
+			mutex_unlock(&vout->update_lock);
+			break;
+
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			mutex_lock(&vout->update_lock);
+			memcpy(&vout->pix, &f->fmt.pix,
+				sizeof(struct v4l2_pix_format));
+			mutex_unlock(&vout->update_lock);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		break;
+	}
+	case VIDIOC_G_FMT: {
+		struct v4l2_format *f = arg;
+
+		switch (f->type) {
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT: {
+			struct v4l2_pix_format *pix = &f->fmt.pix;
+			memset(pix, 0, sizeof(*pix));
+			*pix = vout->pix;
+			break;
+		}
+
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY: {
+			struct v4l2_window *win = &f->fmt.win;
+			memset(win, 0, sizeof(*win));
+			win->w = vout->win.w;
+			break;
+		}
+		default:
+			return -EINVAL;
+		}
+		break;
+	}
+
+	case VIDIOC_CROPCAP: {
+		struct v4l2_cropcap *cr = arg;
+		if (cr->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+
+		cr->bounds.left =  0;
+		cr->bounds.top = 0;
+		cr->bounds.width = vout->crop_rect.width;
+		cr->bounds.height = vout->crop_rect.height;
+
+		cr->defrect.left =  0;
+		cr->defrect.top = 0;
+		cr->defrect.width = vout->crop_rect.width;
+		cr->defrect.height = vout->crop_rect.height;
+
+		cr->pixelaspect.numerator = 1;
+		cr->pixelaspect.denominator = 1;
+		break;
+	}
+
+	case VIDIOC_S_CROP: {
+		struct v4l2_crop *crop = arg;
+
+		switch (crop->type) {
+
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+
+			mutex_lock(&vout->update_lock);
+			memcpy(&vout->crop_rect, &crop->c,
+				sizeof(struct v4l2_rect));
+			mutex_unlock(&vout->update_lock);
+
+			break;
+
+		default:
+
+			return -EINVAL;
+		}
+		break;
+	}
+	case VIDIOC_G_CROP: {
+		struct v4l2_crop *crop = arg;
+
+		switch (crop->type) {
+
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			memcpy(&crop->c, &vout->crop_rect,
+				sizeof(struct v4l2_rect));
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		break;
+	}
+
+	case VIDIOC_S_CTRL: {
+		struct v4l2_control *ctrl = arg;
+		int32_t rotflag;
+
+		switch (ctrl->id) {
+
+		case V4L2_CID_ROTATE:
+			switch (ctrl->value) {
+			case 0:
+				rotflag = MDP_ROT_NOP;
+				break;
+			case 90:
+				rotflag = MDP_ROT_90;
+				break;
+			case 180:
+				rotflag = MDP_ROT_180;
+				break;
+			case 270:
+				rotflag = MDP_ROT_270;
+				break;
+			default:
+				pr_err("%s: V4L2_CID_ROTATE invalid rotation value %d.\n",
+						__func__, ctrl->value);
+				return -ERANGE;
+			}
+
+			mutex_lock(&vout->update_lock);
+			/* Clear the rotation flags */
+			vout->req.flags &= ~MDP_ROT_NOP;
+			vout->req.flags &= ~MDP_ROT_90;
+			vout->req.flags &= ~MDP_ROT_180;
+			vout->req.flags &= ~MDP_ROT_270;
+			/* Set the new rotation flag */
+			vout->req.flags |= rotflag;
+			mutex_unlock(&vout->update_lock);
+
+			break;
+
+		case V4L2_CID_HFLIP:
+			mutex_lock(&vout->update_lock);
+			/* Clear the flip flag */
+			vout->req.flags &= ~MDP_FLIP_LR;
+			if (true == ctrl->value)
+				vout->req.flags |= MDP_FLIP_LR;
+			mutex_unlock(&vout->update_lock);
+
+			break;
+
+		case V4L2_CID_VFLIP:
+			mutex_lock(&vout->update_lock);
+			/* Clear the flip flag */
+			vout->req.flags &= ~MDP_FLIP_UD;
+			if (true == ctrl->value)
+				vout->req.flags |= MDP_FLIP_UD;
+			mutex_unlock(&vout->update_lock);
+
+			break;
+
+		default:
+			pr_err("%s: VIDIOC_S_CTRL invalid control ID %d.\n",
+			__func__, ctrl->id);
+			return -EINVAL;
+		}
+		break;
+	}
+	case VIDIOC_G_CTRL: {
+		struct v4l2_control *ctrl = arg;
+		__s32 rotation;
+
+		switch (ctrl->id) {
+
+		case V4L2_CID_ROTATE:
+			if (MDP_ROT_NOP == (vout->req.flags & MDP_ROT_NOP))
+				rotation = 0;
+			if (MDP_ROT_90 == (vout->req.flags & MDP_ROT_90))
+				rotation = 90;
+			if (MDP_ROT_180 == (vout->req.flags & MDP_ROT_180))
+				rotation = 180;
+			if (MDP_ROT_270 == (vout->req.flags & MDP_ROT_270))
+				rotation = 270;
+
+			ctrl->value = rotation;
+			break;
+
+		case V4L2_CID_HFLIP:
+			if (MDP_FLIP_LR == (vout->req.flags & MDP_FLIP_LR))
+				ctrl->value = true;
+			break;
+
+		case V4L2_CID_VFLIP:
+			if (MDP_FLIP_UD == (vout->req.flags & MDP_FLIP_UD))
+				ctrl->value = true;
+			break;
+
+		default:
+			pr_err("%s: VIDIOC_G_CTRL invalid control ID %d.\n",
+			__func__, ctrl->id);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	case VIDIOC_STREAMON: {
+
+		if (vout->streaming) {
+			pr_err("%s: VIDIOC_STREAMON: already streaming.\n",
+			__func__);
+			return -EBUSY;
+		}
+
+		mutex_lock(&vout->update_lock);
+		msm_v4l2_overlay_startstreaming(vout);
+		mutex_unlock(&vout->update_lock);
+
+		break;
+	}
+
+	case VIDIOC_STREAMOFF: {
+
+		if (!vout->streaming) {
+			pr_err("%s: VIDIOC_STREAMOFF: not currently streaming.\n",
+			__func__);
+			return -EINVAL;
+		}
+
+		mutex_lock(&vout->update_lock);
+		msm_v4l2_overlay_stopstreaming(vout);
+		mutex_unlock(&vout->update_lock);
+
+		break;
+	}
+
+	default:
+		return -ENOIOCTLCMD;
+
+	} /* switch */
+
+	return 0;
+}
+
+static long
+msm_v4l2_overlay_ioctl(struct file *file, unsigned int cmd,
+		    unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_v4l2_overlay_do_ioctl);
+}
+
+static int
+msm_v4l2_overlay_mmap(struct file *filp, struct vm_area_struct * vma)
+{
+	unsigned long start = (unsigned long)v4l2_ram_phys;
+
+	/*
+	 * vm_pgoff is the offset (>>PAGE_SHIFT) that we provided
+	 * during REQBUFS. off therefore should equal the offset we
+	 * provided in REQBUFS, since last (PAGE_SHIFT) bits of off
+	 * should be 0
+	 */
+	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+	u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + v4l2_ram_size);
+
+	/*
+	 * This is probably unnecessary now - the last PAGE_SHIFT
+	 * bits of start should be 0 now, since we are page aligning
+	 * v4l2_ram_phys
+	 */
+	start &= PAGE_MASK;
+
+	pr_debug("v4l2 map req for phys(%p,%p) offset %u to virt (%p,%p)\n",
+	(void *)(start+off), (void *)(start+off+(vma->vm_end - vma->vm_start)),
+	(unsigned int)off, (void *)vma->vm_start, (void *)vma->vm_end);
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		pr_err("v4l2 map request, memory requested too big\n");
+		return -EINVAL;
+	}
+
+	start += off;
+	vma->vm_pgoff = start >> PAGE_SHIFT;
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	/* Remap the frame buffer I/O range */
+	if (io_remap_pfn_range(vma, vma->vm_start, start >> PAGE_SHIFT,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static int
+msm_v4l2_overlay_release(struct file *file)
+{
+	struct msm_v4l2_overlay_fh *fh = file->private_data;
+	struct msm_v4l2_overlay_device *vout = fh->vout;
+
+	if (vout->streaming)
+		msm_v4l2_overlay_stopstreaming(vout);
+
+	vout->ref_count--;
+
+	kfree(vout->bufs);
+	vout->numbufs = 0;
+	kfree(fh);
+
+	return 0;
+}
+
+static int
+msm_v4l2_overlay_open(struct file *file)
+{
+	struct msm_v4l2_overlay_device	*vout = NULL;
+	struct v4l2_pix_format	*pix = NULL;
+	struct msm_v4l2_overlay_fh *fh;
+
+	vout = saved_vout0;
+	vout->id = 0;
+
+	if (vout->ref_count) {
+		pr_err("%s: multiple open currently is not"
+		"supported!\n", __func__);
+		return -EBUSY;
+	}
+
+	vout->ref_count++;
+
+	/* allocate per-filehandle data */
+	fh = kmalloc(sizeof(struct msm_v4l2_overlay_fh), GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+
+	fh->vout = vout;
+	fh->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+	file->private_data = fh;
+
+	vout->streaming		= 0;
+	vout->crop_rect.left	= vout->crop_rect.top = 0;
+	vout->crop_rect.width	= vout->screen_width;
+	vout->crop_rect.height	= vout->screen_height;
+
+	pix				= &vout->pix;
+	pix->width			= vout->screen_width;
+	pix->height		= vout->screen_height;
+	pix->pixelformat	= V4L2_PIX_FMT_RGB32;
+	pix->field			= V4L2_FIELD_NONE;
+	pix->bytesperline	= pix->width * 4;
+	pix->sizeimage		= pix->bytesperline * pix->height;
+	pix->priv			= 0;
+	pix->colorspace		= V4L2_COLORSPACE_SRGB;
+
+	vout->win.w.left	= 0;
+	vout->win.w.top		= 0;
+	vout->win.w.width	= vout->screen_width;
+	vout->win.w.height	= vout->screen_height;
+
+	vout->fb.capability = V4L2_FBUF_CAP_EXTERNOVERLAY
+		| V4L2_FBUF_CAP_LOCAL_ALPHA;
+	vout->fb.flags = V4L2_FBUF_FLAG_LOCAL_ALPHA;
+	vout->fb.base = 0;
+	memcpy(&vout->fb.fmt, pix, sizeof(struct v4l2_format));
+
+	vout->bufs = 0;
+	vout->numbufs = 0;
+
+	mutex_init(&vout->update_lock);
+
+	return 0;
+}
+
+
+static int __devinit
+msm_v4l2_overlay_probe(struct platform_device *pdev)
+{
+	char *v4l2_ram_phys_unaligned;
+	if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+		v4l2_ram_size =
+			pdev->resource[0].end - pdev->resource[0].start + 1;
+		v4l2_ram_phys_unaligned = (char *)pdev->resource[0].start;
+		v4l2_ram_phys =
+		(char *)PAGE_ALIGN((unsigned int)v4l2_ram_phys_unaligned);
+		/*
+		 * We are (fwd) page aligning the start of v4l2 memory.
+		 * Therefore we have that much less physical memory available
+		 */
+		v4l2_ram_size -= (unsigned int)v4l2_ram_phys
+			- (unsigned int)v4l2_ram_phys_unaligned;
+
+
+	}
+	return 0;
+}
+
+static int __devexit
+msm_v4l2_overlay_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static void msm_v4l2_overlay_videodev_release(struct video_device *vfd)
+{
+	return;
+}
+
+static const struct v4l2_file_operations msm_v4l2_overlay_fops = {
+	.owner		= THIS_MODULE,
+	.open		= msm_v4l2_overlay_open,
+	.release	= msm_v4l2_overlay_release,
+	.mmap		= msm_v4l2_overlay_mmap,
+	.ioctl		= msm_v4l2_overlay_ioctl,
+};
+
+static struct video_device msm_v4l2_overlay_vid_device0 = {
+	.name		= "msm_v4l2_overlay",
+	.fops       = &msm_v4l2_overlay_fops,
+	.minor		= -1,
+	.release	= msm_v4l2_overlay_videodev_release,
+};
+
+static struct platform_driver msm_v4l2_overlay_platform_driver = {
+	.probe   = msm_v4l2_overlay_probe,
+	.remove  = msm_v4l2_overlay_remove,
+	.driver  = {
+			 .name = "msm_v4l2_overlay_pd",
+		   },
+};
+
+static int __init msm_v4l2_overlay_init(void)
+{
+	int ret;
+
+
+	saved_vout0 = kzalloc(sizeof(struct msm_v4l2_overlay_device),
+		GFP_KERNEL);
+
+	if (!saved_vout0)
+		return -ENOMEM;
+
+	ret = platform_driver_register(&msm_v4l2_overlay_platform_driver);
+	if (ret < 0)
+		goto end;
+
+	/*
+	 * Register the device with videodev.
+	 * Videodev will make IOCTL calls on application requests
+	 */
+	ret = video_register_device(&msm_v4l2_overlay_vid_device0,
+		VFL_TYPE_GRABBER, MSM_VIDEO);
+
+	if (ret < 0) {
+		pr_err("%s: V4L2 video overlay device registration failure(%d)\n",
+				  __func__, ret);
+		goto end_unregister;
+	}
+
+	mutex_init(&msmfb_lock);
+
+	return 0;
+
+end_unregister:
+	platform_driver_unregister(&msm_v4l2_overlay_platform_driver);
+
+end:
+	kfree(saved_vout0);
+	return ret;
+}
+
+static void __exit msm_v4l2_overlay_exit(void)
+{
+	video_unregister_device(&msm_v4l2_overlay_vid_device0);
+	platform_driver_unregister(&msm_v4l2_overlay_platform_driver);
+	mutex_destroy(&msmfb_lock);
+	kfree(saved_vout0);
+}
+
+module_init(msm_v4l2_overlay_init);
+module_exit(msm_v4l2_overlay_exit);
+
+MODULE_DESCRIPTION("MSM V4L2 Video Overlay Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_v4l2_video.h b/drivers/media/video/msm/msm_v4l2_video.h
new file mode 100644
index 0000000..a7baa75
--- /dev/null
+++ b/drivers/media/video/msm/msm_v4l2_video.h
@@ -0,0 +1,59 @@
+/* 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 MSM_V4L2_VIDEO_H
+#define MSM_V4L2_VIDEO_H
+
+#include <linux/mm.h>
+#include <linux/msm_mdp.h>
+#include <linux/videodev2.h>
+
+
+struct msm_v4l2_overlay_buffer {
+	int mapped;
+	int queued;
+	int offset;
+	int bufsize;
+};
+
+struct msm_v4l2_overlay_device {
+	struct device dev;
+
+	int ref_count;
+	int id;
+
+	int screen_width;
+	int screen_height;
+	int streaming;
+
+	struct v4l2_pix_format pix;
+	struct v4l2_window win;
+	struct v4l2_rect crop_rect;
+	struct v4l2_framebuffer fb;
+	struct msm_v4l2_overlay_buffer *bufs;
+	int numbufs;
+	struct mdp_overlay req;
+	void *par;
+
+	struct mutex update_lock;
+};
+
+struct msm_v4l2_overlay_fh {
+	struct msm_v4l2_overlay_device *vout;
+	enum v4l2_buf_type type;
+};
+
+struct msm_v4l2_overlay_userptr_buffer {
+	uint base[3];
+	size_t length[3];
+};
+
+#endif
diff --git a/drivers/media/video/msm/msm_vfe31.c b/drivers/media/video/msm/msm_vfe31.c
index f1d70aa..1c9fd03 100644
--- a/drivers/media/video/msm/msm_vfe31.c
+++ b/drivers/media/video/msm/msm_vfe31.c
@@ -21,7 +21,6 @@
 
 #include "msm_vfe31.h"
 #include "msm_vpe1.h"
-
 atomic_t irq_cnt;
 
 #define CHECKED_COPY_FROM_USER(in) {					\
@@ -3029,6 +3028,15 @@
 	/* we render frames in the following conditions:
 	1. Continuous mode and the free buffer is avaialable.
 	*/
+	if (vfe31_ctrl->outpath.output_mode &
+		VFE31_OUTPUT_MODE_P_ALL_CHNLS) {
+		if (!(((ping_pong & PINGPONG_LOWER) == PINGPONG_LOWER) ||
+			((ping_pong & PINGPONG_LOWER) == 0x0))) {
+			pr_err(" Irq_2 - skip the frame pp_status is not proper"
+				"PP_status = 0x%x\n", ping_pong);
+			return;
+		}
+	}
 	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out0);
 
 	if (free_buf) {
diff --git a/drivers/media/video/msm/msm_vfe31.h b/drivers/media/video/msm/msm_vfe31.h
index d1df2dd..1d66621 100644
--- a/drivers/media/video/msm/msm_vfe31.h
+++ b/drivers/media/video/msm/msm_vfe31.h
@@ -154,6 +154,7 @@
 #define VFE_AE_PINGPONG_STATUS_BIT       0x80
 #define VFE_AF_PINGPONG_STATUS_BIT       0x100
 #define VFE_AWB_PINGPONG_STATUS_BIT      0x200
+#define PINGPONG_LOWER                   0x7
 
 #define HFR_MODE_OFF 1
 
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index b539d19..84b9b28 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -868,6 +868,7 @@
 	irq_comp_mask	= msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 
 	if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+		vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
 		vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
 		if (vfe32_ctrl->outpath.output_mode &
 			VFE32_OUTPUT_MODE_PRIMARY) {
@@ -938,7 +939,9 @@
 	}
 	msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 
-	if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+	switch (vfe32_ctrl->operation_mode) {
+	case VFE_OUTPUTS_PREVIEW:
+	case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
 		if (vfe32_ctrl->outpath.output_mode &
 			VFE32_OUTPUT_MODE_PRIMARY) {
 			msm_io_w(1, vfe32_ctrl->vfebase +
@@ -954,7 +957,8 @@
 			msm_io_w(1, vfe32_ctrl->vfebase +
 			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]);
 		}
-	} else {
+		break;
+	default:
 		if (vfe32_ctrl->outpath.output_mode &
 			VFE32_OUTPUT_MODE_SECONDARY) {
 			msm_io_w(1, vfe32_ctrl->vfebase +
@@ -970,7 +974,9 @@
 			msm_io_w(1, vfe32_ctrl->vfebase +
 			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch2]);
 		}
+		break;
 	}
+
 	msm_camio_bus_scale_cfg(
 		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe32_start_common();
@@ -1259,8 +1265,10 @@
 	case VFE_CMD_START:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
 			vfe32_general_cmd[cmd->id]);
-		if (vfe32_ctrl->operation_mode ==
-				VFE_OUTPUTS_PREVIEW_AND_VIDEO)
+		if ((vfe32_ctrl->operation_mode ==
+				VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+				(vfe32_ctrl->operation_mode ==
+				VFE_OUTPUTS_PREVIEW))
 			/* Configure primary channel */
 			rc = vfe32_configure_pingpong_buffers(
 				VFE_MSG_V32_START, VFE_MSG_OUTPUT_PRIMARY);
@@ -1297,8 +1305,6 @@
 		rc = vfe32_capture_raw(snapshot_cnt);
 		break;
 	case VFE_CMD_CAPTURE:
-		CDBG("vfe32_proc_general: cmdID = %s op mode = %d\n",
-			vfe32_general_cmd[cmd->id], vfe32_ctrl->operation_mode);
 		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
 				sizeof(uint32_t))) {
 			rc = -EFAULT;
@@ -2960,13 +2966,14 @@
 
 	free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
 		VFE_MSG_OUTPUT_SECONDARY);
-
 	out_bool = ((vfe32_ctrl->operation_mode ==
 				VFE_OUTPUTS_THUMB_AND_MAIN ||
 			vfe32_ctrl->operation_mode ==
 				VFE_OUTPUTS_MAIN_AND_THUMB ||
 			vfe32_ctrl->operation_mode ==
-				VFE_OUTPUTS_RAW) &&
+				VFE_OUTPUTS_RAW ||
+			vfe32_ctrl->operation_mode ==
+				VFE_OUTPUTS_JPEG_AND_THUMB) &&
 			(vfe32_ctrl->vfe_capture_count <= 1)) || free_buf;
 
 	if (out_bool) {
@@ -3003,7 +3010,9 @@
 			vfe32_ctrl->operation_mode ==
 				VFE_OUTPUTS_MAIN_AND_THUMB ||
 			vfe32_ctrl->operation_mode ==
-				VFE_OUTPUTS_RAW)
+				VFE_OUTPUTS_RAW ||
+			vfe32_ctrl->operation_mode ==
+				VFE_OUTPUTS_JPEG_AND_THUMB)
 			vfe32_ctrl->outpath.out1.capture_cnt--;
 
 		vfe_send_outmsg(&vfe32_ctrl->subdev,
@@ -3947,6 +3956,9 @@
 void msm_vfe_subdev_release(struct platform_device *pdev)
 {
 	struct msm_sync *sync = vfe_syncdata;
+	CDBG("%s, free_irq\n", __func__);
+	disable_irq(vfe32_ctrl->vfeirq->start);
+	tasklet_kill(&vfe32_tasklet);
 	msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info,
 			vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
 	if (vfe32_ctrl->fs_vfe) {
@@ -3954,9 +3966,6 @@
 		regulator_put(vfe32_ctrl->fs_vfe);
 		vfe32_ctrl->fs_vfe = NULL;
 	}
-	CDBG("%s, free_irq\n", __func__);
-	disable_irq(vfe32_ctrl->vfeirq->start);
-	tasklet_kill(&vfe32_tasklet);
 	iounmap(vfe32_ctrl->vfebase);
 
 	if (atomic_read(&irq_cnt))
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 638c51d..e2236191 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -292,7 +292,8 @@
 		"VFE_DEMOSAICv3_BPC_UPDATE"},
 	{VFE_CMD_XBAR_CFG, VFE_MAX, VFE_MAX},
 	{VFE_CMD_MODULE_CFG, VFE_MAX, VFE_MAX},
-	{VFE_CMD_ZSL, VFE_MAX, VFE_MAX},
+	{VFE_CMD_ZSL, VFE_START, QDSP_CMDQUEUE,
+			"VFE_CMD_ZSL", "VFE_START"},
 	{VFE_CMD_LINEARIZATION_UPDATE, VFE_MAX, VFE_MAX},
 	{VFE_CMD_DEMOSAICV3_ABF_UPDATE, VFE_DEMOSAICv3_ABF_CFG,
 		QDSP_TABLEQUEUE, "VFE_CMD_DEMOSAICV3_ABF_UPDATE",
@@ -327,6 +328,9 @@
 	{VFE_CMD_SCALE_OUTPUT2_CONFIG, VFE_SCALE_OUTPUT2_CONFIG,
 		QDSP_SCALEQUEUE, "VFE_CMD_SCALE_OUTPUT2_CONFIG",
 		"VFE_SCALE_OUTPUT2_CONFIG"},
+	{VFE_CMD_CAPTURE_RAW, VFE_START, QDSP_CMDQUEUE,
+			"VFE_CMD_CAPTURE_RAW", "VFE_START"},
+	{VFE_CMD_RECONFIG_VFE, VFE_MAX, VFE_MAX},
 };
 
 
@@ -400,9 +404,9 @@
 	unsigned char buf[256];
 	struct msm_free_buf *free_buf = NULL;
 	struct vfe_outputack fack;
+	int i;
 
 	CDBG("%s:id=%d\n", __func__, id);
-
 	if (id != VFE_ADSP_EVENT) {
 		data = kzalloc(len, GFP_KERNEL);
 		if (!data) {
@@ -434,8 +438,9 @@
 			cbcr_phy = outch->ping.ch_paddr[1];
 			CDBG("MSG_OUTPUT_S: %x %x\n",
 				(unsigned int)y_phy, (unsigned int)cbcr_phy);
-			vfe_send_outmsg(&vfe2x_ctrl->subdev, MSG_ID_OUTPUT_S,
-							y_phy, cbcr_phy);
+			vfe_send_outmsg(&vfe2x_ctrl->subdev,
+					MSG_ID_OUTPUT_PRIMARY,
+						y_phy, cbcr_phy);
 			break;
 		case MSG_OUTPUT_T:
 			outch = &vfe2x_ctrl->thumb;
@@ -443,10 +448,80 @@
 			cbcr_phy = outch->ping.ch_paddr[1];
 			CDBG("MSG_OUTPUT_T: %x %x\n",
 				(unsigned int)y_phy, (unsigned int)cbcr_phy);
-			vfe_send_outmsg(&vfe2x_ctrl->subdev, MSG_ID_OUTPUT_T,
+			vfe_send_outmsg(&vfe2x_ctrl->subdev,
+						MSG_ID_OUTPUT_SECONDARY,
 							y_phy, cbcr_phy);
 			break;
 		case MSG_OUTPUT1:
+			if (op_mode & SNAPSHOT_MASK_MODE) {
+				kfree(data);
+				return;
+			} else {
+				free_buf = vfe2x_check_free_buffer(
+							VFE_MSG_OUTPUT_IRQ,
+							VFE_MSG_OUTPUT_SECONDARY
+							);
+				CDBG("free_buf = %x\n",
+						(unsigned int) free_buf);
+				if (free_buf) {
+					fack.header = VFE_OUTPUT1_ACK;
+
+					fack.output2newybufferaddress =
+						(void *)(free_buf->ch_paddr[0]);
+
+					fack.output2newcbcrbufferaddress =
+						(void *)(free_buf->ch_paddr[1]);
+
+					cmd_data = &fack;
+					len = sizeof(fack);
+					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+							cmd_data, len);
+			      } else {
+					fack.header = VFE_OUTPUT1_ACK;
+					fack.output2newybufferaddress =
+					(void *)
+				((struct vfe_endframe *)data)->y_address;
+					fack.output2newcbcrbufferaddress =
+					(void *)
+				((struct vfe_endframe *)data)->cbcr_address;
+					cmd_data = &fack;
+					len = sizeof(fack);
+					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+						cmd_data, len);
+				}
+			}
+			y_phy = ((struct vfe_endframe *)data)->y_address;
+			cbcr_phy = ((struct vfe_endframe *)data)->cbcr_address;
+
+
+			CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+				 y_phy, cbcr_phy);
+			if (free_buf) {
+				for (i = 0; i < 3; i++) {
+					if (vfe2x_ctrl->free_buf.buf[i].
+							ch_paddr[0] == y_phy) {
+						vfe2x_ctrl->free_buf.
+							buf[i].ch_paddr[0] =
+							free_buf->ch_paddr[0];
+						vfe2x_ctrl->free_buf.
+							buf[i].ch_paddr[1] =
+							free_buf->ch_paddr[1];
+						break;
+					}
+				}
+				if (i == 3)
+					CDBG("Address doesnt match\n");
+			}
+			memcpy(((struct vfe_frame_extra *)extdata),
+				&((struct vfe_endframe *)data)->extra,
+				sizeof(struct vfe_frame_extra));
+
+			vfe2x_ctrl->vfeFrameId =
+				((struct vfe_frame_extra *)extdata)->frame_id;
+			vfe_send_outmsg(&vfe2x_ctrl->subdev,
+						MSG_ID_OUTPUT_SECONDARY,
+						y_phy, cbcr_phy);
+			break;
 		case MSG_OUTPUT2:
 			if (op_mode & SNAPSHOT_MASK_MODE) {
 				kfree(data);
@@ -454,7 +529,7 @@
 			} else {
 				free_buf = vfe2x_check_free_buffer(
 					VFE_MSG_OUTPUT_IRQ,
-					VFE_MSG_OUTPUT_P);
+					VFE_MSG_OUTPUT_PRIMARY);
 			      CDBG("free_buf = %x\n", (unsigned int) free_buf);
 			      if (free_buf) {
 					fack.header = VFE_OUTPUT2_ACK;
@@ -489,7 +564,22 @@
 
 			CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
 				 y_phy, cbcr_phy);
-
+			if (free_buf) {
+				for (i = 0; i < 3; i++) {
+					if (vfe2x_ctrl->free_buf.buf[i].
+							ch_paddr[0] == y_phy) {
+						vfe2x_ctrl->free_buf.
+							buf[i].ch_paddr[0] =
+							free_buf->ch_paddr[0];
+						vfe2x_ctrl->free_buf.
+							buf[i].ch_paddr[1] =
+							free_buf->ch_paddr[1];
+						break;
+					}
+				}
+				if (i == 3)
+					CDBG("Address doesnt match\n");
+			}
 			memcpy(((struct vfe_frame_extra *)extdata),
 				&((struct vfe_endframe *)data)->extra,
 				sizeof(struct vfe_frame_extra));
@@ -497,8 +587,8 @@
 			vfe2x_ctrl->vfeFrameId =
 				((struct vfe_frame_extra *)extdata)->frame_id;
 			vfe_send_outmsg(&vfe2x_ctrl->subdev,
-							MSG_ID_OUTPUT_P,
-							y_phy, cbcr_phy);
+						MSG_ID_OUTPUT_PRIMARY,
+						y_phy, cbcr_phy);
 			break;
 		case MSG_RESET_ACK:
 		case MSG_START_ACK:
@@ -509,11 +599,55 @@
 			vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
 			if (id == MSG_START_ACK)
 				vfe2x_ctrl->vfe_started = 1;
+			if (id == MSG_VFE_ERROR) {
+				uint16_t *ptr;
+				struct vfe_error_msg *VFE_ErrorMessageBuffer
+					= data;
+				ptr = data;
+				CDBG("Error: %x %x\n", ptr[0], ptr[1]);
+				CDBG("CAMIF_Error              = %d\n",
+					VFE_ErrorMessageBuffer->camif_error);
+				CDBG("output1YBusOverflow      = %d\n",
+					VFE_ErrorMessageBuffer->
+					output1ybusoverflow);
+				CDBG("output1CbCrBusOverflow   = %d\n",
+					VFE_ErrorMessageBuffer->
+					output1cbcrbusoverflow);
+				CDBG("output2YBusOverflow      = %d\n",
+					VFE_ErrorMessageBuffer->
+					output2ybusoverflow);
+				CDBG("output2CbCrBusOverflow   = %d\n",
+						VFE_ErrorMessageBuffer->
+						output2cbcrbusoverflow);
+				CDBG("autofocusStatBusOverflow = %d\n",
+						VFE_ErrorMessageBuffer->
+						autofocusstatbusoverflow);
+				CDBG("WB_EXPStatBusOverflow    = %d\n",
+						VFE_ErrorMessageBuffer->
+						wb_expstatbusoverflow);
+				CDBG("AXIError                 = %d\n",
+						VFE_ErrorMessageBuffer->
+						axierror);
+				CDBG("CAMIF_Staus              = %d\n",
+						VFE_ErrorMessageBuffer->
+						camif_staus);
+				CDBG("pixel_count              = %d\n",
+						VFE_ErrorMessageBuffer->
+						pixel_count);
+				CDBG("line_count               = %d\n",
+						VFE_ErrorMessageBuffer->
+						line_count);
+			}
 			break;
 		case MSG_SOF:
 			vfe2x_ctrl->vfeFrameId++;
 			if (vfe2x_ctrl->vfeFrameId == 0)
 				vfe2x_ctrl->vfeFrameId = 1; /* wrapped back */
+			if ((op_mode & SNAPSHOT_MASK_MODE) && !raw_mode) {
+				pr_err("Ignore SOF for snapshot\n");
+				kfree(data);
+				return;
+			}
 			vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_SOF_ACK);
 			if (raw_mode)
 				vfe2x_send_isp_msg(vfe2x_ctrl,
@@ -537,6 +671,7 @@
 	}
 	if (MSG_TABLE_CMD_ACK == id) {
 		spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+		vfe2x_ctrl->tableack_pending = 0;
 		if (list_empty(&vfe2x_ctrl->table_q)) {
 			if (vfe2x_ctrl->start_pending) {
 				CDBG("Send START\n");
@@ -550,15 +685,31 @@
 				msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
 						cmd_data, len);
 				vfe2x_ctrl->start_pending = 0;
+			} else if (vfe2x_ctrl->stop_pending) {
+				CDBG("Send STOP\n");
+				cmd_data = buf;
+				*(uint32_t *)cmd_data = VFE_STOP;
+				/* Send Stop cmd here */
+				len  = 4;
+				msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+						cmd_data, len);
+				vfe2x_ctrl->stop_pending = 0;
+			} else if (vfe2x_ctrl->update_pending) {
+				CDBG("Send Update\n");
+				cmd_data = buf;
+				*(uint32_t *)cmd_data = VFE_UPDATE;
+				/* Send Update cmd here */
+				len  = 4;
+				msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+						cmd_data, len);
+				vfe2x_ctrl->update_pending = 0;
 			}
-			vfe2x_ctrl->tableack_pending = 0;
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			return;
 		}
 		table_pending = list_first_entry(&vfe2x_ctrl->table_q,
 					struct table_cmd, list);
 		if (!table_pending) {
-			vfe2x_ctrl->tableack_pending = 0;
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			return;
 		}
@@ -584,23 +735,42 @@
 	unsigned long *bptr;
 	int    cnt;
 	int rc = 0;
+	int o_mode = 0;
 
+	if (op_mode & SNAPSHOT_MASK_MODE)
+		o_mode = SNAPSHOT_MASK_MODE;
 
-	if (mode == OUTPUT_1) {
-		ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
-		ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
-		ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
-		ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
-		bptr = &ao->output1buffer3_y_phy;
-		for (cnt = 0; cnt < 6; cnt++) {
-			*bptr = ad->pong.ch_paddr[0];
-			bptr++;
-			*bptr = ad->pong.ch_paddr[1];
-			bptr++;
+	if (mode == OUTPUT_SEC) {
+		/* Thumbnail */
+		if (vfe2x_ctrl->zsl_mode) {
+			ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
+			ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+			ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
+			ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+			ao->output1buffer3_y_phy = ad->free_buf.ch_paddr[0];
+			ao->output1buffer3_cbcr_phy = ad->free_buf.ch_paddr[1];
+			bptr = &ao->output1buffer4_y_phy;
+			for (cnt = 0; cnt < 5; cnt++) {
+				*bptr = ad->pong.ch_paddr[0];
+				bptr++;
+				*bptr = ad->pong.ch_paddr[1];
+				bptr++;
+			}
+		} else {
+			ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
+			ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+			ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
+			ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+			bptr = &ao->output1buffer3_y_phy;
+			for (cnt = 0; cnt < 6; cnt++) {
+				*bptr = ad->pong.ch_paddr[0];
+				bptr++;
+				*bptr = ad->pong.ch_paddr[1];
+				bptr++;
+			}
 		}
-	}
-
-	if (mode == OUTPUT_2) {
+	} else if (mode == OUTPUT_PRIM && o_mode != SNAPSHOT_MASK_MODE) {
+		/* Preview */
 		ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
 		ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[1];
 		ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
@@ -614,9 +784,30 @@
 			*bptr = ad->pong.ch_paddr[1];
 			bptr++;
 		}
-	}
-
-	if (mode == OUTPUT_1_AND_2) {
+		CDBG("%x %x\n", (unsigned int)ao->output2buffer1_y_phy,
+			(unsigned int)ao->output2buffer1_cbcr_phy);
+		CDBG("%x %x\n", (unsigned int)ao->output2buffer2_y_phy,
+			(unsigned int)ao->output2buffer2_cbcr_phy);
+		CDBG("%x %x\n", (unsigned int)ao->output2buffer3_y_phy,
+			(unsigned int)ao->output2buffer3_cbcr_phy);
+		CDBG("%x %x\n", (unsigned int)ao->output2buffer4_y_phy,
+			(unsigned int)ao->output2buffer4_cbcr_phy);
+		CDBG("%x %x\n", (unsigned int)ao->output2buffer5_y_phy,
+			(unsigned int)ao->output2buffer5_cbcr_phy);
+		CDBG("%x %x\n", (unsigned int)ao->output2buffer6_y_phy,
+			(unsigned int)ao->output2buffer6_cbcr_phy);
+		CDBG("%x %x\n", (unsigned int)ao->output2buffer7_y_phy,
+			(unsigned int)ao->output2buffer7_cbcr_phy);
+		vfe2x_ctrl->free_buf.buf[0].ch_paddr[0] = ad->ping.ch_paddr[0];
+		vfe2x_ctrl->free_buf.buf[0].ch_paddr[1] = ad->ping.ch_paddr[1];
+		vfe2x_ctrl->free_buf.buf[1].ch_paddr[0] = ad->pong.ch_paddr[0];
+		vfe2x_ctrl->free_buf.buf[1].ch_paddr[1] = ad->pong.ch_paddr[1];
+		vfe2x_ctrl->free_buf.buf[2].ch_paddr[0] =
+			ad->free_buf.ch_paddr[0];
+		vfe2x_ctrl->free_buf.buf[2].ch_paddr[1] =
+			ad->free_buf.ch_paddr[1];
+	} else if (mode == OUTPUT_PRIM && o_mode == SNAPSHOT_MASK_MODE) {
+		vfe2x_ctrl->reconfig_vfe = 0;
 		if (raw_mode) {
 			ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
 			ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[0];
@@ -632,7 +823,7 @@
 		for (cnt = 0; cnt < 6; cnt++) {
 			*bptr = ad->pong.ch_paddr[0];
 			bptr++;
-			*bptr = ad->pong.ch_paddr[0];
+			*bptr = ad->pong.ch_paddr[1];
 			bptr++;
 		}
 	}
@@ -664,13 +855,18 @@
 
 	vfe2x_subdev_notify(id, path);
 	if (op_mode & SNAPSHOT_MASK_MODE) {
-		if (path == VFE_MSG_OUTPUT_S)
+		if (path == VFE_MSG_OUTPUT_PRIMARY)
 			outch = &vfe2x_ctrl->snap;
-		else if (path == VFE_MSG_OUTPUT_T)
+		else if (path == VFE_MSG_OUTPUT_SECONDARY)
 			outch = &vfe2x_ctrl->thumb;
 	} else {
-		if (path == VFE_MSG_OUTPUT_P)
-			outch = &vfe2x_ctrl->prev;
+		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+			if (vfe2x_ctrl->zsl_mode)
+				outch = &vfe2x_ctrl->zsl_prim;
+			else
+				outch = &vfe2x_ctrl->prev;
+		} else if (path == VFE_MSG_OUTPUT_SECONDARY)
+				outch = &vfe2x_ctrl->zsl_sec;
 	}
 	if (outch->free_buf.ch_paddr[0])
 		return &outch->free_buf;
@@ -684,16 +880,20 @@
 	int rc = 0;
 
 	vfe2x_subdev_notify(id, path);
-
 	CDBG("Opmode = %d\n", op_mode);
 	if (op_mode & SNAPSHOT_MASK_MODE) {
-		if (path == VFE_MSG_OUTPUT_S)
+		if (path == VFE_MSG_OUTPUT_PRIMARY)
 			outch = &vfe2x_ctrl->snap;
-		else if (path == VFE_MSG_OUTPUT_T)
+		else if (path == VFE_MSG_OUTPUT_SECONDARY)
 			outch = &vfe2x_ctrl->thumb;
 	} else {
-		if (path == VFE_MSG_OUTPUT_P)
-			outch = &vfe2x_ctrl->prev;
+		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+			if (vfe2x_ctrl->zsl_mode)
+				outch = &vfe2x_ctrl->zsl_prim;
+			else
+				outch = &vfe2x_ctrl->prev;
+		} else if (path == VFE_MSG_OUTPUT_SECONDARY)
+			outch = &vfe2x_ctrl->zsl_sec;
 	}
 	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
 		/* Configure Preview Ping Pong */
@@ -711,14 +911,20 @@
 	struct buf_info *ch = NULL;
 
 	CDBG("path = %d op_mode = %d\n", path, op_mode);
+	/* TODO: Remove Mode specific stuff */
 	if (op_mode & SNAPSHOT_MASK_MODE) {
-		if (path == VFE_MSG_OUTPUT_T)
+		if (path == VFE_MSG_OUTPUT_SECONDARY)
 			ch = &vfe2x_ctrl->thumb;
-		else if (path == VFE_MSG_OUTPUT_S)
+		else if (path == VFE_MSG_OUTPUT_PRIMARY)
 			ch = &vfe2x_ctrl->snap;
 	} else {
-		if (path == VFE_MSG_OUTPUT_P)
-			ch = &vfe2x_ctrl->prev;
+		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+			if (vfe2x_ctrl->zsl_mode)
+				ch = &vfe2x_ctrl->zsl_prim;
+			else
+				ch = &vfe2x_ctrl->prev;
+		} else if (path == VFE_MSG_OUTPUT_SECONDARY)
+			ch = &vfe2x_ctrl->zsl_sec;
 	}
 
 	BUG_ON(ch == NULL);
@@ -777,11 +983,11 @@
 		if (op_mode & SNAPSHOT_MASK_MODE) {
 			free_buf = vfe2x_check_free_buffer(
 					VFE_MSG_OUTPUT_IRQ,
-					VFE_MSG_OUTPUT_T);
+					VFE_MSG_OUTPUT_SECONDARY);
 		} else {
 			free_buf = vfe2x_check_free_buffer(
 					VFE_MSG_OUTPUT_IRQ,
-					VFE_MSG_OUTPUT_P);
+					VFE_MSG_OUTPUT_PRIMARY);
 			if (free_buf) {
 				fack.header = VFE_OUTPUT2_ACK;
 
@@ -875,6 +1081,7 @@
 		break;
 	case CMD_STATS_AF_ENABLE:
 	case CMD_STATS_AF_AXI_CFG: {
+		CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
 		axid = data;
 		if (!axid) {
 			rc = -EFAULT;
@@ -908,6 +1115,7 @@
 			goto config_failure;
 		}
 		*(uint32_t *)sfcfg = header;
+		CDBG("Number of buffers = %d\n", axid->bufnum1);
 		if (axid->bufnum1 > 0) {
 			regptr = &axid->region[0];
 
@@ -973,6 +1181,11 @@
 			op_mode = vfe2x_ctrl->start_cmd.mode_of_operation;
 			return rc;
 		}
+		if (vfecmd.id == VFE_CMD_RECONFIG_VFE) {
+			CDBG("VFE is RECONFIGURED\n");
+			vfe2x_ctrl->reconfig_vfe = 1;
+			return 0;
+		}
 		if (vfecmd.length > 256 - 4) {
 			cmd_data_alloc =
 			cmd_data = kmalloc(vfecmd.length + 4, GFP_ATOMIC);
@@ -1002,16 +1215,18 @@
 		if (queue == QDSP_CMDQUEUE) {
 			switch (vfecmd.id) {
 			case VFE_CMD_RESET:
-				msm_adsp_enable(qcam_mod);
-				msm_adsp_enable(vfe_mod);
 				msm_camio_vfe_blk_reset();
 				vfestopped = 0;
 				break;
 			case VFE_CMD_START:
 			case VFE_CMD_CAPTURE:
+			case VFE_CMD_CAPTURE_RAW:
+			case VFE_CMD_ZSL:
 				spin_lock_irqsave(&vfe2x_ctrl->table_lock,
 									flags);
-				if (!list_empty(&vfe2x_ctrl->table_q)) {
+				if ((!list_empty(&vfe2x_ctrl->table_q)) ||
+						vfe2x_ctrl->tableack_pending) {
+					CDBG("start pending\n");
 					vfe2x_ctrl->start_pending = 1;
 					spin_unlock_irqrestore(
 						&vfe2x_ctrl->table_lock,
@@ -1032,18 +1247,99 @@
 				break;
 			case VFE_CMD_STOP:
 				vfestopped = 1;
+				spin_lock_irqsave(&vfe2x_ctrl->table_lock,
+						flags);
+				if ((!list_empty(&vfe2x_ctrl->table_q)) ||
+						vfe2x_ctrl->tableack_pending) {
+					CDBG("stop pending\n");
+					vfe2x_ctrl->stop_pending = 1;
+					spin_unlock_irqrestore(
+							&vfe2x_ctrl->table_lock,
+							flags);
+					return 0;
+				}
+				spin_unlock_irqrestore(&vfe2x_ctrl->table_lock,
+						flags);
 				vfe2x_ctrl->vfe_started = 0;
 				goto config_send;
-
+			case VFE_CMD_UPDATE:
+				spin_lock_irqsave(&vfe2x_ctrl->table_lock,
+						flags);
+				if ((!list_empty(&vfe2x_ctrl->table_q)) ||
+						vfe2x_ctrl->tableack_pending) {
+					CDBG("update pending\n");
+					vfe2x_ctrl->update_pending = 1;
+					spin_unlock_irqrestore(
+							&vfe2x_ctrl->table_lock,
+							flags);
+					return 0;
+				}
+				spin_unlock_irqrestore(&vfe2x_ctrl->table_lock,
+						flags);
+				goto config_send;
 			default:
 				break;
 			}
 		} /* QDSP_CMDQUEUE */
 	}
 		break;
-	case CMD_AXI_CFG_PREVIEW: {
-		CDBG("CMD_AXI_CFG_PREVIEW\n");
+	case CMD_AXI_CFG_SEC: {
+		CDBG("CMD_AXI_CFG_SEC\n");
 		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 0;
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			pr_err("NULL axio\n");
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)axio + 4,
+					(void __user *)(vfecmd.value),
+					sizeof(struct axiout))) {
+			CDBG("copy_from_user failed\n");
+			rc = -EFAULT;
+			goto config_done;
+		}
+		if (op_mode & SNAPSHOT_MASK_MODE)
+			rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_CAPTURE,
+						VFE_MSG_OUTPUT_SECONDARY);
+		else
+			rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_SECONDARY);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers"
+				" for preview", __func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+
+		if (!(op_mode & SNAPSHOT_MASK_MODE))
+			free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_SECONDARY);
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		*(uint32_t *)axio = header;
+		if (op_mode & SNAPSHOT_MASK_MODE)
+			vfe_7x_config_axi(OUTPUT_SEC,
+					&vfe2x_ctrl->thumb, axio);
+		else
+			vfe_7x_config_axi(OUTPUT_SEC,
+					&vfe2x_ctrl->video, axio);
+		cmd_data = axio;
+	}
+		break;
+	case CMD_AXI_CFG_PRIM: {
+		CDBG("CMD_AXI_CFG_PRIM : %d\n", op_mode);
+		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 0;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
 			pr_err("NULL axio\n");
@@ -1058,18 +1354,40 @@
 			rc = -EFAULT;
 			goto config_done;
 		}
-		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_PREVIEW,
-							VFE_MSG_OUTPUT_P);
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				" for preview", __func__);
-			rc = -EINVAL;
-			goto config_done;
-		}
-
-		free_buf = vfe2x_check_free_buffer(
+		if (!vfe2x_ctrl->reconfig_vfe) {
+			if (op_mode & SNAPSHOT_MASK_MODE)
+				rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_CAPTURE,
+						VFE_MSG_OUTPUT_PRIMARY);
+			else
+				rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_PRIMARY);
+			if (rc < 0) {
+				pr_err("%s error configuring pingpong buffers"
+					" for preview", __func__);
+				rc = -EINVAL;
+				goto config_done;
+			}
+			if (!(op_mode & SNAPSHOT_MASK_MODE))
+				free_buf = vfe2x_check_free_buffer(
 					VFE_MSG_OUTPUT_IRQ,
-					VFE_MSG_OUTPUT_P);
+					VFE_MSG_OUTPUT_PRIMARY);
+		} else {
+			vfe2x_ctrl->prev.ping.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[0].ch_paddr[0];
+			vfe2x_ctrl->prev.ping.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[0].ch_paddr[1];
+			vfe2x_ctrl->prev.pong.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[1].ch_paddr[0];
+			vfe2x_ctrl->prev.pong.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[1].ch_paddr[1];
+			vfe2x_ctrl->prev.free_buf.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[2].ch_paddr[0];
+			vfe2x_ctrl->prev.free_buf.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[2].ch_paddr[1];
+			vfe2x_ctrl->reconfig_vfe = 0;
+		}
 		header = cmds_map[vfecmd.id].vfe_id;
 		queue = cmds_map[vfecmd.id].queue;
 		if (header == -1 && queue == -1) {
@@ -1077,7 +1395,151 @@
 			goto config_done;
 		}
 		*(uint32_t *)axio = header;
-		vfe_7x_config_axi(OUTPUT_2, &vfe2x_ctrl->prev, axio);
+		if (op_mode & SNAPSHOT_MASK_MODE)
+			vfe_7x_config_axi(OUTPUT_PRIM, &vfe2x_ctrl->snap, axio);
+		else
+			vfe_7x_config_axi(OUTPUT_PRIM, &vfe2x_ctrl->prev, axio);
+		cmd_data = axio;
+	}
+		break;
+	case CMD_AXI_CFG_ZSL: {
+		CDBG("CMD_AXI_CFG_ZSL: %d\n", op_mode);
+		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 1;
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			pr_err("NULL axio\n");
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)axio + 4,
+					(void __user *)(vfecmd.value),
+					sizeof(struct axiout))) {
+			pr_err("copy_from_user failed\n");
+			rc = -EFAULT;
+			goto config_done;
+		}
+		if (!vfe2x_ctrl->reconfig_vfe) {
+				rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_PRIMARY);
+				rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_SECONDARY);
+			if (rc < 0) {
+				pr_err("%s error configuring pingpong buffers"
+					" for preview", __func__);
+				rc = -EINVAL;
+				goto config_done;
+			}
+				free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_PRIMARY);
+				free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_SECONDARY);
+		} else {
+			vfe2x_ctrl->prev.ping.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[0].ch_paddr[0];
+			vfe2x_ctrl->prev.ping.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[0].ch_paddr[1];
+			vfe2x_ctrl->prev.pong.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[1].ch_paddr[0];
+			vfe2x_ctrl->prev.pong.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[1].ch_paddr[1];
+			vfe2x_ctrl->prev.free_buf.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[2].ch_paddr[0];
+			vfe2x_ctrl->prev.free_buf.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[2].ch_paddr[1];
+			vfe2x_ctrl->reconfig_vfe = 0;
+		}
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		*(uint32_t *)axio = header;
+		vfe_7x_config_axi(OUTPUT_PRIM, &vfe2x_ctrl->zsl_prim, axio);
+		vfe_7x_config_axi(OUTPUT_SEC, &vfe2x_ctrl->zsl_sec, axio);
+		cmd_data = axio;
+	}
+		break;
+	case CMD_AXI_CFG_SEC|CMD_AXI_CFG_PRIM: {
+		CDBG("CMD_AXI_CFG_SEC|PRIM\n");
+		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 0;
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			pr_err("NULL axio\n");
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)axio + 4,
+					(void __user *)(vfecmd.value),
+					sizeof(struct axiout))) {
+			pr_err("copy_from_user failed\n");
+			rc = -EFAULT;
+			goto config_done;
+		}
+		if (op_mode & SNAPSHOT_MASK_MODE)
+			rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_CAPTURE,
+						VFE_MSG_OUTPUT_SECONDARY);
+		else
+			rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_SECONDARY);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers"
+				" for preview", __func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+
+		if (!(op_mode & SNAPSHOT_MASK_MODE))
+			free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_SECONDARY);
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		*(uint32_t *)axio = header;
+		if (op_mode & SNAPSHOT_MASK_MODE)
+			vfe_7x_config_axi(OUTPUT_SEC, &vfe2x_ctrl->thumb, axio);
+		else
+			vfe_7x_config_axi(OUTPUT_SEC, &vfe2x_ctrl->prev, axio);
+
+		if (op_mode & SNAPSHOT_MASK_MODE)
+			rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_CAPTURE,
+						VFE_MSG_OUTPUT_PRIMARY);
+		else
+			rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_PRIMARY);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers"
+				" for preview", __func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+
+		if (!(op_mode & SNAPSHOT_MASK_MODE))
+			free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_PRIMARY);
+		if (op_mode & SNAPSHOT_MASK_MODE)
+			vfe_7x_config_axi(OUTPUT_PRIM,
+					&vfe2x_ctrl->snap, axio);
+		else
+			vfe_7x_config_axi(OUTPUT_PRIM,
+					&vfe2x_ctrl->prev, axio);
 		cmd_data = axio;
 	}
 		break;
@@ -1099,7 +1561,7 @@
 		header = cmds_map[vfecmd.id].vfe_id;
 		queue = cmds_map[vfecmd.id].queue;
 		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
-							VFE_MSG_OUTPUT_S);
+						VFE_MSG_OUTPUT_PRIMARY);
 		if (rc < 0) {
 			pr_err("%s error configuring pingpong buffers"
 				" for preview", __func__);
@@ -1111,50 +1573,7 @@
 			goto config_done;
 		}
 		*(uint32_t *)axio = header;
-		vfe_7x_config_axi(OUTPUT_1_AND_2, &vfe2x_ctrl->snap, axio);
-		cmd_data = axio;
-	}
-		break;
-	case CMD_AXI_CFG_SNAP: {
-		raw_mode = 0;
-		CDBG("CMD_AXI_CFG_SNAP :%d\n", op_mode);
-		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
-		if (!axio) {
-			rc = -ENOMEM;
-			goto config_failure;
-		}
-
-		if (copy_from_user((char *)axio + 4,
-					(void __user *)(vfecmd.value),
-					sizeof(struct axiout))) {
-			rc = -EFAULT;
-			goto config_done;
-		}
-		header = cmds_map[vfecmd.id].vfe_id;
-		queue = cmds_map[vfecmd.id].queue;
-		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
-							VFE_MSG_OUTPUT_S);
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				" for preview", __func__);
-			rc = -EINVAL;
-			goto config_done;
-		}
-		if (header == -1 && queue == -1) {
-			rc = -EFAULT;
-			goto config_done;
-		}
-		*(uint32_t *)axio = header;
-		vfe_7x_config_axi(OUTPUT_1_AND_2, &vfe2x_ctrl->snap, axio);
-		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
-							VFE_MSG_OUTPUT_T);
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				" for preview", __func__);
-			rc = -EINVAL;
-			goto config_done;
-		}
-		vfe_7x_config_axi(OUTPUT_1, &vfe2x_ctrl->thumb, axio);
+		vfe_7x_config_axi(OUTPUT_PRIM, &vfe2x_ctrl->snap, axio);
 		cmd_data = axio;
 	}
 		break;
@@ -1169,6 +1588,7 @@
 	CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
 	if (queue == QDSP_TABLEQUEUE &&
 			vfe2x_ctrl->tableack_pending) {
+		CDBG("store table cmd\n");
 		table_pending = kzalloc(sizeof(struct table_cmd), GFP_ATOMIC);
 		if (!table_pending) {
 			rc = -ENOMEM;
@@ -1189,17 +1609,21 @@
 	} else {
 		if (queue == QDSP_TABLEQUEUE) {
 			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+			CDBG("sending table cmd\n");
+			vfe2x_ctrl->tableack_pending = 1;
 			rc = msm_adsp_write(vfe_mod, queue,
 				cmd_data, vfecmd.length + 4);
-			vfe2x_ctrl->tableack_pending = 1;
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 		} else {
 			if (*(uint32_t *)cmd_data == VFE_OUTPUT2_ACK) {
 				uint32_t *ptr = cmd_data;
 				CDBG("%x %x %x\n", ptr[0], ptr[1], ptr[2]);
 			}
+			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+			CDBG("send n-table cmd\n");
 			rc = msm_adsp_write(vfe_mod, queue,
 				cmd_data, vfecmd.length + 4);
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			CDBG("%x\n", vfecmd.length + 4);
 		}
 	}
@@ -1263,6 +1687,8 @@
 		rc = -EBUSY;
 		goto get_vfe_fail;
 	}
+	msm_adsp_enable(qcam_mod);
+	msm_adsp_enable(vfe_mod);
 	return 0;
 
 get_vfe_fail:
@@ -1287,6 +1713,7 @@
 
 void msm_vfe_subdev_release(struct platform_device *pdev)
 {
+	CDBG("msm_cam_clk_enable: disable vfe_clk\n");
 	msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
 			vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
 	vfe_syncdata = NULL;
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 0f7fb60..2f2d3c6 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -51,6 +51,10 @@
 	struct msm_free_buf free_buf;
 } __packed;
 
+struct prev_free_buf_info {
+	struct msm_free_buf buf[3];
+};
+
 struct vfe_cmd_start {
 	uint32_t input_source:1;
 	uint32_t mode_of_operation:1;
@@ -76,9 +80,15 @@
 
 struct vfe2x_ctrl_type {
 	struct buf_info prev;
+	struct buf_info video;
 	struct buf_info snap;
 	struct buf_info raw;
 	struct buf_info thumb;
+	struct prev_free_buf_info free_buf;
+	struct buf_info zsl_prim;
+	struct buf_info zsl_sec;
+	struct prev_free_buf_info zsl_free_buf[2];
+
 
 	spinlock_t  table_lock;
 	struct list_head table_q;
@@ -91,12 +101,16 @@
 	struct vfe_cmd_start start_cmd;
 	uint32_t start_pending;
 	uint32_t vfe_started;
+	uint32_t stop_pending;
+	uint32_t update_pending;
 
 	/* v4l2 subdev */
 	struct v4l2_subdev subdev;
 	struct platform_device *pdev;
 	struct clk *vfe_clk[3];
 	spinlock_t  sd_notify_lock;
+	uint32_t    reconfig_vfe;
+	uint32_t    zsl_mode;
 } __packed;
 
 struct vfe_frame_extra {
@@ -379,6 +393,21 @@
 	int state;
 	int timeout;
 };
+struct vfe_error_msg {
+	unsigned int camif_error:1;
+	unsigned int output1ybusoverflow:1;
+	unsigned int output1cbcrbusoverflow:1;
+	unsigned int output2ybusoverflow:1;
+	unsigned int output2cbcrbusoverflow:1;
+	unsigned int autofocusstatbusoverflow:1;
+	unsigned int wb_expstatbusoverflow:1;
+	unsigned int axierror:1;
+	unsigned int /* reserved */ : 24;
+	unsigned int camif_staus:1;
+	unsigned int pixel_count:14;
+	unsigned int line_count:14;
+	unsigned int /*reserved */ : 3;
+} __packed;
 
 static struct msm_free_buf *vfe2x_check_free_buffer(int id, int path);
 
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 7186e58..5919553 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -529,14 +529,14 @@
 	}
 	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
 
+	disable_irq(vpe_ctrl->vpeirq->start);
+	tasklet_kill(&vpe_tasklet);
 	msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info,
 			vpe_ctrl->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0);
 
 	regulator_disable(vpe_ctrl->fs_vpe);
 	regulator_put(vpe_ctrl->fs_vpe);
 	vpe_ctrl->fs_vpe = NULL;
-	disable_irq(vpe_ctrl->vpeirq->start);
-	tasklet_kill(&vpe_tasklet);
 	spin_lock_irqsave(&vpe_ctrl->lock, flags);
 	vpe_ctrl->state = VPE_STATE_IDLE;
 	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
diff --git a/drivers/media/video/msm/ov7692.c b/drivers/media/video/msm/ov7692.c
index 7372156..7696b44 100644
--- a/drivers/media/video/msm/ov7692.c
+++ b/drivers/media/video/msm/ov7692.c
@@ -522,6 +522,8 @@
 	case CFG_PWR_DOWN:
 		rc = ov7692_power_down();
 		break;
+	case CFG_SET_EFFECT:
+		break;
 	default:
 		rc = -EFAULT;
 		break;
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 047226e..3052832 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -3,10 +3,13 @@
 EXTRA_CFLAGS += -Idrivers/media/video/msm/io
 EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
+obj-$(CONFIG_OV5647) += ov5647_v4l2.o
 obj-$(CONFIG_IMX074) += imx074_v4l2.o
-obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
 obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
+obj-$(CONFIG_IMX091) += imx091.o
 obj-$(CONFIG_OV2720) += ov2720.o
+obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
 obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
 obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
 obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
+obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 92700f6..af9d1f4 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -175,7 +175,6 @@
 
 static struct msm_camera_csi2_params imx074_csi_params = {
 	.csid_params = {
-		.lane_assign = 0xe4,
 		.lane_cnt = 4,
 		.lut_params = {
 			.num_cid = 2,
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
new file mode 100644
index 0000000..34f0820
--- /dev/null
+++ b/drivers/media/video/msm/sensors/imx091.c
@@ -0,0 +1,344 @@
+/* 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_sensor.h"
+#define SENSOR_NAME "imx091"
+#define PLATFORM_DRIVER_NAME "msm_camera_imx091"
+#define imx091_obj imx091_##obj
+
+DEFINE_MUTEX(imx091_mut);
+static struct msm_sensor_ctrl_t imx091_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf imx091_start_settings[] = {
+	{0x0100, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf imx091_stop_settings[] = {
+	{0x0100, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf imx091_groupon_settings[] = {
+	{0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf imx091_groupoff_settings[] = {
+	{0x0104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf imx091_prev_settings[] = {
+	/* 30fps 1/2 * 1/2 */
+	/* PLL setting */
+	{0x0305, 0x02}, /* pre_pll_clk_div[7:0] */
+	{0x0307, 0x2F}, /* pll_multiplier[7:0] */
+	{0x30A4, 0x02},
+	{0x303C, 0x4B},
+	/* mode setting */
+	{0x0340, 0x06}, /* frame_length_lines[15:8] */
+	{0x0341, 0x5A}, /* frame_length_lines[7:0] */
+	{0x0342, 0x12}, /* line_length_pck[15:8] */
+	{0x0343, 0x0C}, /* line_length_pck[7:0] */
+	{0x0344, 0x00}, /* x_addr_start[15:8] */
+	{0x0345, 0x08}, /* x_addr_start[7:0] */
+	{0x0346, 0x00}, /* y_addr_start[15:8] */
+	{0x0347, 0x30}, /* y_addr_start[7:0] */
+	{0x0348, 0x10}, /* x_addr_end[15:8] */
+	{0x0349, 0x77}, /* x_addr_end[7:0] */
+	{0x034A, 0x0C}, /* y_addr_end[15:8] */
+	{0x034B, 0x5F}, /* y_addr_end[7:0] */
+	{0x034C, 0x08}, /* x_output_size[15:8] */
+	{0x034D, 0x38}, /* x_output_size[7:0] */
+	{0x034E, 0x06}, /* y_output_size[15:8] */
+	{0x034F, 0x18}, /* y_output_size[7:0] */
+	{0x0381, 0x01}, /* x_even_inc[3:0] */
+	{0x0383, 0x03}, /* x_odd_inc[3:0] */
+	{0x0385, 0x01}, /* y_even_inc[7:0] */
+	{0x0387, 0x03}, /* y_odd_inc[7:0] */
+	{0x3040, 0x08},
+	{0x3041, 0x97},
+	{0x3048, 0x01},
+	{0x3064, 0x12},
+	{0x309B, 0x28},
+	{0x309E, 0x00},
+	{0x30D5, 0x09},
+	{0x30D6, 0x01},
+	{0x30D7, 0x01},
+	{0x30D8, 0x64},
+	{0x30D9, 0x89},
+	{0x30DE, 0x02},
+	{0x3102, 0x10},
+	{0x3103, 0x44},
+	{0x3104, 0x40},
+	{0x3105, 0x00},
+	{0x3106, 0x0D},
+	{0x3107, 0x01},
+	{0x310A, 0x0A},
+	{0x315C, 0x99},
+	{0x315D, 0x98},
+	{0x316E, 0x9A},
+	{0x316F, 0x99},
+	{0x3318, 0x73},
+};
+
+static struct msm_camera_i2c_reg_conf imx091_snap_settings[] = {
+	/* full size */
+	/* PLL setting */
+	{0x0305, 0x02}, /* pre_pll_clk_div[7:0] */
+	{0x0307, 0x2B}, /* pll_multiplier[7:0] */
+	{0x30A4, 0x02},
+	{0x303C, 0x4B},
+	/* mode setting */
+	{0x0340, 0x0C}, /* frame_length_lines[15:8] */
+	{0x0341, 0x8C}, /* frame_length_lines[7:0] */
+	{0x0342, 0x12}, /* line_length_pck[15:8] */
+	{0x0343, 0x0C}, /* line_length_pck[7:0] */
+	{0x0344, 0x00}, /* x_addr_start[15:8] */
+	{0x0345, 0x08}, /* x_addr_start[7:0] */
+	{0x0346, 0x00}, /* y_addr_start[15:8] */
+	{0x0347, 0x30}, /* y_addr_start[7:0] */
+	{0x0348, 0x10}, /* x_addr_end[15:8] */
+	{0x0349, 0x77}, /* x_addr_end[7:0] */
+	{0x034A, 0x0C}, /* y_addr_end[15:8] */
+	{0x034B, 0x5F}, /* y_addr_end[7:0] */
+	{0x034C, 0x10}, /* x_output_size[15:8] */
+	{0x034D, 0x70}, /* x_output_size[7:0] */
+	{0x034E, 0x0C}, /* y_output_size[15:8] */
+	{0x034F, 0x30}, /* y_output_size[7:0] */
+	{0x0381, 0x01}, /* x_even_inc[3:0] */
+	{0x0383, 0x01}, /* x_odd_inc[3:0] */
+	{0x0385, 0x01}, /* y_even_inc[7:0] */
+	{0x0387, 0x01}, /* y_odd_inc[7:0] */
+	{0x3040, 0x08},
+	{0x3041, 0x97},
+	{0x3048, 0x00},
+	{0x3064, 0x12},
+	{0x309B, 0x20},
+	{0x309E, 0x00},
+	{0x30D5, 0x00},
+	{0x30D6, 0x85},
+	{0x30D7, 0x2A},
+	{0x30D8, 0x64},
+	{0x30D9, 0x89},
+	{0x30DE, 0x00},
+	{0x3102, 0x10},
+	{0x3103, 0x44},
+	{0x3104, 0x40},
+	{0x3105, 0x00},
+	{0x3106, 0x0D},
+	{0x3107, 0x01},
+	{0x310A, 0x0A},
+	{0x315C, 0x99},
+	{0x315D, 0x98},
+	{0x316E, 0x9A},
+	{0x316F, 0x99},
+	{0x3318, 0x64},
+};
+
+static struct msm_camera_i2c_reg_conf imx091_recommend_settings[] = {
+	/* global setting */
+	{0x3087, 0x53},
+	{0x309D, 0x94},
+	{0x30A1, 0x08},
+	{0x30C7, 0x00},
+	{0x3115, 0x0E},
+	{0x3118, 0x42},
+	{0x311D, 0x34},
+	{0x3121, 0x0D},
+	{0x3212, 0xF2},
+	{0x3213, 0x0F},
+	{0x3215, 0x0F},
+	{0x3217, 0x0B},
+	{0x3219, 0x0B},
+	{0x321B, 0x0D},
+	{0x321D, 0x0D},
+	/* black level setting */
+	{0x3032, 0x40},
+};
+
+static struct v4l2_subdev_info imx091_subdev_info[] = {
+	{
+	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array imx091_init_conf[] = {
+	{&imx091_recommend_settings[0],
+	ARRAY_SIZE(imx091_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array imx091_confs[] = {
+	{&imx091_snap_settings[0],
+	ARRAY_SIZE(imx091_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&imx091_prev_settings[0],
+	ARRAY_SIZE(imx091_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t imx091_dimensions[] = {
+	{
+	/* full size */
+		.x_output = 0x1070, /* 4208 */
+		.y_output = 0x0C30, /* 3120 */
+		.line_length_pclk = 0x120C, /* 4620 */
+		.frame_length_lines = 0x0C8C, /* 3212 */
+		.vt_pixel_clk = 206400000,
+		.op_pixel_clk = 206400000,
+		.binning_factor = 1,
+	},
+	{
+	/* 30 fps 1/2 * 1/2 */
+		.x_output = 0x0838, /* 2104 */
+		.y_output = 0x0618, /* 1560 */
+		.line_length_pclk = 0x120C, /* 4620 */
+		.frame_length_lines = 0x065A, /* 1626 */
+		.vt_pixel_clk = 225600000,
+		.op_pixel_clk = 225600000,
+		.binning_factor = 1,
+	},
+};
+
+static struct msm_camera_csid_vc_cfg imx091_cid_cfg[] = {
+	{0, CSI_RAW10, CSI_DECODE_10BIT},
+	{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
+};
+
+static struct msm_camera_csi2_params imx091_csi_params = {
+	.csid_params = {
+		.lane_cnt = 4,
+		.lut_params = {
+			.num_cid = 2,
+			.vc_cfg = imx091_cid_cfg,
+		},
+	},
+	.csiphy_params = {
+		.lane_cnt = 4,
+		.settle_cnt = 0x12,
+	},
+};
+
+static struct msm_camera_csi2_params *imx091_csi_params_array[] = {
+	&imx091_csi_params,
+	&imx091_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t imx091_reg_addr = {
+	.x_output = 0x034C,
+	.y_output = 0x034E,
+	.line_length_pclk = 0x0342,
+	.frame_length_lines = 0x0340,
+};
+
+static struct msm_sensor_id_info_t imx091_id_info = {
+	.sensor_id_reg_addr = 0x0000,
+	.sensor_id = 0x0091,
+};
+
+static struct msm_sensor_exp_gain_info_t imx091_exp_gain_info = {
+	.coarse_int_time_addr = 0x0202,
+	.global_gain_addr = 0x0204,
+	.vert_offset = 5,
+};
+
+static const struct i2c_device_id imx091_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&imx091_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver imx091_i2c_driver = {
+	.id_table = imx091_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client imx091_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+
+static int __init imx091_sensor_init_module(void)
+{
+	return i2c_add_driver(&imx091_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops imx091_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops imx091_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops imx091_subdev_ops = {
+	.core = &imx091_subdev_core_ops,
+	.video  = &imx091_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t imx091_func_tbl = {
+	.sensor_start_stream = msm_sensor_start_stream,
+	.sensor_stop_stream = msm_sensor_stop_stream,
+	.sensor_group_hold_on = msm_sensor_group_hold_on,
+	.sensor_group_hold_off = msm_sensor_group_hold_off,
+	.sensor_set_fps = msm_sensor_set_fps,
+	.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
+	.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
+	.sensor_setting = msm_sensor_setting,
+	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+	.sensor_mode_init = msm_sensor_mode_init,
+	.sensor_get_output_info = msm_sensor_get_output_info,
+	.sensor_config = msm_sensor_config,
+	.sensor_power_up = msm_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t imx091_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.start_stream_conf = imx091_start_settings,
+	.start_stream_conf_size = ARRAY_SIZE(imx091_start_settings),
+	.stop_stream_conf = imx091_stop_settings,
+	.stop_stream_conf_size = ARRAY_SIZE(imx091_stop_settings),
+	.group_hold_on_conf = imx091_groupon_settings,
+	.group_hold_on_conf_size = ARRAY_SIZE(imx091_groupon_settings),
+	.group_hold_off_conf = imx091_groupoff_settings,
+	.group_hold_off_conf_size = ARRAY_SIZE(imx091_groupoff_settings),
+	.init_settings = &imx091_init_conf[0],
+	.init_size = ARRAY_SIZE(imx091_init_conf),
+	.mode_settings = &imx091_confs[0],
+	.output_settings = &imx091_dimensions[0],
+	.num_conf = ARRAY_SIZE(imx091_confs),
+};
+
+static struct msm_sensor_ctrl_t imx091_s_ctrl = {
+	.msm_sensor_reg = &imx091_regs,
+	.sensor_i2c_client = &imx091_sensor_i2c_client,
+	.sensor_i2c_addr = 0x34,
+	.sensor_output_reg_addr = &imx091_reg_addr,
+	.sensor_id_info = &imx091_id_info,
+	.sensor_exp_gain_info = &imx091_exp_gain_info,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.csi_params = &imx091_csi_params_array[0],
+	.msm_sensor_mutex = &imx091_mut,
+	.sensor_i2c_driver = &imx091_i2c_driver,
+	.sensor_v4l2_subdev_info = imx091_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx091_subdev_info),
+	.sensor_v4l2_subdev_ops = &imx091_subdev_ops,
+	.func_tbl = &imx091_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
+
+module_init(imx091_sensor_init_module);
+MODULE_DESCRIPTION("SONY 12MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index cade3d6..d882e52 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -173,6 +173,47 @@
 	return 0;
 }
 
+int32_t msm_sensor_setting3(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res)
+{
+	int32_t rc = 0;
+	static int csi_config;
+	if (update_type == MSM_SENSOR_REG_INIT) {
+		CDBG("Register INIT\n");
+		s_ctrl->curr_csi_params = NULL;
+		csi_config = 0;
+		msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x0e, 0x08,
+			MSM_CAMERA_I2C_BYTE_DATA);
+	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+		CDBG("PERIODIC : %d\n", res);
+		if (res == 0)
+			return 0;
+		if (!csi_config) {
+			msm_sensor_write_conf_array(
+				s_ctrl->sensor_i2c_client,
+				s_ctrl->msm_sensor_reg->mode_settings, res);
+			msleep(30);
+			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
+			CDBG("CSI config in progress\n");
+			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+				NOTIFY_CSIC_CFG,
+				s_ctrl->curr_csic_params);
+			CDBG("CSI config is done\n");
+			mb();
+			msleep(30);
+			msm_camera_i2c_write(
+					s_ctrl->sensor_i2c_client,
+					0x0e, 0x00,
+					MSM_CAMERA_I2C_BYTE_DATA);
+			csi_config = 1;
+		}
+		msleep(50);
+	}
+	return rc;
+}
+
 int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res)
 {
@@ -227,6 +268,12 @@
 		msm_sensor_write_res_settings(s_ctrl, res);
 		if (s_ctrl->curr_csi_params != s_ctrl->csi_params[res]) {
 			s_ctrl->curr_csi_params = s_ctrl->csi_params[res];
+			s_ctrl->curr_csi_params->csid_params.lane_assign =
+				s_ctrl->sensordata->sensor_platform_info->
+				csi_lane_params->csi_lane_assign;
+			s_ctrl->curr_csi_params->csiphy_params.lane_mask =
+				s_ctrl->sensordata->sensor_platform_info->
+				csi_lane_params->csi_lane_mask;
 			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 				NOTIFY_CSID_CFG,
 				&s_ctrl->curr_csi_params->csid_params);
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 2b1be1e..d1a6cee 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -226,6 +226,12 @@
 int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res);
 
+int32_t msm_sensor_setting2(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res);
+
+int32_t msm_sensor_setting3(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res);
+
 int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
 
 long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
@@ -233,6 +239,10 @@
 
 struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
 
+#if (defined CONFIG_WEBCAM_OV7692_QRD || defined CONFIG_OV5647)
+	extern int lcd_camera_power_onoff(int on);
+#endif
+
 #define VIDIOC_MSM_SENSOR_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
 
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index 924cbc9..a6bc653 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -28,12 +28,6 @@
 };
 
 static struct msm_camera_i2c_reg_conf mt9e013_prev_settings[] = {
-	{0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
-	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
-	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
-	{0x0306, 0x003A},/*PLL_MULTIPLIER*/
-	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
-	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
 	/*Output Size (1632x1224)*/
 	{0x0344, 0x0008},/*X_ADDR_START*/
 	{0x0348, 0x0CC9},/*X_ADDR_END*/
@@ -56,12 +50,6 @@
 };
 
 static struct msm_camera_i2c_reg_conf mt9e013_snap_settings[] = {
-	{0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
-	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
-	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
-	{0x0306, 0x003A},/*PLL_MULTIPLIER*/
-	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
-	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
 	/*Output Size (3264x2448)*/
 	{0x0344, 0x0000},/*X_ADDR_START */
 	{0x0348, 0x0CCF},/*X_ADDR_END*/
@@ -172,14 +160,14 @@
 	{0x31B8, 0x0E3F},/*MIPI_TIMING_2*/
 	/*set data to RAW10 format*/
 	{0x0112, 0x0A0A},/*CCP_DATA_FORMAT*/
-	{0x30F0, 0x8000},/*VCM CONTROL*/
+	{0x30F0, 0x800D},/*VCM CONTROL*/
 
 	{0x3044, 0x0590},
 	{0x306E, 0xFC80},
 	{0x30B2, 0xC000},
 	{0x30D6, 0x0800},
 	{0x316C, 0xB42F},
-	{0x316E, 0x869C},
+	{0x316E, 0x869A},
 	{0x3170, 0x210E},
 	{0x317A, 0x010E},
 	{0x31E0, 0x1FB9},
@@ -188,17 +176,19 @@
 	{0x37C2, 0x0000},
 	{0x37C4, 0x0000},
 	{0x37C6, 0x0000},
+	{0x3E00, 0x0011},
 	{0x3E02, 0x8801},
-	{0x3E04, 0x2301},
+	{0x3E04, 0x2801},
 	{0x3E06, 0x8449},
 	{0x3E08, 0x6841},
 	{0x3E0A, 0x400C},
 	{0x3E0C, 0x1001},
-	{0x3E0E, 0x2103},
+	{0x3E0E, 0x2603},
 	{0x3E10, 0x4B41},
-	{0x3E12, 0x4B26},
+	{0x3E12, 0x4B24},
+	{0x3E14, 0xA3CF},
 	{0x3E16, 0x8802},
-	{0x3E18, 0x84FF},
+	{0x3E18, 0x8401},
 	{0x3E1A, 0x8601},
 	{0x3E1C, 0x8401},
 	{0x3E1E, 0x840A},
@@ -207,41 +197,56 @@
 	{0x3E24, 0x00FF},
 	{0x3E26, 0x0088},
 	{0x3E28, 0x2E8A},
+	{0x3E30, 0x0000},
 	{0x3E32, 0x8801},
-	{0x3E34, 0x4024},
+	{0x3E34, 0x4029},
+	{0x3E36, 0x00FF},
 	{0x3E38, 0x8469},
-	{0x3E3C, 0x2301},
-	{0x3E3E, 0x3E25},
+	{0x3E3A, 0x00FF},
+	{0x3E3C, 0x2801},
+	{0x3E3E, 0x3E2A},
 	{0x3E40, 0x1C01},
-	{0x3E42, 0x8486},
+	{0x3E42, 0xFF84},
 	{0x3E44, 0x8401},
-	{0x3E46, 0x00FF},
+	{0x3E46, 0x0C01},
 	{0x3E48, 0x8401},
-	{0x3E4A, 0x8601},
+	{0x3E4A, 0x00FF},
 	{0x3E4C, 0x8402},
-	{0x3E4E, 0x00FF},
-	{0x3E50, 0x6623},
+	{0x3E4E, 0x8984},
+	{0x3E50, 0x6628},
 	{0x3E52, 0x8340},
 	{0x3E54, 0x00FF},
 	{0x3E56, 0x4A42},
-	{0x3E58, 0x2203},
-	{0x3E5A, 0x674D},
-	{0x3E5C, 0x3F25},
+	{0x3E58, 0x2703},
+	{0x3E5A, 0x6752},
+	{0x3E5C, 0x3F2A},
 	{0x3E5E, 0x846A},
 	{0x3E60, 0x4C01},
 	{0x3E62, 0x8401},
 	{0x3E66, 0x3901},
+	{0x3E90, 0x2C01},
+	{0x3E98, 0x2B02},
+	{0x3E92, 0x2A04},
+	{0x3E94, 0x2509},
+	{0x3E96, 0x0000},
+	{0x3E9A, 0x2905},
+	{0x3E9C, 0x00FF},
 	{0x3ECC, 0x00EB},
 	{0x3ED0, 0x1E24},
 	{0x3ED4, 0xAFC4},
 	{0x3ED6, 0x909B},
-	{0x3ED8, 0x0006},
-	{0x3EDA, 0xCFC6},
-	{0x3EDC, 0x4FE4},
 	{0x3EE0, 0x2424},
 	{0x3EE2, 0x9797},
 	{0x3EE4, 0xC100},
-	{0x3EE6, 0x0540}
+	{0x3EE6, 0x0540},
+	{0x3174, 0x8000},
+	/* PLL settings */
+	{0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x003A},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
 };
 
 static struct v4l2_subdev_info mt9e013_subdev_info[] = {
@@ -498,6 +503,7 @@
 	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(mt9e013_subdev_info),
 	.sensor_v4l2_subdev_ops = &mt9e013_subdev_ops,
 	.func_tbl = &mt9e013_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
 };
 
 module_init(msm_sensor_init_module);
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index a1e56f7..2184806 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.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
@@ -1191,7 +1191,6 @@
 
 static struct msm_camera_csi2_params mt9m114_csi_params = {
 	.csid_params = {
-		.lane_assign = 0xe4,
 		.lane_cnt = 1,
 		.lut_params = {
 			.num_cid = 2,
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 246900e..05556eb 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -341,7 +341,6 @@
 
 static struct msm_camera_csi2_params ov2720_csi_params = {
 	.csid_params = {
-		.lane_assign = 0xe4,
 		.lane_cnt = 2,
 		.lut_params = {
 			.num_cid = 2,
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
new file mode 100644
index 0000000..ba0592e
--- /dev/null
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -0,0 +1,743 @@
+/* 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_sensor.h"
+#include "msm.h"
+#define SENSOR_NAME "ov5647"
+#define PLATFORM_DRIVER_NAME "msm_camera_ov5647"
+#define ov5647_obj ov5647_##obj
+
+static struct msm_sensor_ctrl_t ov5647_s_ctrl;
+
+DEFINE_MUTEX(ov5647_mut);
+
+
+
+static struct msm_camera_i2c_reg_conf ov5647_start_settings[] = {
+	{0x4202, 0x00},  /* streaming on */
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_stop_settings[] = {
+	{0x4202, 0x0f},  /* streaming off*/
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_groupon_settings[] = {
+	{0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_groupoff_settings[] = {
+	{0x0104, 0x0},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_prev_settings[] = {
+	/*1280*960 Reference Setting 24M MCLK 2lane 280Mbps/lane 30fps
+	for back to preview*/
+	{0x3035, 0x21},
+	{0x3036, 0x37},
+	{0x3821, 0x07},
+	{0x3820, 0x41},
+	{0x3612, 0x09},
+	{0x3618, 0x00},
+	{0x380c, 0x07},
+	{0x380d, 0x68},
+	{0x380e, 0x03},
+	{0x380f, 0xd8},
+	{0x3814, 0x31},
+	{0x3815, 0x31},
+	{0x3709, 0x52},
+	{0x3808, 0x05},
+	{0x3809, 0x00},
+	{0x380a, 0x03},
+	{0x380b, 0xc0},
+	{0x3800, 0x00},
+	{0x3801, 0x18},
+	{0x3802, 0x00},
+	{0x3803, 0x0e},
+	{0x3804, 0x0a},
+	{0x3805, 0x27},
+	{0x3806, 0x07},
+	{0x3807, 0x95},
+	{0x4004, 0x02},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_snap_settings[] = {
+	/*2608*1952 Reference Setting 24M MCLK 2lane 280Mbps/lane 30fps*/
+	{0x3035, 0x21},
+	{0x3036, 0x4f},
+	{0x3821, 0x06},
+	{0x3820, 0x00},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x380c, 0x0a},
+	{0x380d, 0x8c},
+	{0x380e, 0x07},
+	{0x380f, 0xb0},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3709, 0x12},
+	{0x3808, 0x0a},
+	{0x3809, 0x30},
+	{0x380a, 0x07},
+	{0x380b, 0xa0},
+	{0x3800, 0x00},
+	{0x3801, 0x04},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x3b},
+	{0x3806, 0x07},
+	{0x3807, 0xa3},
+	{0x4004, 0x04},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_recommend_settings[] = {
+	{0x3035, 0x11},
+	{0x303c, 0x11},
+	{0x370c, 0x03},
+	{0x5000, 0x06},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xff},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x3708, 0x64},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4000, 0x09},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3017, 0xe0},
+	{0x301c, 0xfc},
+	{0x3636, 0x06},
+	{0x3016, 0x08},
+	{0x3827, 0xec},
+	{0x3018, 0x44},
+	{0x3035, 0x21},
+	{0x3106, 0xf5},
+	{0x3034, 0x18},
+	{0x301c, 0xf8},
+	/*lens setting*/
+	{0x5000, 0x86},
+	{0x5800, 0x11},
+	{0x5801, 0x0c},
+	{0x5802, 0x0a},
+	{0x5803, 0x0b},
+	{0x5804, 0x0d},
+	{0x5805, 0x13},
+	{0x5806, 0x09},
+	{0x5807, 0x05},
+	{0x5808, 0x03},
+	{0x5809, 0x03},
+	{0x580a, 0x06},
+	{0x580b, 0x08},
+	{0x580c, 0x05},
+	{0x580d, 0x01},
+	{0x580e, 0x00},
+	{0x580f, 0x00},
+	{0x5810, 0x02},
+	{0x5811, 0x06},
+	{0x5812, 0x05},
+	{0x5813, 0x01},
+	{0x5814, 0x00},
+	{0x5815, 0x00},
+	{0x5816, 0x02},
+	{0x5817, 0x06},
+	{0x5818, 0x09},
+	{0x5819, 0x05},
+	{0x581a, 0x04},
+	{0x581b, 0x04},
+	{0x581c, 0x06},
+	{0x581d, 0x09},
+	{0x581e, 0x11},
+	{0x581f, 0x0c},
+	{0x5820, 0x0b},
+	{0x5821, 0x0b},
+	{0x5822, 0x0d},
+	{0x5823, 0x13},
+	{0x5824, 0x22},
+	{0x5825, 0x26},
+	{0x5826, 0x26},
+	{0x5827, 0x24},
+	{0x5828, 0x24},
+	{0x5829, 0x24},
+	{0x582a, 0x22},
+	{0x582b, 0x20},
+	{0x582c, 0x22},
+	{0x582d, 0x26},
+	{0x582e, 0x22},
+	{0x582f, 0x22},
+	{0x5830, 0x42},
+	{0x5831, 0x22},
+	{0x5832, 0x02},
+	{0x5833, 0x24},
+	{0x5834, 0x22},
+	{0x5835, 0x22},
+	{0x5836, 0x22},
+	{0x5837, 0x26},
+	{0x5838, 0x42},
+	{0x5839, 0x26},
+	{0x583a, 0x06},
+	{0x583b, 0x26},
+	{0x583c, 0x24},
+	{0x583d, 0xce},
+	/* manual AWB,manual AE,close Lenc,open WBC*/
+	{0x3503, 0x03}, /*manual AE*/
+	{0x3501, 0x10},
+	{0x3502, 0x80},
+	{0x350a, 0x00},
+	{0x350b, 0x7f},
+	{0x5001, 0x01}, /*manual AWB*/
+	{0x5180, 0x08},
+	{0x5186, 0x04},
+	{0x5187, 0x00},
+	{0x5188, 0x04},
+	{0x5189, 0x00},
+	{0x518a, 0x04},
+	{0x518b, 0x00},
+	{0x5000, 0x06}, /*No lenc,WBC on*/
+};
+
+
+static struct msm_camera_i2c_conf_array ov5647_init_conf[] = {
+	{&ov5647_recommend_settings[0],
+	ARRAY_SIZE(ov5647_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array ov5647_confs[] = {
+	{&ov5647_snap_settings[0],
+	ARRAY_SIZE(ov5647_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov5647_prev_settings[0],
+	ARRAY_SIZE(ov5647_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_camera_csi_params ov5647_csi_params = {
+	.data_format = CSI_8BIT,
+	.lane_cnt    = 2,
+	.lane_assign = 0xe4,
+	.dpcm_scheme = 0,
+	.settle_cnt  = 10,
+};
+
+static struct v4l2_subdev_info ov5647_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_sensor_output_info_t ov5647_dimensions[] = {
+	{ /* For SNAPSHOT */
+		.x_output = 0xA30,  /*2608*/  /*for 5Mp*/
+		.y_output = 0x7A0,   /*1952*/
+		.line_length_pclk = 0xA8C,
+		.frame_length_lines = 0x7B0,
+		.vt_pixel_clk = 79704000,
+		.op_pixel_clk = 159408000,
+		.binning_factor = 0x0,
+	},
+	{ /* For PREVIEW */
+		.x_output = 0x500, /*1280*/
+		.y_output = 0x3C0, /*960*/
+		.line_length_pclk = 0x768,
+		.frame_length_lines = 0x3D8,
+		.vt_pixel_clk = 55969920,
+		.op_pixel_clk = 159408000,
+		.binning_factor = 0x0,
+	},
+};
+
+static struct msm_sensor_output_reg_addr_t ov5647_reg_addr = {
+	.x_output = 0x3808,
+	.y_output = 0x380A,
+	.line_length_pclk = 0x380C,
+	.frame_length_lines = 0x380E,
+};
+
+static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
+	&ov5647_csi_params,
+	&ov5647_csi_params,
+};
+
+static struct msm_sensor_id_info_t ov5647_id_info = {
+	.sensor_id_reg_addr = 0x300a,
+	.sensor_id = 0x5647,
+};
+
+static struct msm_sensor_exp_gain_info_t ov5647_exp_gain_info = {
+	.coarse_int_time_addr = 0x3500,
+	.global_gain_addr = 0x350A,
+	.vert_offset = 4,
+};
+
+void ov5647_sensor_reset_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_camera_i2c_write(
+		s_ctrl->sensor_i2c_client,
+		0x103, 0x1,
+		MSM_CAMERA_I2C_BYTE_DATA);
+}
+
+static int32_t ov5647_write_pict_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+
+	uint16_t max_line;
+	uint8_t gain_lsb, gain_hsb;
+	u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
+
+	gain_lsb = (uint8_t) (gain);
+	gain_hsb = (uint8_t)((gain & 0x300)>>8);
+
+	CDBG(KERN_ERR "snapshot exposure seting 0x%x, 0x%x, %d"
+		, gain, line, line);
+
+	if (line > 1964) {
+		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines,
+			(uint8_t)((line+4) >> 8),
+			MSM_CAMERA_I2C_BYTE_DATA);
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
+			(uint8_t)((line+4) & 0x00FF),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+
+		max_line = line + 4;
+	} else if (line > 1968) {
+		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines,
+			(uint8_t)((line+4) >> 8),
+			MSM_CAMERA_I2C_BYTE_DATA);
+
+		 msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
+			(uint8_t)((line+4) & 0x00FF),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+			max_line = 1968;
+	}
+
+
+	line = line<<4;
+	/* ov5647 need this operation */
+	intg_time_hsb = (u8)(line>>16);
+	intg_time_msb = (u8) ((line & 0xFF00) >> 8);
+	intg_time_lsb = (u8) (line & 0x00FF);
+
+	/* FIXME for BLC trigger */
+	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+
+	/* Coarse Integration Time */
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		intg_time_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+		intg_time_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 2,
+		intg_time_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* gain */
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		gain_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		gain_lsb-1,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* Coarse Integration Time */
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		intg_time_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+		intg_time_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 2,
+		intg_time_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* gain */
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		gain_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		gain_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+
+	s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+	return 0;
+
+}
+
+
+static int32_t ov5647_write_prev_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+						uint16_t gain, uint32_t line)
+{
+
+	uint16_t max_line;
+	u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
+	uint8_t gain_lsb, gain_hsb;
+
+	pr_info(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
+		 gain, line, line);
+
+	gain_lsb = (uint8_t) (gain);
+	gain_hsb = (uint8_t)((gain & 0x300)>>8);
+	/* adjust frame rate */
+	if (line > 980) {
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines,
+		(uint8_t)((line+4) >> 8),
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
+		(uint8_t)((line+4) & 0x00FF),
+		MSM_CAMERA_I2C_BYTE_DATA);
+		max_line = line + 4;
+	} else if (line > 984) {
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines,
+		(uint8_t)(984 >> 8),
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines + 1 ,
+		(uint8_t)(984 & 0x00FF),
+		MSM_CAMERA_I2C_BYTE_DATA);
+		max_line = 984;
+	}
+
+	line = line<<4;
+	/* ov5647 need this operation */
+	intg_time_hsb = (u8)(line>>16);
+	intg_time_msb = (u8) ((line & 0xFF00) >> 8);
+	intg_time_lsb = (u8) (line & 0x00FF);
+
+	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+
+	/* Coarse Integration Time */
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		intg_time_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+		intg_time_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 2,
+		intg_time_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* gain */
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		gain_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		gain_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+
+	return 0;
+}
+
+static const struct i2c_device_id ov5647_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&ov5647_s_ctrl},
+	{ }
+};
+int32_t ov5647_sensor_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int32_t rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl;
+
+	rc = msm_sensor_i2c_probe(client, id);
+
+	if (client->dev.platform_data == NULL) {
+		pr_err("%s: NULL sensor data\n", __func__);
+		return -EFAULT;
+	}
+
+	s_ctrl = client->dev.platform_data;
+	if (s_ctrl->sensordata->pmic_gpio_enable)
+		lcd_camera_power_onoff(0);
+
+	return rc;
+}
+
+static struct i2c_driver ov5647_i2c_driver = {
+	.id_table = ov5647_i2c_id,
+	.probe  = ov5647_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+
+
+static struct msm_camera_i2c_client ov5647_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	return i2c_add_driver(&ov5647_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov5647_subdev_ops = {
+	.core = &ov5647_subdev_core_ops,
+	.video  = &ov5647_subdev_video_ops,
+};
+
+int32_t ov5647_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	struct msm_camera_sensor_info *info = NULL;
+	unsigned short rdata;
+	int rc;
+
+	info = s_ctrl->sensordata;
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x4202, 0xf,
+		MSM_CAMERA_I2C_BYTE_DATA);
+	msleep(20);
+	rc = msm_camera_i2c_read(s_ctrl->sensor_i2c_client, 0x3018,
+			&rdata, MSM_CAMERA_I2C_WORD_DATA);
+	CDBG("ov5647_sensor_power_down: %d\n", rc);
+	rdata |= 0x18;
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x3018, rdata,
+		MSM_CAMERA_I2C_WORD_DATA);
+	msleep(20);
+	gpio_direction_output(info->sensor_pwd, 1);
+	usleep_range(5000, 5100);
+	msm_sensor_power_down(s_ctrl);
+	return 0;
+}
+
+int32_t ov5647_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct msm_camera_sensor_info *info = NULL;
+
+	info = s_ctrl->sensordata;
+	gpio_direction_output(info->sensor_pwd, 1);
+	gpio_direction_output(info->sensor_reset, 0);
+	usleep_range(10000, 11000);
+	if (info->pmic_gpio_enable) {
+		info->pmic_gpio_enable = 0;
+		lcd_camera_power_onoff(1);
+	}
+	usleep_range(10000, 11000);
+	rc = msm_sensor_power_up(s_ctrl);
+	if (rc < 0) {
+		CDBG("%s: msm_sensor_power_up failed\n", __func__);
+		return rc;
+	}
+
+	/* turn on ldo and vreg */
+
+	gpio_direction_output(info->sensor_pwd, 0);
+	msleep(20);
+	gpio_direction_output(info->sensor_reset, 1);
+	msleep(25);
+
+	return rc;
+
+}
+
+int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res)
+{
+	int32_t rc = 0;
+	static int csi_config;
+
+	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+	if (csi_config == 0 || res == 0)
+		msleep(66);
+	else
+		msleep(266);
+	msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x4800, 0x25,
+			MSM_CAMERA_I2C_BYTE_DATA);
+	if (update_type == MSM_SENSOR_REG_INIT) {
+		CDBG("Register INIT\n");
+		s_ctrl->curr_csi_params = NULL;
+		msm_camera_i2c_write(
+				s_ctrl->sensor_i2c_client,
+				0x103, 0x1,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		msm_sensor_enable_debugfs(s_ctrl);
+		msm_sensor_write_init_settings(s_ctrl);
+		csi_config = 0;
+	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+		CDBG("PERIODIC : %d\n", res);
+		msm_sensor_write_conf_array(
+			s_ctrl->sensor_i2c_client,
+			s_ctrl->msm_sensor_reg->mode_settings, res);
+		msleep(30);
+		if (!csi_config) {
+			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
+			CDBG("CSI config in progress\n");
+			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+				NOTIFY_CSIC_CFG,
+				s_ctrl->curr_csic_params);
+			CDBG("CSI config is done\n");
+			mb();
+			msleep(30);
+			csi_config = 1;
+		msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x100, 0x1,
+			MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x4800, 0x4,
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msleep(266);
+		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+		msleep(50);
+	}
+	return rc;
+}
+static struct msm_sensor_fn_t ov5647_func_tbl = {
+	.sensor_start_stream = msm_sensor_start_stream,
+	.sensor_stop_stream = msm_sensor_stop_stream,
+	.sensor_group_hold_on = msm_sensor_group_hold_on,
+	.sensor_group_hold_off = msm_sensor_group_hold_off,
+	.sensor_set_fps = msm_sensor_set_fps,
+	.sensor_write_exp_gain = ov5647_write_prev_exp_gain,
+	.sensor_write_snapshot_exp_gain = ov5647_write_pict_exp_gain,
+	.sensor_setting = ov5647_sensor_setting,
+	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+	.sensor_mode_init = msm_sensor_mode_init,
+	.sensor_get_output_info = msm_sensor_get_output_info,
+	.sensor_config = msm_sensor_config,
+	.sensor_power_up = ov5647_sensor_power_up,
+	.sensor_power_down = ov5647_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t ov5647_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.start_stream_conf = ov5647_start_settings,
+	.start_stream_conf_size = ARRAY_SIZE(ov5647_start_settings),
+	.stop_stream_conf = ov5647_stop_settings,
+	.stop_stream_conf_size = ARRAY_SIZE(ov5647_stop_settings),
+	.group_hold_on_conf = ov5647_groupon_settings,
+	.group_hold_on_conf_size = ARRAY_SIZE(ov5647_groupon_settings),
+	.group_hold_off_conf = ov5647_groupoff_settings,
+	.group_hold_off_conf_size =
+		ARRAY_SIZE(ov5647_groupoff_settings),
+	.init_settings = &ov5647_init_conf[0],
+	.init_size = ARRAY_SIZE(ov5647_init_conf),
+	.mode_settings = &ov5647_confs[0],
+	.output_settings = &ov5647_dimensions[0],
+	.num_conf = ARRAY_SIZE(ov5647_confs),
+};
+
+static struct msm_sensor_ctrl_t ov5647_s_ctrl = {
+	.msm_sensor_reg = &ov5647_regs,
+	.sensor_i2c_client = &ov5647_sensor_i2c_client,
+	.sensor_i2c_addr =  0x36 << 1 ,
+	.sensor_output_reg_addr = &ov5647_reg_addr,
+	.sensor_id_info = &ov5647_id_info,
+	.sensor_exp_gain_info = &ov5647_exp_gain_info,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.csic_params = &ov5647_csi_params_array[0],
+	.msm_sensor_mutex = &ov5647_mut,
+	.sensor_i2c_driver = &ov5647_i2c_driver,
+	.sensor_v4l2_subdev_info = ov5647_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov5647_subdev_info),
+	.sensor_v4l2_subdev_ops = &ov5647_subdev_ops,
+	.func_tbl = &ov5647_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omnivision WXGA Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
new file mode 100644
index 0000000..99e96f0
--- /dev/null
+++ b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
@@ -0,0 +1,735 @@
+/* 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_sensor.h"
+#define SENSOR_NAME "ov7692"
+#define PLATFORM_DRIVER_NAME "msm_camera_ov7692"
+#define ov7692_obj ov7692_##obj
+#define MSB                             1
+#define LSB                             0
+
+DEFINE_MUTEX(ov7692_mut);
+static struct msm_sensor_ctrl_t ov7692_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf ov7692_prev_settings[] = {
+	{0x12, 0x80},
+	{0x0e, 0x08},
+	{0x69, 0x52},
+	{0x1e, 0xb3},
+	{0x48, 0x42},
+	{0xff, 0x01},
+	{0xae, 0xa0},
+	{0xa8, 0x26},
+	{0xb4, 0xc0},
+	{0xb5, 0x40},
+	{0xff, 0x00},
+	{0x0c, 0x00},
+	{0x62, 0x10},
+	{0x12, 0x00},
+	{0x17, 0x65},
+	{0x18, 0xa4},
+	{0x19, 0x0a},
+	{0x1a, 0xf6},
+	{0x3e, 0x30},
+	{0x64, 0x0a},
+	{0xff, 0x01},
+	{0xb4, 0xc0},
+	{0xff, 0x00},
+	{0x67, 0x20},
+	{0x81, 0x3f},
+	{0xcc, 0x02},
+	{0xcd, 0x80},
+	{0xce, 0x01},
+	{0xcf, 0xe0},
+	{0xc8, 0x02},
+	{0xc9, 0x80},
+	{0xca, 0x01},
+	{0xcb, 0xe0},
+	{0xd0, 0x48},
+	{0x82, 0x03},
+	{0x70, 0x00},
+	{0x71, 0x34},
+	{0x74, 0x28},
+	{0x75, 0x98},
+	{0x76, 0x00},
+	{0x77, 0x64},
+	{0x78, 0x01},
+	{0x79, 0xc2},
+	{0x7a, 0x4e},
+	{0x7b, 0x1f},
+	{0x7c, 0x00},
+	{0x11, 0x00},
+	{0x20, 0x00},
+	{0x21, 0x23},
+	{0x50, 0x9a},
+	{0x51, 0x80},
+	{0x4c, 0x7d},
+	{0x85, 0x10},
+	{0x86, 0x00},
+	{0x87, 0x00},
+	{0x88, 0x00},
+	{0x89, 0x2a},
+	{0x8a, 0x26},
+	{0x8b, 0x22},
+	{0xbb, 0x7a},
+	{0xbc, 0x69},
+	{0xbd, 0x11},
+	{0xbe, 0x13},
+	{0xbf, 0x81},
+	{0xc0, 0x96},
+	{0xc1, 0x1e},
+	{0xb7, 0x05},
+	{0xb8, 0x09},
+	{0xb9, 0x00},
+	{0xba, 0x18},
+	{0x5a, 0x1f},
+	{0x5b, 0x9f},
+	{0x5c, 0x6a},
+	{0x5d, 0x42},
+	{0x24, 0x78},
+	{0x25, 0x68},
+	{0x26, 0xb3},
+	{0xa3, 0x0b},
+	{0xa4, 0x15},
+	{0xa5, 0x2a},
+	{0xa6, 0x51},
+	{0xa7, 0x63},
+	{0xa8, 0x74},
+	{0xa9, 0x83},
+	{0xaa, 0x91},
+	{0xab, 0x9e},
+	{0xac, 0xaa},
+	{0xad, 0xbe},
+	{0xae, 0xce},
+	{0xaf, 0xe5},
+	{0xb0, 0xf3},
+	{0xb1, 0xfb},
+	{0xb2, 0x06},
+	{0x8c, 0x5c},
+	{0x8d, 0x11},
+	{0x8e, 0x12},
+	{0x8f, 0x19},
+	{0x90, 0x50},
+	{0x91, 0x20},
+	{0x92, 0x96},
+	{0x93, 0x80},
+	{0x94, 0x13},
+	{0x95, 0x1b},
+	{0x96, 0xff},
+	{0x97, 0x00},
+	{0x98, 0x3d},
+	{0x99, 0x36},
+	{0x9a, 0x51},
+	{0x9b, 0x43},
+	{0x9c, 0xf0},
+	{0x9d, 0xf0},
+	{0x9e, 0xf0},
+	{0x9f, 0xff},
+	{0xa0, 0x68},
+	{0xa1, 0x62},
+	{0xa2, 0x0e},
+
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_snap_settings[] = {
+	{0x12, 0x80},
+	{0x0e, 0x08},
+	{0x69, 0x52},
+	{0x1e, 0xb3},
+	{0x48, 0x42},
+	{0xff, 0x01},
+	{0xae, 0xa0},
+	{0xa8, 0x26},
+	{0xb4, 0xc0},
+	{0xb5, 0x40},
+	{0xff, 0x00},
+	{0x0c, 0x00},
+	{0x62, 0x10},
+	{0x12, 0x00},
+	{0x17, 0x65},
+	{0x18, 0xa4},
+	{0x19, 0x0a},
+	{0x1a, 0xf6},
+	{0x3e, 0x30},
+	{0x64, 0x0a},
+	{0xff, 0x01},
+	{0xb4, 0xc0},
+	{0xff, 0x00},
+	{0x67, 0x20},
+	{0x81, 0x3f},
+	{0xcc, 0x02},
+	{0xcd, 0x80},
+	{0xce, 0x01},
+	{0xcf, 0xe0},
+	{0xc8, 0x02},
+	{0xc9, 0x80},
+	{0xca, 0x01},
+	{0xcb, 0xe0},
+	{0xd0, 0x48},
+	{0x82, 0x03},
+	{0x70, 0x00},
+	{0x71, 0x34},
+	{0x74, 0x28},
+	{0x75, 0x98},
+	{0x76, 0x00},
+	{0x77, 0x64},
+	{0x78, 0x01},
+	{0x79, 0xc2},
+	{0x7a, 0x4e},
+	{0x7b, 0x1f},
+	{0x7c, 0x00},
+	{0x11, 0x00},
+	{0x20, 0x00},
+	{0x21, 0x23},
+	{0x50, 0x9a},
+	{0x51, 0x80},
+	{0x4c, 0x7d},
+	{0x85, 0x10},
+	{0x86, 0x00},
+	{0x87, 0x00},
+	{0x88, 0x00},
+	{0x89, 0x2a},
+	{0x8a, 0x26},
+	{0x8b, 0x22},
+	{0xbb, 0x7a},
+	{0xbc, 0x69},
+	{0xbd, 0x11},
+	{0xbe, 0x13},
+	{0xbf, 0x81},
+	{0xc0, 0x96},
+	{0xc1, 0x1e},
+	{0xb7, 0x05},
+	{0xb8, 0x09},
+	{0xb9, 0x00},
+	{0xba, 0x18},
+	{0x5a, 0x1f},
+	{0x5b, 0x9f},
+	{0x5c, 0x6a},
+	{0x5d, 0x42},
+	{0x24, 0x78},
+	{0x25, 0x68},
+	{0x26, 0xb3},
+	{0xa3, 0x0b},
+	{0xa4, 0x15},
+	{0xa5, 0x2a},
+	{0xa6, 0x51},
+	{0xa7, 0x63},
+	{0xa8, 0x74},
+	{0xa9, 0x83},
+	{0xaa, 0x91},
+	{0xab, 0x9e},
+	{0xac, 0xaa},
+	{0xad, 0xbe},
+	{0xae, 0xce},
+	{0xaf, 0xe5},
+	{0xb0, 0xf3},
+	{0xb1, 0xfb},
+	{0xb2, 0x06},
+	{0x8c, 0x5c},
+	{0x8d, 0x11},
+	{0x8e, 0x12},
+	{0x8f, 0x19},
+	{0x90, 0x50},
+	{0x91, 0x20},
+	{0x92, 0x96},
+	{0x93, 0x80},
+	{0x94, 0x13},
+	{0x95, 0x1b},
+	{0x96, 0xff},
+	{0x97, 0x00},
+	{0x98, 0x3d},
+	{0x99, 0x36},
+	{0x9a, 0x51},
+	{0x9b, 0x43},
+	{0x9c, 0xf0},
+	{0x9d, 0xf0},
+	{0x9e, 0xf0},
+	{0x9f, 0xff},
+	{0xa0, 0x68},
+	{0xa1, 0x62},
+	{0xa2, 0x0e},
+
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_recommend_settings[] = {
+	{0x12, 0x80},
+	{0x0e, 0x08},
+	{0x69, 0x52},
+	{0x1e, 0xb3},
+	{0x48, 0x42},
+	{0xff, 0x01},
+	{0xae, 0xa0},
+	{0xa8, 0x26},
+	{0xb4, 0xc0},
+	{0xb5, 0x40},
+	{0xff, 0x00},
+	{0x0c, 0x00},
+	{0x62, 0x10},
+	{0x12, 0x00},
+	{0x17, 0x65},
+	{0x18, 0xa4},
+	{0x19, 0x0a},
+	{0x1a, 0xf6},
+	{0x3e, 0x30},
+	{0x64, 0x0a},
+	{0xff, 0x01},
+	{0xb4, 0xc0},
+	{0xff, 0x00},
+	{0x67, 0x20},
+	{0x81, 0x3f},
+	{0xcc, 0x02},
+	{0xcd, 0x80},
+	{0xce, 0x01},
+	{0xcf, 0xe0},
+	{0xc8, 0x02},
+	{0xc9, 0x80},
+	{0xca, 0x01},
+	{0xcb, 0xe0},
+	{0xd0, 0x48},
+	{0x82, 0x03},
+	{0x70, 0x00},
+	{0x71, 0x34},
+	{0x74, 0x28},
+	{0x75, 0x98},
+	{0x76, 0x00},
+	{0x77, 0x64},
+	{0x78, 0x01},
+	{0x79, 0xc2},
+	{0x7a, 0x4e},
+	{0x7b, 0x1f},
+	{0x7c, 0x00},
+	{0x11, 0x00},
+	{0x20, 0x00},
+	{0x21, 0x23},
+	{0x50, 0x9a},
+	{0x51, 0x80},
+	{0x4c, 0x7d},
+	{0x85, 0x10},
+	{0x86, 0x00},
+	{0x87, 0x00},
+	{0x88, 0x00},
+	{0x89, 0x2a},
+	{0x8a, 0x26},
+	{0x8b, 0x22},
+	{0xbb, 0x7a},
+	{0xbc, 0x69},
+	{0xbd, 0x11},
+	{0xbe, 0x13},
+	{0xbf, 0x81},
+	{0xc0, 0x96},
+	{0xc1, 0x1e},
+	{0xb7, 0x05},
+	{0xb8, 0x09},
+	{0xb9, 0x00},
+	{0xba, 0x18},
+	{0x5a, 0x1f},
+	{0x5b, 0x9f},
+	{0x5c, 0x6a},
+	{0x5d, 0x42},
+	{0x24, 0x78},
+	{0x25, 0x68},
+	{0x26, 0xb3},
+	{0xa3, 0x0b},
+	{0xa4, 0x15},
+	{0xa5, 0x2a},
+	{0xa6, 0x51},
+	{0xa7, 0x63},
+	{0xa8, 0x74},
+	{0xa9, 0x83},
+	{0xaa, 0x91},
+	{0xab, 0x9e},
+	{0xac, 0xaa},
+	{0xad, 0xbe},
+	{0xae, 0xce},
+	{0xaf, 0xe5},
+	{0xb0, 0xf3},
+	{0xb1, 0xfb},
+	{0xb2, 0x06},
+	{0x8c, 0x5c},
+	{0x8d, 0x11},
+	{0x8e, 0x12},
+	{0x8f, 0x19},
+	{0x90, 0x50},
+	{0x91, 0x20},
+	{0x92, 0x96},
+	{0x93, 0x80},
+	{0x94, 0x13},
+	{0x95, 0x1b},
+	{0x96, 0xff},
+	{0x97, 0x00},
+	{0x98, 0x3d},
+	{0x99, 0x36},
+	{0x9a, 0x51},
+	{0x9b, 0x43},
+	{0x9c, 0xf0},
+	{0x9d, 0xf0},
+	{0x9e, 0xf0},
+	{0x9f, 0xff},
+	{0xa0, 0x68},
+	{0xa1, 0x62},
+	{0xa2, 0x0e},
+
+};
+
+static struct v4l2_subdev_info ov7692_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+
+static struct msm_camera_i2c_conf_array ov7692_init_conf[] = {
+	{&ov7692_recommend_settings[0],
+	ARRAY_SIZE(ov7692_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array ov7692_confs[] = {
+	{&ov7692_snap_settings[0],
+	ARRAY_SIZE(ov7692_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov7692_prev_settings[0],
+	ARRAY_SIZE(ov7692_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t ov7692_dimensions[] = {
+	{
+		.x_output = 0x280,
+		.y_output = 0x1E0,
+		.line_length_pclk = 0x290,
+		.frame_length_lines = 0x1EC,
+		.vt_pixel_clk = 9216000,
+		.op_pixel_clk = 9216000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x280,
+		.y_output = 0x1E0,
+		.line_length_pclk = 0x290,
+		.frame_length_lines = 0x1EC,
+		.vt_pixel_clk = 9216000,
+		.op_pixel_clk = 9216000,
+		.binning_factor = 1,
+	},
+};
+
+
+static struct msm_camera_csi_params ov7692_csi_params = {
+	.data_format = CSI_8BIT,
+	.lane_cnt    = 1,
+	.lane_assign = 0xe4,
+	.dpcm_scheme = 0,
+	.settle_cnt  = 0x14,
+};
+
+static struct msm_camera_csi_params *ov7692_csi_params_array[] = {
+	&ov7692_csi_params,
+	&ov7692_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t ov7692_reg_addr = {
+	.x_output = 0xCC,
+	.y_output = 0xCE,
+	.line_length_pclk = 0xC8,
+	.frame_length_lines = 0xCA,
+};
+
+static struct msm_sensor_id_info_t ov7692_id_info = {
+	.sensor_id_reg_addr = 0x0A,
+	.sensor_id = 0x7692,
+};
+
+static struct msm_sensor_exp_gain_info_t ov7692_exp_gain_info = {
+	.coarse_int_time_addr = 0x0202,
+	.global_gain_addr = 0x0204,
+	.vert_offset = 4,
+};
+
+static inline uint8_t ov7692_byte(uint16_t word, uint8_t offset)
+{
+	return word >> (offset * BITS_PER_BYTE);
+}
+
+
+static const struct i2c_device_id ov7692_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&ov7692_s_ctrl},
+	{ }
+};
+static int ov7692_pwdn_gpio;
+static int ov7692_reset_gpio;
+
+static int ov7692_probe_init_gpio(const struct msm_camera_sensor_info *data)
+{
+	int rc = 0;
+	CDBG("%s: entered\n", __func__);
+
+	ov7692_pwdn_gpio = data->sensor_pwd;
+	ov7692_reset_gpio = data->sensor_reset ;
+
+	CDBG("%s: pwdn_gpio:%d, reset_gpio:%d\n", __func__,
+			ov7692_pwdn_gpio, ov7692_reset_gpio);
+
+	if (data->sensor_reset_enable)
+		gpio_direction_output(data->sensor_reset, 1);
+
+	gpio_direction_output(data->sensor_pwd, 1);
+
+	return rc;
+
+}
+static void ov7692_power_on(void)
+{
+	CDBG("%s\n", __func__);
+	gpio_set_value(ov7692_pwdn_gpio, 0);
+}
+
+static void ov7692_power_down(void)
+{
+	CDBG("%s\n", __func__);
+	gpio_set_value(ov7692_pwdn_gpio, 1);
+}
+
+int32_t ov7692_sensor_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int32_t rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl;
+	rc = msm_sensor_i2c_probe(client, id);
+
+	ov7692_power_down();
+
+	if (client->dev.platform_data == NULL) {
+		pr_err("%s: NULL sensor data\n", __func__);
+		return -EFAULT;
+	}
+
+	s_ctrl = client->dev.platform_data;
+	if (s_ctrl->sensordata->pmic_gpio_enable)
+		lcd_camera_power_onoff(0);
+
+	return rc;
+
+}
+
+static struct i2c_driver ov7692_i2c_driver = {
+	.id_table = ov7692_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov7692_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	int rc = 0;
+	CDBG("OV7692\n");
+
+	rc = i2c_add_driver(&ov7692_i2c_driver);
+
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops ov7692_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops ov7692_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov7692_subdev_ops = {
+	.core = &ov7692_subdev_core_ops,
+	.video  = &ov7692_subdev_video_ops,
+};
+
+static int32_t ov7692_i2c_txdata(struct i2c_client *ov7692_client,
+		unsigned short saddr,
+		unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = 2,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(ov7692_client->adapter, msg, 1) < 0) {
+		CDBG("ov7692_i2c_txdata faild 0x%x\n", ov7692_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+static int32_t ov7692_i2c_write_b_sensor(struct i2c_client *ov7692_client,
+		uint8_t waddr,
+		uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = ov7692_i2c_txdata(ov7692_client, ov7692_client->addr >> 1, buf, 2);
+	if (rc < 0)
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+		waddr, bdata);
+
+	return rc;
+}
+
+static int32_t ov7692_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+	CDBG("ov7692_write_exp_gain : Not supported\n");
+	return 0;
+}
+
+int32_t ov7692_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
+		struct fps_cfg *fps)
+{
+	CDBG("ov7692_sensor_set_fps: Not supported\n");
+	return 0;
+}
+
+
+
+static void ov7692_sw_reset(struct msm_sensor_ctrl_t *s_ctrl)
+{
+
+	CDBG("%s\n", __func__);
+	ov7692_i2c_write_b_sensor(s_ctrl->sensor_i2c_client->client,
+			0x12, 0x80);
+}
+
+static void ov7692_hw_reset(void)
+{
+	CDBG("--CAMERA-- %s ... (Start...)\n", __func__);
+	gpio_set_value(ov7692_reset_gpio, 1);   /*reset camera reset pin*/
+	usleep_range(5000, 5100);
+	gpio_set_value(ov7692_reset_gpio, 0);
+	usleep_range(5000, 5100);
+	gpio_set_value(ov7692_reset_gpio, 1);
+	usleep_range(1000, 1100);
+	CDBG("--CAMERA-- %s ... (End...)\n", __func__);
+}
+
+
+
+int32_t ov7692_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct msm_camera_sensor_info *info = NULL;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+
+	rc = msm_sensor_power_up(s_ctrl);
+	if (rc < 0) {
+		CDBG("%s: msm_sensor_power_up failed\n", __func__);
+		return rc;
+	}
+	info = s_ctrl->sensordata;
+
+	rc = ov7692_probe_init_gpio(info);
+	if (rc < 0) {
+		CDBG("%s: gpio init failed\n", __func__);
+		goto power_up_fail;
+	}
+	/* turn on LDO for PVT */
+	if (info->pmic_gpio_enable)
+		lcd_camera_power_onoff(1);
+
+	ov7692_power_down();
+
+	usleep_range(5000, 5100);
+
+	ov7692_power_on();
+	usleep_range(5000, 5100);
+
+	if (info->sensor_reset_enable)
+		ov7692_hw_reset();
+	else
+		ov7692_sw_reset(s_ctrl);
+
+	return rc;
+
+power_up_fail:
+	CDBG("ov7692_sensor_power_up: OV7692 SENSOR POWER UP FAILS!\n");
+	if (info->pmic_gpio_enable)
+		lcd_camera_power_onoff(0);
+	return rc;
+
+
+}
+
+
+static struct msm_sensor_fn_t ov7692_func_tbl = {
+	.sensor_start_stream = msm_sensor_start_stream,
+	.sensor_stop_stream = msm_sensor_stop_stream,
+	.sensor_group_hold_on = msm_sensor_group_hold_on,
+	.sensor_group_hold_off = msm_sensor_group_hold_off,
+	.sensor_set_fps = ov7692_sensor_set_fps,
+	.sensor_setting = msm_sensor_setting3,
+	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+	.sensor_mode_init = msm_sensor_mode_init,
+	.sensor_get_output_info = msm_sensor_get_output_info,
+	.sensor_config = msm_sensor_config,
+	.sensor_power_up = ov7692_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+	.sensor_write_exp_gain = ov7692_write_exp_gain,
+	.sensor_write_snapshot_exp_gain = ov7692_write_exp_gain,
+};
+
+static struct msm_sensor_reg_t ov7692_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.start_stream_conf_size = 0,
+	.stop_stream_conf_size = 0,
+	.group_hold_on_conf_size = 0,
+	.group_hold_off_conf_size = 0,
+	.init_settings = &ov7692_init_conf[0],
+	.init_size = ARRAY_SIZE(ov7692_init_conf),
+	.mode_settings = &ov7692_confs[0],
+	.output_settings = &ov7692_dimensions[0],
+	.num_conf = ARRAY_SIZE(ov7692_confs),
+};
+
+static struct msm_sensor_ctrl_t ov7692_s_ctrl = {
+	.msm_sensor_reg = &ov7692_regs,
+	.sensor_i2c_client = &ov7692_sensor_i2c_client,
+	.sensor_i2c_addr = 0x78,
+	.sensor_output_reg_addr = &ov7692_reg_addr,
+	.sensor_id_info = &ov7692_id_info,
+	.sensor_exp_gain_info = &ov7692_exp_gain_info,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.csic_params = &ov7692_csi_params_array[0],
+	.msm_sensor_mutex = &ov7692_mut,
+	.sensor_i2c_driver = &ov7692_i2c_driver,
+	.sensor_v4l2_subdev_info = ov7692_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov7692_subdev_info),
+	.sensor_v4l2_subdev_ops = &ov7692_subdev_ops,
+	.func_tbl = &ov7692_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omni VGA YUV sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
index e345717..17291ff 100644
--- a/drivers/media/video/msm/sensors/ov9726_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -271,6 +271,7 @@
 	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov9726_subdev_info),
 	.sensor_v4l2_subdev_ops = &ov9726_subdev_ops,
 	.func_tbl = &ov9726_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
 };
 
 module_init(msm_sensor_init_module);
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 954dd2f..4a790f8 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -123,7 +123,7 @@
 	{0x0344, 0x01}, /* x_addr_start */
 	{0x0345, 0x20}, /* x_addr_start */
 	{0x0346, 0x02}, /* y_addr_start */
-	{0x0347, 0x23}, /* y_addr_start */
+	{0x0347, 0x24}, /* y_addr_start */
 	{0x0348, 0x0E}, /* x_addr_end */
 	{0x0349, 0xA0}, /* x_addr_end */
 	{0x034A, 0x09}, /* y_addr_end */
@@ -160,7 +160,7 @@
 	{0x0344, 0x01}, /* x_addr_start */
 	{0x0345, 0x20}, /* x_addr_start */
 	{0x0346, 0x02}, /* y_addr_start */
-	{0x0347, 0x23}, /* y_addr_start */
+	{0x0347, 0x24}, /* y_addr_start */
 	{0x0348, 0x0E}, /* x_addr_end */
 	{0x0349, 0xA0}, /* x_addr_end */
 	{0x034A, 0x09}, /* y_addr_end */
@@ -197,7 +197,7 @@
 	{0x0344, 0x01}, /* x_addr_start */
 	{0x0345, 0x20}, /* x_addr_start */
 	{0x0346, 0x02}, /* y_addr_start */
-	{0x0347, 0x23}, /* y_addr_start */
+	{0x0347, 0x24}, /* y_addr_start */
 	{0x0348, 0x0E}, /* x_addr_end */
 	{0x0349, 0xA0}, /* x_addr_end */
 	{0x034A, 0x09}, /* y_addr_end */
@@ -542,7 +542,6 @@
 
 static struct msm_camera_csi2_params s5k3l1yx_csi_params = {
 	.csid_params = {
-		.lane_assign = 0xe4,
 		.lane_cnt = 4,
 		.lut_params = {
 			.num_cid = ARRAY_SIZE(s5k3l1yx_cid_cfg),
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index 1f99119..699f0dd 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -196,8 +196,8 @@
 		.y_output = 0x7A8,
 		.line_length_pclk = 0xAB2,
 		.frame_length_lines = 0x7B4,
-		.vt_pixel_clk = 816000000,
-		.op_pixel_clk = 816000000,
+		.vt_pixel_clk = 81600000,
+		.op_pixel_clk = 81600000,
 		.binning_factor = 0,
 	},
 	{
@@ -205,8 +205,8 @@
 		.y_output = 0x3D4,
 		.line_length_pclk = 0xAB2,
 		.frame_length_lines = 0x3E0,
-		.vt_pixel_clk = 816000000,
-		.op_pixel_clk = 816000000,
+		.vt_pixel_clk = 81600000,
+		.op_pixel_clk = 81600000,
 		.binning_factor = 1,
 	},
 };
@@ -349,8 +349,6 @@
 		gain = max_legal_gain;
 	}
 
-	gain = 32;
-	line = 1465;
 	pr_info("s5k4e1_write_exp_gain : gain = %d line = %d\n", gain, line);
 	line = (uint32_t) (line * s_ctrl->fps_divider);
 	fl_lines = s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider / Q10;
@@ -494,6 +492,7 @@
 	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k4e1_subdev_info),
 	.sensor_v4l2_subdev_ops = &s5k4e1_subdev_ops,
 	.func_tbl = &s5k4e1_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
 };
 
 module_init(msm_sensor_init_module);
diff --git a/drivers/media/video/msm/wfd/Makefile b/drivers/media/video/msm/wfd/Makefile
index 2b39e66..5decaca 100644
--- a/drivers/media/video/msm/wfd/Makefile
+++ b/drivers/media/video/msm/wfd/Makefile
@@ -2,3 +2,4 @@
 obj-y += enc-subdev.o
 obj-y += vsg-subdev.o
 obj-y += wfd-ioctl.o
+obj-y += wfd-util.o
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index e3d9d2d..57dff2e 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -12,7 +12,7 @@
 */
 
 #include <media/v4l2-subdev.h>
-
+#include <mach/iommu_domains.h>
 #include "enc-subdev.h"
 #include "wfd-util.h"
 #include <media/msm/vcd_api.h>
@@ -198,6 +198,40 @@
 				(int)vbuf->v4l2_buf.timestamp.tv_usec,
 				frame_data->frame);
 
+		/*
+		 * Output buffers are enc-subdev and vcd's problem, so
+		 * if buffer is cached, need to flush before giving to
+		 * client. So doing the dirty stuff in this little context
+		 */
+		{
+			unsigned long kvaddr, phys_addr;
+			s32 buffer_index = -1, ion_flags = 0;
+			struct ion_handle *ion_handle;
+			int pmem_fd;
+			struct file *filp;
+			bool rc;
+
+			rc = vidc_lookup_addr_table(client_ctx,
+					BUFFER_TYPE_OUTPUT, true,
+					(unsigned long *)&frame_data->
+					frm_clnt_data, &kvaddr, &phys_addr,
+					&pmem_fd, &filp, &buffer_index);
+
+			if (rc)
+				ion_flags = vidc_get_fd_info(client_ctx,
+					BUFFER_TYPE_OUTPUT, pmem_fd,
+					kvaddr, buffer_index, &ion_handle);
+			else
+				WFD_MSG_ERR("Got an output buffer that we "
+						"couldn't recognize!\n");
+
+			if (msm_ion_do_cache_op(client_ctx->user_ion_client,
+				ion_handle, &kvaddr, frame_data->data_len,
+				ION_IOC_CLEAN_INV_CACHES))
+				WFD_MSG_ERR("OP buffer flush failed\n");
+
+		}
+
 		inst->op_buffer_done(inst->cbdata, status, vbuf);
 		break;
 	case VCD_EVT_RESP_START:
@@ -334,17 +368,27 @@
 	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.align = 0;
+	buf_req.sz = ALIGN(aligned_height * aligned_width, SZ_2K)
+		+ ALIGN(aligned_height * aligned_width * 1/2, SZ_2K);
+	buf_req.align = SZ_4K;
 	inst->width = b->width;
 	inst->height = b->height;
 	rc = vcd_set_buffer_requirements(client_ctx->vcd_handle,
@@ -699,7 +743,8 @@
 }
 
 static long venc_set_h264_intra_period(struct video_client_ctx *client_ctx,
-		__s32 period) {
+		__s32 period)
+{
 	struct vcd_property_i_period vcd_property_i_period;
 	struct vcd_property_codec vcd_property_codec;
 	struct vcd_property_hdr vcd_property_hdr;
@@ -726,7 +771,7 @@
 	vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
 
 	vcd_property_i_period.p_frames = period - 1;
-	vcd_property_i_period.b_frames = 1;
+	vcd_property_i_period.b_frames = 0;
 
 	rc = vcd_set_property(client_ctx->vcd_handle,
 				&vcd_property_hdr, &vcd_property_i_period);
@@ -740,6 +785,47 @@
 	return rc;
 }
 
+static long venc_get_h264_intra_period(struct video_client_ctx *client_ctx,
+		__s32 *period)
+{
+	struct vcd_property_i_period vcd_property_i_period;
+	struct vcd_property_codec vcd_property_codec;
+	struct vcd_property_hdr vcd_property_hdr;
+	int rc = 0;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting codec property\n");
+		goto err;
+	}
+
+	if (vcd_property_codec.codec != VCD_CODEC_H264) {
+		rc = -ENOTSUPP;
+		WFD_MSG_ERR("Control not supported for non H264 codec\n");
+		goto err;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_INTRA_PERIOD;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_i_period);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting intra period\n");
+		goto err;
+	}
+
+	*period = vcd_property_i_period.p_frames + 1;
+err:
+	return rc;
+}
+
 static long venc_request_frame(struct video_client_ctx *client_ctx, __s32 type)
 {
 	struct vcd_property_req_i_frame vcd_property_req_i_frame;
@@ -950,21 +1036,537 @@
 	return rc;
 }
 
-static long venc_alloc_input_buffer(struct v4l2_subdev *sd, void *arg)
+static long venc_set_qp_value(struct video_client_ctx *client_ctx,
+		__s32 frametype, __s32 qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_session_qp vcd_property_session_qp;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_SESSION_QP;
+	vcd_property_hdr.sz = sizeof(vcd_property_session_qp);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_session_qp);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get session qp\n");
+		goto err;
+	}
+
+	switch (frametype) {
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+		vcd_property_session_qp.i_frame_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+		vcd_property_session_qp.p_frame_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+		vcd_property_session_qp.b_frame_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+		rc = -ENOTSUPP;
+		goto err;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+
+	rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_session_qp);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set session qp\n");
+		goto err;
+	}
+err:
+	return rc;
+}
+
+static long venc_get_qp_value(struct video_client_ctx *client_ctx,
+		__s32 frametype, __s32 *qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_session_qp vcd_property_session_qp;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_SESSION_QP;
+	vcd_property_hdr.sz = sizeof(vcd_property_session_qp);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_session_qp);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get session qp\n");
+		goto err;
+	}
+
+	switch (frametype) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+		*qp = vcd_property_session_qp.i_frame_qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+		*qp = vcd_property_session_qp.p_frame_qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+		*qp = vcd_property_session_qp.b_frame_qp;
+		break;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+err:
+	return rc;
+}
+
+static long venc_set_qp_range(struct video_client_ctx *client_ctx,
+		__s32 type, __s32 qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_qp_range vcd_property_qp_range;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_QP_RANGE;
+	vcd_property_hdr.sz = sizeof(vcd_property_qp_range);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get qp range\n");
+		goto err;
+	}
+
+	switch (type) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+		vcd_property_qp_range.min_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		vcd_property_qp_range.max_qp = qp;
+		break;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set qp range\n");
+		goto err;
+	}
+err:
+	return rc;
+}
+
+static long venc_get_qp_range(struct video_client_ctx *client_ctx,
+		__s32 type, __s32 *qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_qp_range vcd_property_qp_range;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_QP_RANGE;
+	vcd_property_hdr.sz = sizeof(vcd_property_qp_range);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get qp range\n");
+		goto err;
+	}
+
+	switch (type) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+		*qp = vcd_property_qp_range.min_qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		*qp = vcd_property_qp_range.max_qp;
+		break;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set qp range\n");
+		goto err;
+	}
+err:
+	return rc;
+}
+
+static long venc_set_header_mode(struct video_client_ctx *client_ctx,
+		__s32 mode)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_sps_pps_for_idr_enable sps_pps_for_idr_enable;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
+	vcd_property_hdr.sz = sizeof(sps_pps_for_idr_enable);
+	switch (mode) {
+	case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE:
+		sps_pps_for_idr_enable.sps_pps_for_idr_enable_flag = 0;
+		break;
+	case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME:
+		sps_pps_for_idr_enable.sps_pps_for_idr_enable_flag = 1;
+		break;
+	case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+	default:
+		WFD_MSG_ERR("Video header mode %d not supported\n",
+				mode);
+		rc = -ENOTSUPP;
+		goto err;
+	}
+
+	rc =  vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&sps_pps_for_idr_enable);
+	if (rc) {
+		WFD_MSG_ERR("Failed to set enable_sps_pps_for_idr\n");
+		goto err;
+	}
+err:
+	return rc;
+}
+
+static long venc_get_header_mode(struct video_client_ctx *client_ctx,
+		__s32 *mode)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_sps_pps_for_idr_enable sps_pps_for_idr_enable;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
+	vcd_property_hdr.sz = sizeof(sps_pps_for_idr_enable);
+	rc =  vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&sps_pps_for_idr_enable);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get sps/pps for idr enable\n");
+		goto err;
+	}
+
+	*mode = sps_pps_for_idr_enable.sps_pps_for_idr_enable_flag ?
+		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME :
+		V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE;
+err:
+	return rc;
+}
+
+static long venc_set_multislicing_mode(struct video_client_ctx *client_ctx,
+			__u32 control, __s32 value)
+{
+	int rc = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size vcd_frame_size;
+	struct vcd_buffer_requirement vcd_buf_req;
+	struct vcd_property_multi_slice vcd_multi_slice;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		rc = -EINVAL;
+		goto set_multislicing_mode_fail;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz =
+		sizeof(vcd_frame_size);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_frame_size);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get frame size\n");
+		goto set_multislicing_mode_fail;
+	}
+
+	rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_OUTPUT, &vcd_buf_req);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get buf reqs\n");
+		goto set_multislicing_mode_fail;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_MULTI_SLICE;
+	vcd_property_hdr.sz = sizeof(vcd_multi_slice);
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_multi_slice);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get multi slice\n");
+		goto set_multislicing_mode_fail;
+	}
+
+	switch (control) {
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+		if (vcd_multi_slice.m_slice_sel !=
+				VCD_MSLICE_BY_BYTE_COUNT) {
+			WFD_MSG_ERR("Not in proper mode\n");
+			goto set_multislicing_mode_fail;
+		}
+		vcd_multi_slice.m_slice_size = value;
+		break;
+
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+		if (vcd_multi_slice.m_slice_sel !=
+				VCD_MSLICE_BY_MB_COUNT) {
+			WFD_MSG_ERR("Not in proper mode\n");
+			goto set_multislicing_mode_fail;
+		}
+		vcd_multi_slice.m_slice_size = value;
+		break;
+
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+			vcd_multi_slice.m_slice_sel = VCD_MSLICE_OFF;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+			vcd_multi_slice.m_slice_sel = VCD_MSLICE_BY_MB_COUNT;
+			/* Just a temporary size until client calls
+			 * V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB */
+			vcd_multi_slice.m_slice_size =
+				(vcd_frame_size.stride / 16) *
+				(vcd_frame_size.scan_lines / 16);
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+			vcd_multi_slice.m_slice_sel = VCD_MSLICE_BY_BYTE_COUNT;
+			/* Just a temporary size until client calls
+			 * V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES */
+			vcd_multi_slice.m_slice_size = vcd_buf_req.sz;
+			break;
+		default:
+			WFD_MSG_ERR("Unrecognized mode %d\n", value);
+			rc = -ENOTSUPP;
+			goto set_multislicing_mode_fail;
+		}
+
+		break;
+	default:
+		rc = -EINVAL;
+		goto set_multislicing_mode_fail;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_multi_slice);
+	if (rc) {
+		WFD_MSG_ERR("Failed to set multi slice\n");
+		goto set_multislicing_mode_fail;
+	}
+
+set_multislicing_mode_fail:
+	return rc;
+}
+
+static long venc_get_multislicing_mode(struct video_client_ctx *client_ctx,
+			__u32 control, __s32 *value)
+{
+	int rc = 0;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size vcd_frame_size;
+	struct vcd_buffer_requirement vcd_buf_req;
+	struct vcd_property_multi_slice vcd_multi_slice;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		rc = -EINVAL;
+		goto get_multislicing_mode_fail;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz =
+		sizeof(vcd_frame_size);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_frame_size);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get frame size\n");
+		goto get_multislicing_mode_fail;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_MULTI_SLICE;
+	vcd_property_hdr.sz = sizeof(vcd_multi_slice);
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_multi_slice);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get multi slice\n");
+		goto get_multislicing_mode_fail;
+	}
+
+	rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_OUTPUT, &vcd_buf_req);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get buf reqs\n");
+		goto get_multislicing_mode_fail;
+	}
+
+	switch (control) {
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+		if (vcd_multi_slice.m_slice_sel == VCD_MSLICE_BY_BYTE_COUNT)
+			*value = vcd_multi_slice.m_slice_size;
+		else {
+			WFD_MSG_ERR("Invalid query when in slice mode %d\n",
+					vcd_multi_slice.m_slice_sel);
+			rc = -EINVAL;
+			goto get_multislicing_mode_fail;
+		}
+		break;
+
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+		if (vcd_multi_slice.m_slice_sel == VCD_MSLICE_BY_MB_COUNT)
+			*value = vcd_multi_slice.m_slice_size;
+		else {
+			WFD_MSG_ERR("Invalid query when in slice mode %d\n",
+					vcd_multi_slice.m_slice_sel);
+			rc = -EINVAL;
+			goto get_multislicing_mode_fail;
+		}
+		break;
+
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+		switch (vcd_multi_slice.m_slice_sel) {
+		case VCD_MSLICE_OFF:
+			*value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE;
+			break;
+		case VCD_MSLICE_BY_MB_COUNT:
+			*value = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB;
+			break;
+		case VCD_MSLICE_BY_BYTE_COUNT:
+			*value = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES;
+			break;
+		default:
+			WFD_MSG_ERR("Encoder in an unknown mode %d\n",
+					vcd_multi_slice.m_slice_sel);
+			rc = -ENOENT;
+			goto get_multislicing_mode_fail;
+
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		goto get_multislicing_mode_fail;
+	}
+
+get_multislicing_mode_fail:
+	return rc;
+}
+
+static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	struct mem_region *mregion = arg;
 	struct venc_inst *inst = sd->dev_priv;
+	unsigned long paddr, kvaddr, temp;
 	struct video_client_ctx *client_ctx = &inst->venc_client;
 	int rc = 0;
+
 	if (!client_ctx || !mregion) {
 		WFD_MSG_ERR("Invalid input\n");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto ins_table_fail;
 	}
-	rc = vcd_allocate_buffer(client_ctx->vcd_handle,
-		VCD_BUFFER_INPUT, mregion->size,
-		&mregion->kvaddr, &mregion->paddr);
-	if (rc)
-		WFD_MSG_ERR("Failed to allocate input buffer\n");
+
+	kvaddr = (unsigned long)mregion->kvaddr;
+	paddr = (unsigned long)mregion->paddr;
+
+	if (!kvaddr || !paddr) {
+		WFD_MSG_ERR("Invalid addresses\n");
+		rc = -EINVAL;
+		goto ins_table_fail;
+	}
+
+	/*
+	 * Just a note: the third arg of vidc_insert_\
+	 * addr_table_kernel is supposed to be a userspace
+	 * address that is used as a key in the table. As
+	 * these bufs never leave the kernel, we need to have
+	 * an unique value to use as a key.  So re-using kernel
+	 * virtual addr for this purpose
+	 */
+	rc = vidc_insert_addr_table_kernel(client_ctx,
+		BUFFER_TYPE_INPUT, kvaddr, kvaddr,
+		paddr, 32, mregion->size);
+
+	if (rc == (u32)false) {
+		WFD_MSG_ERR("Failed to insert input buffer into table\n");
+		rc = -EFAULT;
+		goto ins_table_fail;
+	}
+
+	rc = vcd_set_buffer(client_ctx->vcd_handle,
+			VCD_BUFFER_INPUT, (u8 *)kvaddr,
+			mregion->size);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set input buffer\n");
+		rc = -EFAULT;
+		goto set_input_buf_fail;
+	}
+
+
+	return rc;
+
+set_input_buf_fail:
+	vidc_delete_addr_table(client_ctx, BUFFER_TYPE_INPUT,
+			kvaddr, &temp);
+ins_table_fail:
 	return rc;
 }
 
@@ -1091,14 +1693,17 @@
 			ctrl->user_virtual_addr = (void *)i;
 			client_ctx->recon_buffer_ion_handle[i]
 				= ion_alloc(client_ctx->user_ion_client,
-			control.size, SZ_8K, (0x1<<ION_CP_MM_HEAP_ID));
+			control.size, SZ_8K, ION_HEAP(ION_IOMMU_HEAP_ID) |
+			ION_HEAP(ION_CP_MM_HEAP_ID));
+
 			ctrl->kernel_virtual_addr = ion_map_kernel(
 				client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],	0);
 
-			rc = ion_phys(client_ctx->user_ion_client,
+			rc = ion_map_iommu(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],
-				&phy_addr, &len);
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+				0, &phy_addr, (unsigned long *)&len, 0, 0);
 			if (rc) {
 				WFD_MSG_ERR("Failed to allo recon buffers\n");
 				break;
@@ -1150,19 +1755,42 @@
 
 static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
 {
-	int rc = 0;
+	int del_rc = 0, free_rc = 0;
 	struct venc_inst *inst = sd->dev_priv;
 	struct video_client_ctx *client_ctx = &inst->venc_client;
 	struct mem_region *mregion = arg;
+	unsigned long vidc_kvaddr;
+
 	if (!client_ctx || !mregion) {
 		WFD_MSG_ERR("Invalid input\n");
 		return -EINVAL;
 	}
-	rc = vcd_free_buffer(client_ctx->vcd_handle, VCD_BUFFER_INPUT,
-					 mregion->kvaddr);
-	if (rc)
-		WFD_MSG_ERR("Failed to free input buffer\n");
-	return rc;
+
+	del_rc = vidc_delete_addr_table(client_ctx, BUFFER_TYPE_INPUT,
+				(unsigned long)mregion->kvaddr,
+				&vidc_kvaddr);
+	/*
+	 * Even if something went wrong in when
+	 * deleting from table, call vcd_free_buf
+	 */
+	if (del_rc == (u32)false) {
+		WFD_MSG_ERR("Failed to delete buf from address table\n");
+		del_rc = -ENOKEY;
+	} else if ((u8 *)vidc_kvaddr != mregion->kvaddr) {
+		WFD_MSG_ERR("Failed to find expected buffer\n");
+		del_rc = -EINVAL;
+	} else
+		del_rc = 0;
+
+	free_rc = vcd_free_buffer(client_ctx->vcd_handle, VCD_BUFFER_INPUT,
+					 (u8 *)vidc_kvaddr);
+
+	if (free_rc) {
+		WFD_MSG_ERR("Failed to free buffer from encoder\n");
+		free_rc = -EINVAL;
+	}
+
+	return del_rc ? del_rc : free_rc;
 }
 
 static long venc_free_recon_buffers(struct v4l2_subdev *sd, void *arg)
@@ -1184,6 +1812,9 @@
 				WFD_MSG_ERR("Failed to free recon buffer\n");
 
 			if (client_ctx->recon_buffer_ion_handle[i]) {
+				ion_unmap_iommu(client_ctx->user_ion_client,
+					 client_ctx->recon_buffer_ion_handle[i],
+					 VIDEO_DOMAIN, VIDEO_MAIN_POOL);
 				ion_unmap_kernel(client_ctx->user_ion_client,
 					client_ctx->recon_buffer_ion_handle[i]);
 				ion_free(client_ctx->user_ion_client,
@@ -1220,6 +1851,34 @@
 	case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
 		rc = venc_request_frame(client_ctx, ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+		rc = venc_set_qp_value(client_ctx, ctrl->id, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		rc = venc_set_qp_range(client_ctx, ctrl->id, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+		rc = venc_set_header_mode(client_ctx, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+		rc = venc_set_multislicing_mode(client_ctx, ctrl->id,
+				ctrl->value);
+		break;
 	default:
 		WFD_MSG_ERR("Set property not suported: %d\n", ctrl->id);
 		rc = -ENOTSUPP;
@@ -1248,6 +1907,37 @@
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 		rc = venc_get_codec_profile(client_ctx, ctrl->id, &ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+		rc = venc_get_h264_intra_period(client_ctx, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+		rc = venc_get_qp_value(client_ctx, ctrl->id, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		rc = venc_get_qp_range(client_ctx, ctrl->id, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+		rc = venc_get_header_mode(client_ctx, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+		rc = venc_get_multislicing_mode(client_ctx, ctrl->id,
+				&ctrl->value);
+		break;
 	default:
 		WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
 		rc = -ENOTSUPP;
@@ -1298,8 +1988,8 @@
 	case SET_FRAMERATE:
 		rc = venc_set_framerate(sd, arg);
 		break;
-	case ALLOC_INPUT_BUFFER:
-		rc = venc_alloc_input_buffer(sd, arg);
+	case SET_INPUT_BUFFER:
+		rc = venc_set_input_buffer(sd, arg);
 		break;
 	case SET_OUTPUT_BUFFER:
 		rc = venc_set_output_buffer(sd, arg);
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm/wfd/enc-subdev.h
index 0f7ca5f..69e7521 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.h
+++ b/drivers/media/video/msm/wfd/enc-subdev.h
@@ -14,6 +14,7 @@
 #ifndef _WFD_ENC_SUBDEV_
 #define _WFD_ENC_SUBDEV_
 
+#include <linux/ion.h>
 #include <media/v4l2-subdev.h>
 #include <media/videobuf2-core.h>
 #define VENC_MAGIC_IOCTL 'V'
@@ -26,6 +27,7 @@
 	u32 offset;
 	u32 fd;
 	u32 cookie;
+	struct ion_handle *ion_handle;
 };
 struct bufreq {
 	u32 count;
@@ -65,7 +67,7 @@
 #define FILL_OUTPUT_BUFFER  _IO('V', 15)
 #define SET_FORMAT _IOW('V', 16, struct v4l2_format *)
 #define SET_FRAMERATE _IOW('V', 17, struct v4l2_fract *)
-#define ALLOC_INPUT_BUFFER _IOWR('V', 18, struct mem_region *)
+#define SET_INPUT_BUFFER _IOWR('V', 18, struct mem_region *)
 #define SET_OUTPUT_BUFFER _IOWR('V', 19, struct mem_region *)
 #define ALLOC_RECON_BUFFERS _IO('V', 20)
 #define FREE_OUTPUT_BUFFER _IOWR('V', 21, struct mem_region *)
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.c b/drivers/media/video/msm/wfd/vsg-subdev.c
index 53b6e20..ac8e4e7 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.c
+++ b/drivers/media/video/msm/wfd/vsg-subdev.c
@@ -21,6 +21,7 @@
 #define DEFAULT_FRAME_INTERVAL (66*NSEC_PER_MSEC)
 #define DEFAULT_MAX_FRAME_INTERVAL (1*NSEC_PER_SEC)
 #define DEFAULT_MODE ((enum vsg_modes)VSG_MODE_CFR)
+#define MAX_BUFS_BUSY_WITH_ENC 5
 
 static int vsg_release_input_buffer(struct vsg_context *context,
 		struct vsg_buf_info *buf)
@@ -55,77 +56,117 @@
 	if (buf->flags & VSG_NEVER_SET_LAST_BUFFER)
 		WFD_MSG_WARN("Shouldn't be setting this to last buffer\n");
 
-	/* Update the last buffer and memcpy the data into the back up buffer*/
 	context->last_buffer = buf;
 
 	WFD_MSG_DBG("Setting last buffer to paddr %p\n",
 			(void *)buf->mdp_buf_info.paddr);
+}
 
-	if (context->regen_buffer) {
-		int buf_size;
-		void *cookie;
+static void vsg_encode_helper_func(struct work_struct *task)
+{
+	struct vsg_encode_work *work =
+		container_of(task, struct vsg_encode_work, work);
 
-		/*FIXME: Somewhat hacky, looking into cookie */
-		cookie = buf->mdp_buf_info.cookie;
-		buf_size = ((struct mem_region *)cookie)->size;
-
-		memcpy((void *)context->regen_buffer->mdp_buf_info.kvaddr,
-				(void *)buf->mdp_buf_info.kvaddr,
-				buf_size);
-		context->send_regen_buffer = false;
+	/*
+	 * 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;
+	int rc = 0, count = 0;
 	mutex_lock(&context->mutex);
 
 	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;
 	}
 
+	list_for_each_entry(temp, &context->busy_queue.node, node) {
+		if (++count > MAX_BUFS_BUSY_WITH_ENC) {
+			WFD_MSG_WARN("Skipping encode, too many "
+				"buffers with encoder");
+			goto err_skip_encode;
+		}
+	}
+
 	buf_info = list_first_entry(&context->free_queue.node,
 			struct vsg_buf_info, node);
 	list_del(&buf_info->node);
 	INIT_LIST_HEAD(&buf_info->node);
 
 	ktime_get_ts(&buf_info->time);
-	mod_timer(&context->threshold_timer, jiffies +
-			nsecs_to_jiffies(context->max_frame_interval));
+	hrtimer_forward_now(&context->threshold_timer, ns_to_ktime(
+				context->max_frame_interval));
 
+	temp = NULL;
 	list_for_each_entry(temp, &context->busy_queue.node, node) {
 		if (mdp_buf_info_equals(&temp->mdp_buf_info,
 					&buf_info->mdp_buf_info)) {
-			WFD_MSG_DBG("Buffer %p already in queue "
-				"to be encoded, delaying encoding\n",
-				(void *)temp->mdp_buf_info.paddr);
-			list_add(&buf_info->node, &context->free_queue.node);
-			/* just skip the push to encoder*/
-			goto err_skip_encode;
+			temp->flags |= VSG_NEVER_RELEASE;
 		}
 	}
 
-	mutex_unlock(&context->mutex);
-	rc = vsg_encode_frame(context, buf_info);
-	if (rc < 0) {
-		WFD_MSG_ERR("frame encode failed");
-		goto err_encode_fail;
+	if (context->last_buffer &&
+		mdp_buf_info_equals(&context->last_buffer->mdp_buf_info,
+			&buf_info->mdp_buf_info)) {
+		context->last_buffer->flags |= VSG_NEVER_RELEASE;
 	}
-	mutex_lock(&context->mutex);
+
+	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_skip_encode;
+	}
+
+	buf_info->flags |= VSG_BUF_BEING_ENCODED;
+	if (!(buf_info->flags & VSG_NEVER_SET_LAST_BUFFER)) {
+		if (context->last_buffer) {
+			struct vsg_buf_info *old_last_buffer =
+				context->last_buffer;
+			bool last_buf_with_us = old_last_buffer &&
+				!(old_last_buffer->flags &
+					VSG_BUF_BEING_ENCODED);
+			bool can_release = old_last_buffer &&
+				!(old_last_buffer->flags &
+					VSG_NEVER_RELEASE);
+
+			if (old_last_buffer && last_buf_with_us
+				&& can_release) {
+				vsg_release_input_buffer(context,
+					old_last_buffer);
+				kfree(old_last_buffer);
+			}
+		}
+		vsg_set_last_buffer(context, buf_info);
+	}
 
 	list_add_tail(&buf_info->node, &context->busy_queue.node);
 err_skip_encode:
 	mutex_unlock(&context->mutex);
-err_encode_fail:
 	kfree(work);
 }
 
@@ -139,7 +180,7 @@
 
 	mutex_lock(&context->mutex);
 
-	if (context->stopped)
+	if (context->state != VSG_STATE_STARTED)
 		goto err_locked;
 
 	if (list_empty(&context->free_queue.node)
@@ -160,24 +201,12 @@
 				goto err_locked;
 			}
 
-			if (context->regen_buffer) {
-				if (context->send_regen_buffer) {
-					buf_to_encode =
-						context->regen_buffer;
-				} else {
-					buf_to_encode = context->last_buffer;
-				}
-
-				context->send_regen_buffer =
-					!context->send_regen_buffer;
-			} else {
-				WFD_MSG_WARN("Have no regen buffer\n");
-				buf_to_encode = context->last_buffer;
-			}
+			buf_to_encode = context->last_buffer;
 
 			info->mdp_buf_info = buf_to_encode->mdp_buf_info;
-			info->flags = buf_to_encode->flags;
+			info->flags = 0;
 			INIT_LIST_HEAD(&info->node);
+
 			list_add_tail(&info->node, &context->free_queue.node);
 			WFD_MSG_DBG("Regenerated frame with paddr %p\n",
 				(void *)info->mdp_buf_info.paddr);
@@ -202,28 +231,32 @@
 	kfree(work);
 }
 
-static void vsg_threshold_timeout_func(unsigned long data)
+static enum hrtimer_restart vsg_threshold_timeout_func(struct hrtimer *timer)
 {
-	struct vsg_context *context = (struct vsg_context *)data;
-	struct vsg_work *task = kzalloc(sizeof(*task), GFP_ATOMIC);
+	struct vsg_context *context = NULL;
+	struct vsg_work *task = NULL;
 
+	task = kzalloc(sizeof(*task), GFP_ATOMIC);
+	context = container_of(timer, struct vsg_context,
+			threshold_timer);
 	if (!task) {
 		WFD_MSG_ERR("Out of memory in %s", __func__);
 		goto threshold_err_bad_param;
 	} else if (!context) {
 		WFD_MSG_ERR("Context not proper in %s", __func__);
-		goto threshold_err_bad_param;
+		goto threshold_err_no_context;
 	}
 
-	mod_timer(&context->threshold_timer, jiffies +
-			nsecs_to_jiffies(context->max_frame_interval));
-
 	INIT_WORK(&task->work, vsg_timer_helper_func);
 	task->context = context;
 
 	queue_work(context->work_queue, &task->work);
 threshold_err_bad_param:
-	return;
+	hrtimer_forward_now(&context->threshold_timer, ns_to_ktime(
+				context->max_frame_interval));
+	return HRTIMER_RESTART;
+threshold_err_no_context:
+	return HRTIMER_NORESTART;
 }
 
 int vsg_init(struct v4l2_subdev *sd, u32 val)
@@ -248,15 +281,13 @@
 	context->frame_interval = DEFAULT_FRAME_INTERVAL;
 	context->max_frame_interval = DEFAULT_MAX_FRAME_INTERVAL;
 
-	context->threshold_timer = (struct timer_list)
-		TIMER_INITIALIZER(vsg_threshold_timeout_func,
-				context->max_frame_interval,
-				(unsigned long)context);
+	hrtimer_init(&context->threshold_timer, CLOCK_MONOTONIC,
+			HRTIMER_MODE_REL);
+	context->threshold_timer.function = vsg_threshold_timeout_func;
 
-	context->last_buffer = context->regen_buffer = NULL;
-	context->send_regen_buffer = false;
+	context->last_buffer = NULL;
 	context->mode = DEFAULT_MODE;
-	context->stopped = false;
+	context->state = VSG_STATE_NONE;
 	mutex_init(&context->mutex);
 
 	sd->dev_priv = context;
@@ -272,7 +303,6 @@
 
 	context = (struct vsg_context *)sd->dev_priv;
 	destroy_workqueue(context->work_queue);
-	kfree(context->regen_buffer);
 	kfree(context);
 	return 0;
 }
@@ -287,8 +317,18 @@
 	}
 
 	context = (struct vsg_context *)sd->dev_priv;
-	mod_timer(&context->threshold_timer, jiffies +
-			nsecs_to_jiffies(context->max_frame_interval));
+
+	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;
+	hrtimer_start(&context->threshold_timer, ns_to_ktime(context->
+			max_frame_interval), HRTIMER_MODE_REL);
 	return 0;
 }
 
@@ -304,7 +344,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) {
@@ -315,7 +355,7 @@
 		}
 	}
 
-	del_timer_sync(&context->threshold_timer);
+	hrtimer_cancel(&context->threshold_timer);
 
 	mutex_unlock(&context->mutex);
 
@@ -356,25 +396,18 @@
 		list_for_each_safe(pos, next, &context->free_queue.node) {
 			struct vsg_buf_info *temp =
 				list_entry(pos, struct vsg_buf_info, node);
-			bool is_last_buffer, is_regen_buffer;
-
-			is_last_buffer = context->last_buffer &&
+			bool is_last_buffer = context->last_buffer &&
 				mdp_buf_info_equals(
 					&context->last_buffer->mdp_buf_info,
 					&temp->mdp_buf_info);
 
-			is_regen_buffer = context->regen_buffer &&
-				mdp_buf_info_equals(
-					&context->regen_buffer->mdp_buf_info,
-					&temp->mdp_buf_info);
+			list_del(&temp->node);
 
-			if (!is_last_buffer && !is_regen_buffer &&
+			if (!is_last_buffer &&
 				!(temp->flags & VSG_NEVER_RELEASE)) {
 				vsg_release_input_buffer(context, temp);
+				kfree(temp);
 			}
-
-			list_del(&temp->node);
-			kfree(temp);
 		}
 	}
 
@@ -415,7 +448,7 @@
 {
 	struct vsg_context *context = NULL;
 	struct vsg_buf_info *buf_info, *last_buffer,
-			*regen_buffer, *expected_buffer;
+			*expected_buffer;
 	int rc = 0;
 
 	if (!arg || !sd) {
@@ -428,7 +461,6 @@
 	mutex_lock(&context->mutex);
 	buf_info = (struct vsg_buf_info *)arg;
 	last_buffer = context->last_buffer;
-	regen_buffer = context->regen_buffer;
 
 	expected_buffer = list_first_entry(&context->busy_queue.node,
 			struct vsg_buf_info, node);
@@ -436,27 +468,26 @@
 	WFD_MSG_DBG("Return frame with paddr %p\n",
 			(void *)buf_info->mdp_buf_info.paddr);
 
+	if (!expected_buffer) {
+		WFD_MSG_ERR("Unexpectedly received buffer from enc with "
+			"paddr %p\n", (void *)buf_info->mdp_buf_info.paddr);
+		goto return_ip_buf_bad_buf;
+	}
+
+	expected_buffer->flags &= ~VSG_BUF_BEING_ENCODED;
 	if (mdp_buf_info_equals(&expected_buffer->mdp_buf_info,
 				&buf_info->mdp_buf_info)) {
-		list_del(&expected_buffer->node);
-
-		if (!(expected_buffer->flags & VSG_NEVER_SET_LAST_BUFFER)) {
-			bool is_same_buffer = context->last_buffer &&
-				mdp_buf_info_equals(
+		bool is_same_buffer = context->last_buffer &&
+			mdp_buf_info_equals(
 					&context->last_buffer->mdp_buf_info,
 					&expected_buffer->mdp_buf_info);
 
-			if (!context->last_buffer || !is_same_buffer) {
-				struct vsg_buf_info *old_last_buffer =
-					context->last_buffer;
-				if (context->last_buffer)
-					vsg_release_input_buffer(context,
-							context->last_buffer);
-				vsg_set_last_buffer(context, expected_buffer);
-				kfree(old_last_buffer);
-			}
-		} else
-			WFD_MSG_WARN("Couldn't set the last buffer\n");
+		list_del(&expected_buffer->node);
+		if (!is_same_buffer &&
+			!(expected_buffer->flags & VSG_NEVER_RELEASE)) {
+			vsg_release_input_buffer(context, expected_buffer);
+			kfree(expected_buffer);
+		}
 	} else {
 		WFD_MSG_ERR("Returned buffer %p is not latest buffer, "
 				"expected %p\n",
@@ -472,38 +503,6 @@
 	return rc;
 }
 
-static long vsg_set_scratch_buffer(struct v4l2_subdev *sd, void *arg)
-{
-	struct vsg_context *context = NULL;
-	struct vsg_buf_info *buf_info;
-	struct vsg_buf_info *regen_buffer =
-		kzalloc(sizeof(*regen_buffer), GFP_KERNEL);
-	int rc = 0;
-
-	if (!arg || !sd) {
-		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
-		rc = -EINVAL;
-		goto set_scratch_buf_err_bad_param;
-	} else if (!regen_buffer) {
-		WFD_MSG_ERR("ERROR, out of memory in %s\n", __func__);
-		rc = -ENOMEM;
-		goto set_scratch_buf_err_bad_param;
-	}
-
-	context = (struct vsg_context *)sd->dev_priv;
-	buf_info = (struct vsg_buf_info *)arg;
-
-	mutex_lock(&context->mutex);
-	*regen_buffer = *buf_info;
-	regen_buffer->flags = VSG_NEVER_RELEASE | VSG_NEVER_SET_LAST_BUFFER;
-	context->regen_buffer = regen_buffer;
-	WFD_MSG_ERR("setting buffer with paddr %p as scratch buffer\n",
-			(void *)regen_buffer->mdp_buf_info.paddr);
-	mutex_unlock(&context->mutex);
-set_scratch_buf_err_bad_param:
-	return rc;
-}
-
 static long vsg_set_frame_interval(struct v4l2_subdev *sd, void *arg)
 {
 	struct vsg_context *context = NULL;
@@ -666,9 +665,6 @@
 	case VSG_RETURN_IP_BUFFER:
 		rc = vsg_return_ip_buffer(sd, arg);
 		break;
-	case VSG_SET_SCRATCH_BUFFER:
-		rc = vsg_set_scratch_buffer(sd, arg);
-		break;
 	case VSG_GET_FRAME_INTERVAL:
 		rc = vsg_get_frame_interval(sd, arg);
 		break;
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.h b/drivers/media/video/msm/wfd/vsg-subdev.h
index 1db45e8..dfc2e2e 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.h
+++ b/drivers/media/video/msm/wfd/vsg-subdev.h
@@ -26,6 +26,7 @@
 enum vsg_flags {
 	VSG_NEVER_RELEASE = 1<<0,
 	VSG_NEVER_SET_LAST_BUFFER = 1<<1,
+	VSG_BUF_BEING_ENCODED = 1<<2,
 };
 
 enum vsg_modes {
@@ -33,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;
@@ -53,12 +61,11 @@
 	/* All time related values below in nanosecs */
 	int64_t frame_interval, max_frame_interval;
 	struct workqueue_struct *work_queue;
-	struct timer_list threshold_timer;
+	struct hrtimer threshold_timer;
 	struct mutex mutex;
-	struct vsg_buf_info *last_buffer, *regen_buffer;
-	bool send_regen_buffer;
+	struct vsg_buf_info *last_buffer;
 	int mode;
-	bool stopped;
+	int state;
 };
 
 struct vsg_work {
@@ -66,6 +73,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)
@@ -74,13 +87,12 @@
 #define VSG_DQ_BUFFER  _IOR(VSG_MAGIC_IOCTL, 6, struct vsg_out_buf *)
 #define VSG_RETURN_IP_BUFFER _IOW(VSG_MAGIC_IOCTL, 7, struct vsg_buf_info *)
 #define VSG_ENCODE_DONE _IO(VSG_MAGIC_IOCTL, 8)
-#define VSG_SET_SCRATCH_BUFFER _IOW(VSG_MAGIC_IOCTL, 9, struct vsg_buf_info *)
 /* Time related arguments for frame interval ioctls are always in nanosecs*/
-#define VSG_SET_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 10, int64_t *)
-#define VSG_GET_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 11, int64_t *)
-#define VSG_SET_MAX_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 12, int64_t *)
-#define VSG_GET_MAX_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 13, int64_t *)
-#define VSG_SET_MODE _IOW(VSG_MAGIC_IOCTL, 14, enum vsg_modes *)
+#define VSG_SET_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 9, int64_t *)
+#define VSG_GET_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 10, int64_t *)
+#define VSG_SET_MAX_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 11, int64_t *)
+#define VSG_GET_MAX_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 12, int64_t *)
+#define VSG_SET_MODE _IOW(VSG_MAGIC_IOCTL, 13, enum vsg_modes *)
 
 extern int vsg_init(struct v4l2_subdev *sd, u32 val);
 extern long vsg_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 315705c..2c2c551 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -35,11 +35,12 @@
 #include "vsg-subdev.h"
 
 #define WFD_VERSION KERNEL_VERSION(0, 0, 1)
+#define WFD_NUM_DEVICES 2
+#define WFD_DEVICE_NUMBER_BASE 38
+#define WFD_DEVICE_SECURE (WFD_DEVICE_NUMBER_BASE + 1)
 #define DEFAULT_WFD_WIDTH 640
 #define DEFAULT_WFD_HEIGHT 480
-#define VSG_SCRATCH_BUFFERS 1
-#define MDP_WRITEBACK_BUFFERS 3
-#define VENC_INPUT_BUFFERS (VSG_SCRATCH_BUFFERS + MDP_WRITEBACK_BUFFERS)
+#define VENC_INPUT_BUFFERS 4
 
 struct wfd_device {
 	struct platform_device *pdev;
@@ -48,6 +49,8 @@
 	struct v4l2_subdev mdp_sdev;
 	struct v4l2_subdev enc_sdev;
 	struct v4l2_subdev vsg_sdev;
+	struct ion_client *ion_client;
+	bool secure_device;
 };
 
 struct mem_info {
@@ -60,6 +63,13 @@
 	unsigned long userptr;
 	struct mem_info minfo;
 };
+
+struct mem_region_pair {
+	struct mem_region *enc;
+	struct mem_region *mdp;
+	struct list_head list;
+};
+
 struct wfd_inst {
 	struct vb2_queue vid_bufq;
 	spinlock_t inst_lock;
@@ -76,6 +86,7 @@
 	u32 input_buf_size;
 	u32 out_buf_size;
 	struct list_head input_mem_list;
+	struct wfd_stats stats;
 };
 
 struct wfd_vid_buffer {
@@ -113,15 +124,127 @@
 {
 }
 
+static unsigned long wfd_enc_addr_to_mdp_addr(struct wfd_inst *inst,
+		unsigned long addr)
+{
+	struct list_head *ptr, *next;
+	struct mem_region_pair *mpair;
+	if (!list_empty(&inst->input_mem_list)) {
+		list_for_each_safe(ptr, next,
+				&inst->input_mem_list) {
+			mpair = list_entry(ptr, struct mem_region_pair,
+					list);
+			if (mpair->enc->paddr == (u8 *)addr)
+				return (unsigned long)mpair->mdp->paddr;
+		}
+	}
+
+	return (unsigned long)NULL;
+}
+
+static int wfd_allocate_ion_buffer(struct ion_client *client,
+		bool secure, struct mem_region *mregion)
+{
+	struct ion_handle *handle;
+	void *kvaddr, *phys_addr;
+	unsigned long size;
+	unsigned int alloc_regions = 0;
+	int rc;
+
+	alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
+	alloc_regions |= secure ? 0 :
+				ION_HEAP(ION_IOMMU_HEAP_ID);
+	handle = ion_alloc(client,
+			mregion->size, SZ_4K, alloc_regions);
+
+	if (IS_ERR_OR_NULL(handle)) {
+		WFD_MSG_ERR("Failed to allocate input buffer\n");
+		rc = PTR_ERR(handle);
+		goto alloc_fail;
+	}
+
+	kvaddr = ion_map_kernel(client,	handle,	CACHED);
+
+	if (IS_ERR_OR_NULL(kvaddr)) {
+		WFD_MSG_ERR("Failed to get virtual addr\n");
+		rc = PTR_ERR(kvaddr);
+		goto alloc_fail;
+	}
+
+	rc = ion_map_iommu(client, handle,
+			VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+			0, (unsigned long *)&phys_addr,
+			&size, 0, 0);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get physical addr\n");
+		goto alloc_fail;
+	} else if (size < mregion->size) {
+		WFD_MSG_ERR("Failed to map enough memory\n");
+		rc = -ENOMEM;
+		goto alloc_fail;
+	}
+
+	mregion->kvaddr = kvaddr;
+	mregion->paddr = phys_addr;
+	mregion->ion_handle = handle;
+
+	return rc;
+alloc_fail:
+	if (!IS_ERR_OR_NULL(handle)) {
+		ion_unmap_kernel(client, handle);
+		ion_free(client, handle);
+
+		mregion->kvaddr = NULL;
+		mregion->paddr = NULL;
+		mregion->ion_handle = NULL;
+	}
+	return rc;
+}
+
+/* Doesn't do iommu unmap */
+static int wfd_free_ion_buffer(struct ion_client *client,
+		struct mem_region *mregion)
+{
+	if (!client || !mregion) {
+		WFD_MSG_ERR("Failed to free ion buffer: "
+				"Invalid client or region");
+		return -EINVAL;
+	}
+	ion_unmap_kernel(client, mregion->ion_handle);
+	ion_free(client, mregion->ion_handle);
+	return 0;
+}
+
+static int wfd_flush_ion_buffer(struct ion_client *client,
+		struct mem_region *mregion)
+{
+	if (!client || !mregion) {
+		WFD_MSG_ERR("Failed to flush ion buffer: "
+				"Invalid client or region");
+		return -EINVAL;
+	} else if (!mregion->ion_handle) {
+		WFD_MSG_ERR("Failed to flush ion buffer: "
+				"not an ion buffer");
+		return -EINVAL;
+	}
+
+	return msm_ion_do_cache_op(client,
+			mregion->ion_handle,
+			mregion->kvaddr,
+			mregion->size,
+			ION_IOC_INV_CACHES);
+
+}
 int wfd_allocate_input_buffers(struct wfd_device *wfd_dev,
 			struct wfd_inst *inst)
 {
 	int i;
-	struct mem_region *mregion;
+	struct mem_region *enc_mregion, *mdp_mregion;
+	struct mem_region_pair *mpair;
 	int rc;
 	unsigned long flags;
 	struct mdp_buf_info mdp_buf = {0};
-	struct vsg_buf_info vsg_buf = {};
 	spin_lock_irqsave(&inst->inst_lock, flags);
 	if (inst->input_bufs_allocated) {
 		spin_unlock_irqrestore(&inst->inst_lock, flags);
@@ -131,42 +254,69 @@
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 
 	for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
-		mregion = kzalloc(sizeof(struct mem_region), GFP_KERNEL);
-		mregion->size = inst->input_buf_size;
-		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
-				ALLOC_INPUT_BUFFER, (void *)mregion);
+		mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
+		enc_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
+		mdp_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
+		enc_mregion->size = ALIGN(inst->input_buf_size, SZ_4K);
+
+		rc = wfd_allocate_ion_buffer(wfd_dev->ion_client,
+				wfd_dev->secure_device, enc_mregion);
 		if (rc) {
 			WFD_MSG_ERR("Failed to allocate input memory."
 				" This error causes memory leak!!!\n");
 			goto alloc_fail;
 		}
-		WFD_MSG_DBG("NOTE: paddr = %p, kvaddr = %p\n", mregion->paddr,
-					mregion->kvaddr);
-		list_add_tail(&mregion->list, &inst->input_mem_list);
+
+		WFD_MSG_DBG("NOTE: enc paddr = %p, kvaddr = %p\n",
+				enc_mregion->paddr,
+				enc_mregion->kvaddr);
+
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+				SET_INPUT_BUFFER, (void *)enc_mregion);
+
+		/* map the buffer from encoder to mdp */
+		mdp_mregion->kvaddr = enc_mregion->kvaddr;
+		mdp_mregion->size = enc_mregion->size;
+		mdp_mregion->offset = enc_mregion->offset;
+		mdp_mregion->fd = enc_mregion->fd;
+		mdp_mregion->cookie = 0;
+		mdp_mregion->ion_handle = enc_mregion->ion_handle;
+
+		rc = ion_map_iommu(wfd_dev->ion_client, mdp_mregion->ion_handle,
+				DISPLAY_DOMAIN, GEN_POOL, SZ_4K,
+				0, (unsigned long *)&mdp_mregion->paddr,
+				(unsigned long *)&mdp_mregion->size, 0, 0);
+		if (rc) {
+			WFD_MSG_ERR("Failed to map to mdp\n");
+			mdp_mregion->kvaddr = NULL;
+			mdp_mregion->paddr = NULL;
+			mdp_mregion->ion_handle = NULL;
+			goto alloc_fail;
+		}
 
 		mdp_buf.inst = inst->mdp_inst;
-		mdp_buf.cookie = mregion;
-		mdp_buf.kvaddr = (u32) mregion->kvaddr;
-		mdp_buf.paddr = (u32) mregion->paddr;
-		vsg_buf.mdp_buf_info = mdp_buf;
+		mdp_buf.cookie = enc_mregion;
+		mdp_buf.kvaddr = (u32) mdp_mregion->kvaddr;
+		mdp_buf.paddr = (u32) mdp_mregion->paddr;
 
-		if (i < MDP_WRITEBACK_BUFFERS) {
-			rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
-					MDP_Q_BUFFER, (void *)&mdp_buf);
-			if (rc) {
-				WFD_MSG_ERR("Unable to queue the"
-						" buffer to mdp\n");
-				break;
-			}
-		} else /*if (i < VSG_SCRATCH_BUFFERS*/ {
-			rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
-					VSG_SET_SCRATCH_BUFFER,
-					(void *)&vsg_buf);
-			if (rc) {
-				WFD_MSG_ERR("Unable to set scratch"
-						" buffer to vsg\n");
-				break;
-			}
+		WFD_MSG_DBG("NOTE: mdp paddr = %p, kvaddr = %p\n",
+				mdp_mregion->paddr,
+				mdp_mregion->kvaddr);
+
+		INIT_LIST_HEAD(&mpair->list);
+		mpair->enc = enc_mregion;
+		mpair->mdp = mdp_mregion;
+		list_add_tail(&mpair->list, &inst->input_mem_list);
+
+		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+				MDP_Q_BUFFER, (void *)&mdp_buf);
+		if (rc) {
+			WFD_MSG_ERR("Unable to queue the"
+					" buffer to mdp\n");
+			break;
+		} else {
+			wfd_stats_update(&inst->stats,
+					WFD_STAT_EVENT_MDP_QUEUE);
 		}
 	}
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
@@ -182,7 +332,7 @@
 			struct wfd_inst *inst)
 {
 	struct list_head *ptr, *next;
-	struct mem_region *mregion;
+	struct mem_region_pair *mpair;
 	unsigned long flags;
 	int rc = 0;
 	spin_lock_irqsave(&inst->inst_lock, flags);
@@ -195,16 +345,31 @@
 	if (!list_empty(&inst->input_mem_list)) {
 		list_for_each_safe(ptr, next,
 				&inst->input_mem_list) {
-			mregion = list_entry(ptr, struct mem_region,
+			mpair = list_entry(ptr, struct mem_region_pair,
 						list);
 			rc = v4l2_subdev_call(&wfd_dev->enc_sdev,
 					core, ioctl, FREE_INPUT_BUFFER,
-					(void *)mregion);
-			if (rc)
-				WFD_MSG_ERR("TODO: SOMETHING IS WRONG!!!\n");
+					(void *)mpair->enc);
 
-			list_del(&mregion->list);
-			kfree(mregion);
+			if (rc)
+				WFD_MSG_ERR("Failed to free buffers "
+						"from encoder\n");
+
+			if (mpair->mdp->paddr)
+				ion_unmap_iommu(wfd_dev->ion_client,
+						mpair->mdp->ion_handle,
+						DISPLAY_DOMAIN, GEN_POOL);
+
+			if (mpair->enc->paddr)
+				ion_unmap_iommu(wfd_dev->ion_client,
+						mpair->enc->ion_handle,
+						VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+
+			wfd_free_ion_buffer(wfd_dev->ion_client, mpair->enc);
+			list_del(&mpair->list);
+			kfree(mpair->enc);
+			kfree(mpair->mdp);
+			kfree(mpair);
 		}
 	}
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
@@ -353,6 +518,9 @@
 			WFD_MSG_ERR("Either streamoff called or"
 						" MDP REPORTED ERROR\n");
 			break;
+		} else {
+			wfd_stats_update(&inst->stats,
+				WFD_STAT_EVENT_MDP_DEQUEUE);
 		}
 
 		mregion = obuf_mdp.cookie;
@@ -366,13 +534,18 @@
 		ibuf_vsg.mdp_buf_info.inst = inst->mdp_inst;
 		ibuf_vsg.mdp_buf_info.cookie = mregion;
 		ibuf_vsg.mdp_buf_info.kvaddr = (u32) mregion->kvaddr;
-		ibuf_vsg.mdp_buf_info.paddr = (u32) mregion->paddr;
+		ibuf_vsg.mdp_buf_info.paddr =
+			(u32)wfd_enc_addr_to_mdp_addr(inst,
+					(unsigned long)mregion->paddr);
 		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev,
 			core, ioctl, VSG_Q_BUFFER, (void *)&ibuf_vsg);
 
 		if (rc) {
-			WFD_MSG_ERR("Failed to encode frame\n");
+			WFD_MSG_ERR("Failed to queue frame to vsg\n");
 			break;
+		} else {
+			wfd_stats_update(&inst->stats,
+				WFD_STAT_EVENT_VSG_QUEUE);
 		}
 	}
 	WFD_MSG_DBG("Exiting the thread\n");
@@ -387,6 +560,8 @@
 	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
 	int rc = 0;
 
+	WFD_MSG_ERR("Stream on called\n");
+	WFD_MSG_DBG("enc start\n");
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 			ENCODE_START, (void *)inst->venc_inst);
 	if (rc) {
@@ -394,6 +569,7 @@
 		goto subdev_start_fail;
 	}
 
+	WFD_MSG_DBG("vsg start\n");
 	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
 			VSG_START, NULL);
 	if (rc) {
@@ -407,6 +583,7 @@
 		rc = PTR_ERR(inst->mdp_task);
 		goto subdev_start_fail;
 	}
+	WFD_MSG_DBG("mdp start\n");
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 			 MDP_START, (void *)inst->mdp_inst);
 	if (rc)
@@ -422,17 +599,20 @@
 		(struct wfd_device *)video_drvdata(priv_data);
 	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
 	int rc = 0;
+	WFD_MSG_DBG("mdp stop\n");
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 			 MDP_STOP, (void *)inst->mdp_inst);
 	if (rc)
 		WFD_MSG_ERR("Failed to stop MDP\n");
 
+	WFD_MSG_DBG("vsg stop\n");
 	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
 			 VSG_STOP, NULL);
 	if (rc)
 		WFD_MSG_ERR("Failed to stop VSG\n");
 
 	kthread_stop(inst->mdp_task);
+	WFD_MSG_DBG("enc stop\n");
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 			ENCODE_STOP, (void *)inst->venc_inst);
 	if (rc)
@@ -560,6 +740,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) {
@@ -658,9 +843,13 @@
 		WFD_MSG_ERR("Failed to register buffer\n");
 		return rc;
 	}
+
 	rc = vb2_qbuf(&inst->vid_bufq, b);
 	if (rc)
 		WFD_MSG_ERR("Failed to queue buffer\n");
+	else
+		wfd_stats_update(&inst->stats, WFD_STAT_EVENT_CLIENT_QUEUE);
+
 	return rc;
 }
 
@@ -719,8 +908,17 @@
 		struct v4l2_buffer *b)
 {
 	struct wfd_inst *inst = filp->private_data;
+	int rc;
+
 	WFD_MSG_INFO("Waiting to dequeue buffer\n");
-	return vb2_dqbuf(&inst->vid_bufq, b, 0);
+	rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
+
+	if (rc)
+		WFD_MSG_ERR("Failed to dequeue buffer\n");
+	else
+		wfd_stats_update(&inst->stats, WFD_STAT_EVENT_CLIENT_DEQUEUE);
+
+	return rc;
 }
 static int wfdioc_g_ctrl(struct file *filp, void *fh,
 					struct v4l2_control *a)
@@ -904,6 +1102,7 @@
 {
 	unsigned long flags;
 	struct v4l2_format fmt;
+	struct v4l2_control ctrl;
 	struct wfd_inst *inst = filp->private_data;
 	if (!inst) {
 		WFD_MSG_ERR("Invalid argument\n");
@@ -917,6 +1116,10 @@
 			= V4L2_PIX_FMT_H264;
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 	wfdioc_s_fmt(filp, filp->private_data, &fmt);
+
+	ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
+	ctrl.value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME;
+	wfdioc_s_ctrl(filp, filp->private_data, &ctrl);
 	return 0;
 }
 static void venc_op_buffer_done(void *cookie, u32 status,
@@ -940,17 +1143,24 @@
 	mdp_buf.inst = inst->mdp_inst;
 	mdp_buf.cookie = mregion;
 	mdp_buf.kvaddr = (u32) mregion->kvaddr;
-	mdp_buf.paddr = (u32) mregion->paddr;
+	mdp_buf.paddr =
+		(u32)wfd_enc_addr_to_mdp_addr(inst,
+			(unsigned long)mregion->paddr);
 	buf.mdp_buf_info = mdp_buf;
+
 	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
 			ioctl, VSG_RETURN_IP_BUFFER, (void *)&buf);
 	if (rc)
 		WFD_MSG_ERR("Failed to return buffer to vsg\n");
+	else
+		wfd_stats_update(&inst->stats, WFD_STAT_EVENT_ENC_DEQUEUE);
+
 }
 
 static int vsg_release_input_frame(void *cookie, struct vsg_buf_info *buf)
 {
 	struct file *filp = cookie;
+	struct wfd_inst *inst = filp->private_data;
 	struct wfd_device *wfd_dev =
 		(struct wfd_device *)video_drvdata(filp);
 	int rc = 0;
@@ -959,6 +1169,10 @@
 			ioctl, MDP_Q_BUFFER, buf);
 	if (rc)
 		WFD_MSG_ERR("Failed to Q buffer to mdp\n");
+	else {
+		wfd_stats_update(&inst->stats, WFD_STAT_EVENT_MDP_QUEUE);
+		wfd_stats_update(&inst->stats, WFD_STAT_EVENT_VSG_DEQUEUE);
+	}
 
 	return rc;
 }
@@ -966,9 +1180,11 @@
 static int vsg_encode_frame(void *cookie, struct vsg_buf_info *buf)
 {
 	struct file *filp = cookie;
+	struct wfd_inst *inst = filp->private_data;
 	struct wfd_device *wfd_dev =
 		(struct wfd_device *)video_drvdata(filp);
 	struct venc_buf_info venc_buf;
+	int rc = 0;
 
 	if (!buf)
 		return -EINVAL;
@@ -978,8 +1194,17 @@
 		.mregion = buf->mdp_buf_info.cookie
 	};
 
-	return v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+	wfd_flush_ion_buffer(wfd_dev->ion_client, venc_buf.mregion);
+
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 			ENCODE_FRAME, &venc_buf);
+
+	if (rc)
+		WFD_MSG_ERR("Encode failed\n");
+	else
+		wfd_stats_update(&inst->stats, WFD_STAT_EVENT_ENC_QUEUE);
+
+	return rc;
 }
 
 void *wfd_vb2_mem_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
@@ -1036,6 +1261,9 @@
 	spin_lock_init(&inst->inst_lock);
 	INIT_LIST_HEAD(&inst->input_mem_list);
 	INIT_LIST_HEAD(&inst->minfo_list);
+
+	wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
+
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
 				(void *)&inst->mdp_inst);
 	if (rc) {
@@ -1114,6 +1342,8 @@
 
 		kfree(inst);
 	}
+
+	wfd_stats_deinit(&inst->stats);
 	WFD_MSG_DBG("wfd_close: X\n");
 	return 0;
 }
@@ -1127,19 +1357,11 @@
 {
 
 }
-static int __devinit __wfd_probe(struct platform_device *pdev)
+
+static int wfd_dev_setup(struct wfd_device *wfd_dev, int dev_num,
+		struct platform_device *pdev)
 {
 	int rc = 0;
-	struct wfd_device *wfd_dev;
-	WFD_MSG_DBG("__wfd_probe: E\n");
-	wfd_dev = kzalloc(sizeof(*wfd_dev), GFP_KERNEL);
-	if (!wfd_dev) {
-		WFD_MSG_ERR("Could not allocate memory for "
-				"wfd device\n");
-		rc = -ENOMEM;
-		goto err_v4l2_registration;
-	}
-	pdev->dev.platform_data = (void *) wfd_dev;
 	rc = v4l2_device_register(&pdev->dev, &wfd_dev->v4l2_dev);
 	if (rc) {
 		WFD_MSG_ERR("Failed to register the video device\n");
@@ -1155,7 +1377,8 @@
 	wfd_dev->pvdev->fops = &g_wfd_fops;
 	wfd_dev->pvdev->ioctl_ops = &g_wfd_ioctl_ops;
 
-	rc = video_register_device(wfd_dev->pvdev, VFL_TYPE_GRABBER, -1);
+	rc = video_register_device(wfd_dev->pvdev, VFL_TYPE_GRABBER,
+			dev_num);
 	if (rc) {
 		WFD_MSG_ERR("Failed to register the device\n");
 		goto err_video_register_device;
@@ -1165,7 +1388,7 @@
 	v4l2_subdev_init(&wfd_dev->mdp_sdev, &mdp_subdev_ops);
 	strncpy(wfd_dev->mdp_sdev.name, "wfd-mdp", V4L2_SUBDEV_NAME_SIZE);
 	rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
-						&wfd_dev->mdp_sdev);
+			&wfd_dev->mdp_sdev);
 	if (rc) {
 		WFD_MSG_ERR("Failed to register mdp subdevice: %d\n", rc);
 		goto err_mdp_register_subdev;
@@ -1174,7 +1397,7 @@
 	v4l2_subdev_init(&wfd_dev->enc_sdev, &enc_subdev_ops);
 	strncpy(wfd_dev->enc_sdev.name, "wfd-venc", V4L2_SUBDEV_NAME_SIZE);
 	rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
-						&wfd_dev->enc_sdev);
+			&wfd_dev->enc_sdev);
 	if (rc) {
 		WFD_MSG_ERR("Failed to register encoder subdevice: %d\n", rc);
 		goto err_venc_register_subdev;
@@ -1188,7 +1411,7 @@
 	v4l2_subdev_init(&wfd_dev->vsg_sdev, &vsg_subdev_ops);
 	strncpy(wfd_dev->vsg_sdev.name, "wfd-vsg", V4L2_SUBDEV_NAME_SIZE);
 	rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
-						&wfd_dev->vsg_sdev);
+			&wfd_dev->vsg_sdev);
 	if (rc) {
 		WFD_MSG_ERR("Failed to register vsg subdevice: %d\n", rc);
 		goto err_venc_init;
@@ -1208,6 +1431,74 @@
 err_video_device_alloc:
 	v4l2_device_unregister(&wfd_dev->v4l2_dev);
 err_v4l2_registration:
+	return rc;
+}
+static int __devinit __wfd_probe(struct platform_device *pdev)
+{
+	int rc = 0, c = 0;
+	struct wfd_device *wfd_dev; /* Should be taken as an array*/
+	struct ion_client *ion_client = NULL;
+
+	WFD_MSG_DBG("__wfd_probe: E\n");
+	wfd_dev = kzalloc(sizeof(*wfd_dev)*WFD_NUM_DEVICES, GFP_KERNEL);
+	if (!wfd_dev) {
+		WFD_MSG_ERR("Could not allocate memory for "
+				"wfd device\n");
+		rc = -ENOMEM;
+		goto err_v4l2_probe;
+	}
+	pdev->dev.platform_data = (void *) wfd_dev;
+
+	ion_client = msm_ion_client_create(-1, "wfd");
+
+	rc = wfd_stats_setup();
+	if (rc) {
+		WFD_MSG_ERR("No debugfs support: %d\n", rc);
+		/* Don't treat this as a fatal err */
+		rc = 0;
+	}
+
+	if (!ion_client) {
+		WFD_MSG_ERR("Failed to create ion client\n");
+		rc = -ENODEV;
+		goto err_v4l2_probe;
+	}
+
+	for (c = 0; c < WFD_NUM_DEVICES; ++c) {
+		rc = wfd_dev_setup(&wfd_dev[c],
+			WFD_DEVICE_NUMBER_BASE + c, pdev);
+
+		if (rc) {
+			/* Clear out old devices */
+			for (--c; c >= 0; --c) {
+				v4l2_device_unregister_subdev(
+						&wfd_dev[c].vsg_sdev);
+				v4l2_device_unregister_subdev(
+						&wfd_dev[c].enc_sdev);
+				v4l2_device_unregister_subdev(
+						&wfd_dev[c].mdp_sdev);
+				video_unregister_device(wfd_dev[c].pvdev);
+				video_device_release(wfd_dev[c].pvdev);
+				v4l2_device_unregister(&wfd_dev[c].v4l2_dev);
+			}
+
+			goto err_v4l2_probe;
+		}
+
+		/* Other device specific stuff */
+		wfd_dev[c].ion_client = ion_client;
+		switch (WFD_DEVICE_NUMBER_BASE + c) {
+		case WFD_DEVICE_SECURE:
+			wfd_dev[c].secure_device = true;
+			break;
+		default:
+			break;
+		}
+
+	}
+	WFD_MSG_DBG("__wfd_probe: X\n");
+	return rc;
+err_v4l2_probe:
 	kfree(wfd_dev);
 	return rc;
 }
@@ -1215,6 +1506,8 @@
 static int __devexit __wfd_remove(struct platform_device *pdev)
 {
 	struct wfd_device *wfd_dev;
+	int c = 0;
+
 	wfd_dev = (struct wfd_device *)pdev->dev.platform_data;
 
 	WFD_MSG_DBG("Inside wfd_remove\n");
@@ -1223,10 +1516,16 @@
 		return -ENODEV;
 	}
 
-	v4l2_device_unregister_subdev(&wfd_dev->mdp_sdev);
-	video_unregister_device(wfd_dev->pvdev);
-	video_device_release(wfd_dev->pvdev);
-	v4l2_device_unregister(&wfd_dev->v4l2_dev);
+	wfd_stats_teardown();
+	for (c = 0; c < WFD_NUM_DEVICES; ++c) {
+		v4l2_device_unregister_subdev(&wfd_dev[c].vsg_sdev);
+		v4l2_device_unregister_subdev(&wfd_dev[c].enc_sdev);
+		v4l2_device_unregister_subdev(&wfd_dev[c].mdp_sdev);
+		video_unregister_device(wfd_dev[c].pvdev);
+		video_device_release(wfd_dev[c].pvdev);
+		v4l2_device_unregister(&wfd_dev[c].v4l2_dev);
+	}
+
 	kfree(wfd_dev);
 	return 0;
 }
diff --git a/drivers/media/video/msm/wfd/wfd-util.c b/drivers/media/video/msm/wfd/wfd-util.c
new file mode 100644
index 0000000..233668b0
--- /dev/null
+++ b/drivers/media/video/msm/wfd/wfd-util.c
@@ -0,0 +1,217 @@
+/* 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/debugfs.h>
+#include <linux/hrtimer.h>
+#include <linux/limits.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include "wfd-util.h"
+
+static struct dentry *wfd_debugfs_root;
+
+int wfd_stats_setup()
+{
+	wfd_debugfs_root = debugfs_create_dir("wfd", NULL);
+
+	if (wfd_debugfs_root == ERR_PTR(-ENODEV))
+		return -ENODEV;
+	else if (!wfd_debugfs_root)
+		return -ENOMEM;
+	else
+		return 0;
+}
+
+void wfd_stats_teardown()
+{
+	if (wfd_debugfs_root)
+		debugfs_remove_recursive(wfd_debugfs_root);
+}
+
+int wfd_stats_init(struct wfd_stats *stats, int device)
+{
+	char device_str[NAME_MAX] = "";
+	int rc = 0;
+
+	if (!stats) {
+		rc = -EINVAL;
+		goto wfd_stats_init_fail;
+	} else if (!wfd_debugfs_root) {
+		WFD_MSG_ERR("wfd debugfs root does not exist\n");
+		rc = -ENOENT;
+		goto wfd_stats_init_fail;
+	}
+
+	memset(stats, 0, sizeof(*stats));
+	INIT_LIST_HEAD(&stats->enc_queue);
+
+	snprintf(device_str, sizeof(device_str), "%d", device);
+	stats->d_parent = debugfs_create_dir(device_str, wfd_debugfs_root);
+	if (IS_ERR(stats->d_parent)) {
+		rc = PTR_ERR(stats->d_parent);
+		stats->d_parent = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	stats->d_v4l2_buf_count = debugfs_create_u32("v4l2_buf_count", S_IRUGO,
+			stats->d_parent, &stats->v4l2_buf_count);
+	if (IS_ERR(stats->d_v4l2_buf_count)) {
+		rc = PTR_ERR(stats->d_v4l2_buf_count);
+		stats->d_v4l2_buf_count = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	stats->d_mdp_buf_count = debugfs_create_u32("mdp_buf_count", S_IRUGO,
+			stats->d_parent, &stats->mdp_buf_count);
+	if (IS_ERR(stats->d_mdp_buf_count)) {
+		rc = PTR_ERR(stats->d_mdp_buf_count);
+		stats->d_mdp_buf_count = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	stats->d_vsg_buf_count = debugfs_create_u32("vsg_buf_count", S_IRUGO,
+			stats->d_parent, &stats->vsg_buf_count);
+	if (IS_ERR(stats->d_vsg_buf_count)) {
+		rc = PTR_ERR(stats->d_vsg_buf_count);
+		stats->d_vsg_buf_count = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	stats->d_enc_buf_count = debugfs_create_u32("enc_buf_count", S_IRUGO,
+			stats->d_parent, &stats->enc_buf_count);
+	if (IS_ERR(stats->d_enc_buf_count)) {
+		rc = PTR_ERR(stats->d_enc_buf_count);
+		stats->d_enc_buf_count = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	stats->d_frames_encoded = debugfs_create_u32("frames_encoded", S_IRUGO,
+			stats->d_parent, &stats->frames_encoded);
+	if (IS_ERR(stats->d_frames_encoded)) {
+		rc = PTR_ERR(stats->d_frames_encoded);
+		stats->d_frames_encoded = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	stats->d_mdp_updates = debugfs_create_u32("mdp_updates", S_IRUGO,
+			stats->d_parent, &stats->mdp_updates);
+	if (IS_ERR(stats->d_mdp_updates)) {
+		rc = PTR_ERR(stats->d_mdp_updates);
+		stats->d_mdp_updates = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	stats->d_enc_avg_latency = debugfs_create_u32("enc_avg_latency",
+			S_IRUGO, stats->d_parent, &stats->enc_avg_latency);
+	if (IS_ERR(stats->d_enc_avg_latency)) {
+		rc = PTR_ERR(stats->d_enc_avg_latency);
+		stats->d_enc_avg_latency = NULL;
+		goto wfd_stats_init_fail;
+	}
+
+	return rc;
+wfd_stats_init_fail:
+	return rc;
+}
+
+int wfd_stats_update(struct wfd_stats *stats, enum wfd_stats_event event)
+{
+	int rc = 0;
+	switch (event) {
+	case WFD_STAT_EVENT_CLIENT_QUEUE:
+		stats->v4l2_buf_count++;
+		break;
+	case WFD_STAT_EVENT_CLIENT_DEQUEUE: {
+		struct wfd_stats_encode_sample *sample = NULL;
+
+		stats->v4l2_buf_count--;
+
+		if (!list_empty(&stats->enc_queue))
+			sample = list_first_entry(&stats->enc_queue,
+					struct wfd_stats_encode_sample,
+					list);
+		if (sample) {
+			ktime_t kdiff = ktime_sub(ktime_get(),
+						sample->encode_start_ts);
+			uint32_t diff = ktime_to_ms(kdiff);
+
+			stats->enc_cumulative_latency += diff;
+			stats->enc_latency_samples++;
+			stats->enc_avg_latency = stats->enc_cumulative_latency /
+				stats->enc_latency_samples;
+
+			list_del(&sample->list);
+			kfree(sample);
+			sample = NULL;
+		}
+		break;
+	}
+	case WFD_STAT_EVENT_MDP_QUEUE:
+		stats->mdp_buf_count++;
+		stats->mdp_updates++;
+		break;
+	case WFD_STAT_EVENT_MDP_DEQUEUE:
+		stats->mdp_buf_count--;
+		break;
+	case WFD_STAT_EVENT_ENC_QUEUE: {
+		struct wfd_stats_encode_sample *sample = NULL;
+
+		stats->enc_buf_count++;
+		stats->frames_encoded++;
+
+		sample = kzalloc(sizeof(*sample), GFP_KERNEL);
+		if (sample) {
+			INIT_LIST_HEAD(&sample->list);
+			sample->encode_start_ts = ktime_get();
+			list_add_tail(&sample->list, &stats->enc_queue);
+		} else {
+			WFD_MSG_WARN("Unable to measure latency\n");
+		}
+		break;
+	}
+	case WFD_STAT_EVENT_ENC_DEQUEUE:
+		stats->enc_buf_count--;
+		break;
+	case WFD_STAT_EVENT_VSG_QUEUE:
+		stats->vsg_buf_count++;
+		break;
+	case WFD_STAT_EVENT_VSG_DEQUEUE:
+		stats->vsg_buf_count--;
+		break;
+	default:
+		rc = -ENOTSUPP;
+	}
+
+	return rc;
+}
+
+int wfd_stats_deinit(struct wfd_stats *stats)
+{
+	WFD_MSG_ERR("Latencies: avg enc. latency %d",
+			stats->enc_avg_latency);
+	/* Delete all debugfs files in one shot :) */
+	if (stats->d_parent)
+		debugfs_remove_recursive(stats->d_parent);
+
+	stats->d_parent =
+	stats->d_v4l2_buf_count =
+	stats->d_mdp_buf_count =
+	stats->d_vsg_buf_count =
+	stats->d_enc_buf_count =
+	stats->d_frames_encoded =
+	stats->d_mdp_updates =
+	stats->d_enc_avg_latency = NULL;
+
+	return 0;
+}
diff --git a/drivers/media/video/msm/wfd/wfd-util.h b/drivers/media/video/msm/wfd/wfd-util.h
index 3fe03e6..b6bb245 100644
--- a/drivers/media/video/msm/wfd/wfd-util.h
+++ b/drivers/media/video/msm/wfd/wfd-util.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
@@ -11,6 +11,10 @@
  *
  */
 
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/ktime.h>
+
 #ifndef _WFD_UTIL_H_
 #define _WFD_UTIL_H_
 
@@ -20,12 +24,66 @@
 #ifdef DEBUG_WFD
 	#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
 	#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
-	#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
 #else
 	#define WFD_MSG_INFO(fmt...)
 	#define WFD_MSG_WARN(fmt...)
-	#define WFD_MSG_DBG(fmt...)
 #endif
 	#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
 	#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
+	#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
+
+
+struct wfd_stats_encode_sample {
+	ktime_t encode_start_ts;
+	struct list_head list;
+};
+
+struct wfd_stats {
+	/* Output Buffers */
+	uint32_t v4l2_buf_count;
+
+	/* Input Buffers */
+	uint32_t mdp_buf_count;
+	uint32_t vsg_buf_count;
+	uint32_t enc_buf_count;
+
+	/* Other */
+	uint32_t frames_encoded;
+	uint32_t mdp_updates;
+
+	uint32_t enc_avg_latency;
+	uint32_t enc_cumulative_latency;
+	uint32_t enc_latency_samples;
+	struct list_head enc_queue;
+
+	/* Debugfs entries */
+	struct dentry *d_parent;
+	struct dentry *d_v4l2_buf_count;
+	struct dentry *d_mdp_buf_count;
+	struct dentry *d_vsg_buf_count;
+	struct dentry *d_enc_buf_count;
+	struct dentry *d_frames_encoded;
+	struct dentry *d_mdp_updates;
+	struct dentry *d_enc_avg_latency;
+};
+
+enum wfd_stats_event {
+	WFD_STAT_EVENT_CLIENT_QUEUE,
+	WFD_STAT_EVENT_CLIENT_DEQUEUE,
+
+	WFD_STAT_EVENT_MDP_QUEUE,
+	WFD_STAT_EVENT_MDP_DEQUEUE,
+
+	WFD_STAT_EVENT_VSG_QUEUE,
+	WFD_STAT_EVENT_VSG_DEQUEUE,
+
+	WFD_STAT_EVENT_ENC_QUEUE,
+	WFD_STAT_EVENT_ENC_DEQUEUE,
+};
+
+int wfd_stats_setup(void);
+int wfd_stats_init(struct wfd_stats *, int device);
+int wfd_stats_update(struct wfd_stats *, enum wfd_stats_event);
+int wfd_stats_deinit(struct wfd_stats *);
+void wfd_stats_teardown(void);
 #endif
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index bdf19ad..e9babcb 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -36,7 +36,7 @@
 static struct fimc_fmt fimc_formats[] = {
 	{
 		.name		= "RGB565",
-		.fourcc		= V4L2_PIX_FMT_RGB565X,
+		.fourcc		= V4L2_PIX_FMT_RGB565,
 		.depth		= { 16 },
 		.color		= S5P_FIMC_RGB565,
 		.memplanes	= 1,
diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c
index 69822a4..c713691 100644
--- a/drivers/media/video/saa7164/saa7164-cards.c
+++ b/drivers/media/video/saa7164/saa7164-cards.c
@@ -203,6 +203,66 @@
 			.i2c_reg_len	= REGLEN_8bit,
 		} },
 	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2200_4] = {
+		.name		= "Hauppauge WinTV-HVR2200",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV3,
+		.unit		= {{
+			.id		= 0x1d,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x05,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1b,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1c,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1e,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x10 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1f,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x12 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
 	[SAA7164_BOARD_HAUPPAUGE_HVR2250] = {
 		.name		= "Hauppauge WinTV-HVR2250",
 		.porta		= SAA7164_MPEG_DVB,
@@ -426,6 +486,10 @@
 		.subvendor = 0x0070,
 		.subdevice = 0x8851,
 		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2250_2,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8940,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2200_4,
 	},
 };
 const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids);
@@ -469,6 +533,7 @@
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2250:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2250_3:
@@ -549,6 +614,7 @@
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2250:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2250_3:
diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c
index f65eab6..d377937 100644
--- a/drivers/media/video/saa7164/saa7164-dvb.c
+++ b/drivers/media/video/saa7164/saa7164-dvb.c
@@ -475,6 +475,7 @@
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
 	case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
 		i2c_bus = &dev->i2c_bus[port->nr + 1];
 		switch (port->nr) {
 		case 0:
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h
index 16745d2..13bd27e 100644
--- a/drivers/media/video/saa7164/saa7164.h
+++ b/drivers/media/video/saa7164/saa7164.h
@@ -83,6 +83,7 @@
 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_3	6
 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2	7
 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3	8
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_4	9
 
 #define SAA7164_MAX_UNITS		8
 #define SAA7164_TS_NUMBER_OF_LINES	312
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index b6eae48..1f962dc 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1960,7 +1960,7 @@
 
 	list_for_each_entry(stream, &dev->streams, list) {
 		if (stream->intf == intf)
-			return uvc_video_resume(stream);
+			return uvc_video_resume(stream, reset);
 	}
 
 	uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 543a803..dbefdb0 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -65,6 +65,15 @@
 			goto done;
 		}
 
+		/* Prevent excessive memory consumption, as well as integer
+		 * overflows.
+		 */
+		if (xmap->menu_count == 0 ||
+		    xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
+			ret = -EINVAL;
+			goto done;
+		}
+
 		size = xmap->menu_count * sizeof(*map->menu_info);
 		map->menu_info = kmalloc(size, GFP_KERNEL);
 		if (map->menu_info == NULL) {
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 4999479..6f147de 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -1104,10 +1104,18 @@
  * buffers, making sure userspace applications are notified of the problem
  * instead of waiting forever.
  */
-int uvc_video_resume(struct uvc_streaming *stream)
+int uvc_video_resume(struct uvc_streaming *stream, int reset)
 {
 	int ret;
 
+	/* If the bus has been reset on resume, set the alternate setting to 0.
+	 * This should be the default value, but some devices crash or otherwise
+	 * misbehave if they don't receive a SET_INTERFACE request before any
+	 * other video control request.
+	 */
+	if (reset)
+		usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+
 	stream->frozen = 0;
 
 	ret = uvc_commit_video(stream, &stream->ctrl);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 20107fd..cf2401a 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -200,6 +200,7 @@
 
 /* Maximum allowed number of control mappings per device */
 #define UVC_MAX_CONTROL_MAPPINGS	1024
+#define UVC_MAX_CONTROL_MENU_ENTRIES	32
 
 /* Devices quirks */
 #define UVC_QUIRK_STATUS_INTERVAL	0x00000001
@@ -639,7 +640,7 @@
 /* Video */
 extern int uvc_video_init(struct uvc_streaming *stream);
 extern int uvc_video_suspend(struct uvc_streaming *stream);
-extern int uvc_video_resume(struct uvc_streaming *stream);
+extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
 extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
 extern int uvc_probe_video(struct uvc_streaming *stream,
 		struct uvc_streaming_control *probe);
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 69e8c6f..bda252f 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -2289,6 +2289,10 @@
 		struct v4l2_ext_controls *ctrls = parg;
 
 		if (ctrls->count != 0) {
+			if (ctrls->count > V4L2_CID_MAX_CTRLS) {
+				ret = -EINVAL;
+				break;
+			}
 			*user_ptr = (void __user *)ctrls->controls;
 			*kernel_ptr = (void **)&ctrls->controls;
 			*array_size = sizeof(struct v4l2_ext_control)
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index c12bed3..7782955 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -45,9 +45,9 @@
 #define D(fmt, args...) do {} while (0)
 #endif
 
-static int32_t msm_mem_allocate(struct videobuf2_contig_pmem *mem)
+static unsigned long msm_mem_allocate(struct videobuf2_contig_pmem *mem)
 {
-	int32_t phyaddr;
+	unsigned long phyaddr;
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	int rc, len;
 	mem->client = msm_ion_client_create(-1, "camera");
@@ -61,8 +61,10 @@
 		pr_err("%s Could not allocate\n", __func__);
 		goto alloc_failed;
 	}
-	rc = ion_phys(mem->client, mem->ion_handle, (ion_phys_addr_t *)&phyaddr,
-		 (size_t *)&len);
+	rc = ion_map_iommu(mem->client, mem->ion_handle,
+			CAMERA_DOMAIN, GEN_POOL, SZ_4K, 0,
+			(unsigned long *)&phyaddr,
+			(unsigned long *)&len, UNCACHED, 0);
 	if (rc < 0) {
 		pr_err("%s Could not get physical address\n", __func__);
 		goto phys_failed;
@@ -85,6 +87,7 @@
 {
 	int32_t rc = 0;
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(mem->client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL);
 	ion_free(mem->client, mem->ion_handle);
 	ion_client_destroy(mem->client);
 #else
@@ -116,8 +119,6 @@
 static void *msm_vb2_mem_ops_alloc(void *alloc_ctx, unsigned long size)
 {
 	struct videobuf2_contig_pmem *mem;
-	unsigned int flags = 0;
-	long rc;
 	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
 	if (!mem)
 		return ERR_PTR(-ENOMEM);
@@ -132,18 +133,7 @@
 		kfree(mem);
 		return ERR_PTR(-ENOMEM);
 	}
-	flags = MSM_SUBSYSTEM_MAP_IOVA;
-	mem->subsys_id = MSM_SUBSYSTEM_CAMERA;
-	mem->msm_buffer = msm_subsystem_map_buffer(mem->phyaddr, mem->size,
-					flags, &(mem->subsys_id), 1);
-	if (IS_ERR((void *)mem->msm_buffer)) {
-		pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
-		rc = PTR_ERR((void *)mem->msm_buffer);
-		msm_mem_free(mem);
-		kfree(mem);
-		return ERR_PTR(-ENOMEM);
-	}
-	mem->mapped_phyaddr = mem->msm_buffer->iova[0];
+	mem->mapped_phyaddr = mem->phyaddr;
 	return mem;
 }
 static void msm_vb2_mem_ops_put(void *buf_priv)
@@ -151,8 +141,6 @@
 	struct videobuf2_contig_pmem *mem = buf_priv;
 	if (!mem->is_userptr) {
 		D("%s Freeing memory ", __func__);
-		if (msm_subsystem_unmap_buffer(mem->msm_buffer) < 0)
-			D("%s unmapped memory\n", __func__);
 		msm_mem_free(mem);
 	}
 	kfree(mem);
@@ -193,7 +181,6 @@
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	unsigned long kvstart;
 #endif
-	unsigned int flags = 0;
 	unsigned long paddr = 0;
 	if (mem->phyaddr != 0)
 		return 0;
@@ -203,8 +190,10 @@
 		pr_err("%s ION import failed\n", __func__);
 		return PTR_ERR(mem->ion_handle);
 	}
-	rc = ion_phys(client, mem->ion_handle, (ion_phys_addr_t *)&mem->phyaddr,
-			 (size_t *)&len);
+	rc = ion_map_iommu(client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL,
+		SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0);
+	if (rc < 0)
+		ion_free(client, mem->ion_handle);
 #elif CONFIG_ANDROID_PMEM
 	rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr,
 					&kvstart, &len, &mem->file);
@@ -224,20 +213,6 @@
 	mem->path = path;
 	mem->buffer_type = buffer_type;
 	paddr = mem->phyaddr;
-	flags = MSM_SUBSYSTEM_MAP_IOVA;
-	mem->subsys_id = MSM_SUBSYSTEM_CAMERA;
-	mem->msm_buffer = msm_subsystem_map_buffer(mem->phyaddr, len,
-					flags, &(mem->subsys_id), 1);
-	if (IS_ERR((void *)mem->msm_buffer)) {
-		pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		ion_free(client, mem->ion_handle);
-#elif CONFIG_ANDROID_PMEM
-		put_pmem_file(mem->file);
-#endif
-		return PTR_ERR((void *)mem->msm_buffer);
-	}
-	paddr = mem->msm_buffer->iova[0];
 	mem->mapped_phyaddr = paddr + addr_offset;
 	mem->addr_offset = addr_offset;
 	return rc;
@@ -247,10 +222,10 @@
 void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem,
 					struct ion_client *client)
 {
-	if (msm_subsystem_unmap_buffer(mem->msm_buffer) < 0)
-		D("%s unmapped memory\n", __func__);
 	if (mem->is_userptr) {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		ion_unmap_iommu(client, mem->ion_handle,
+				CAMERA_DOMAIN, GEN_POOL);
 		ion_free(client, mem->ion_handle);
 #elif CONFIG_ANDROID_PMEM
 		put_pmem_file(mem->file);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 77ac845..54e1b9a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -879,6 +879,16 @@
 	  voltage leaves the accepatable range which then calls a notifier call
 	  chain.
 
+config WCD9304_CODEC
+        tristate "WCD9304 Codec"
+        select SLIMBUS
+        select MFD_CORE
+        default n
+        help
+          Enables the WCD9304 core driver. The core driver provides
+          read/write capability to registers which are part of the
+          WCD9304 core and gives the ability to use the WCD9304 codec.
+
 config WCD9310_CODEC
         tristate "WCD9310 Codec"
         select SLIMBUS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c8fcf5f..fd887ea 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -69,7 +69,8 @@
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
 obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-ts.o
 
-obj-$(CONFIG_WCD9310_CODEC)       += wcd9310-core.o wcd9310-irq.o wcd9310-slimslave.o
+obj-$(CONFIG_WCD9310_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
+obj-$(CONFIG_WCD9304_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
 
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index 5c4b705..041815776 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -230,6 +230,30 @@
 	.id		= -1,
 };
 
+static const struct resource thermal_alarm_cell_resources[] __devinitconst = {
+	SINGLE_IRQ_RESOURCE("pm8018_tempstat_irq", PM8018_TEMPSTAT_IRQ),
+	SINGLE_IRQ_RESOURCE("pm8018_overtemp_irq", PM8018_OVERTEMP_IRQ),
+};
+
+static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
+	.adc_channel =			CHANNEL_DIE_TEMP,
+	.adc_type =			PM8XXX_TM_ADC_PM8XXX_ADC,
+	.reg_addr_temp_alarm_ctrl =	REG_TEMP_ALARM_CTRL,
+	.reg_addr_temp_alarm_pwm =	REG_TEMP_ALARM_PWM,
+	.tm_name =			"pm8018_tz",
+	.irq_name_temp_stat =		"pm8018_tempstat_irq",
+	.irq_name_over_temp =		"pm8018_overtemp_irq",
+};
+
+static struct mfd_cell thermal_alarm_cell __devinitdata = {
+	.name		= PM8XXX_TM_DEV_NAME,
+	.id		= -1,
+	.resources	= thermal_alarm_cell_resources,
+	.num_resources	= ARRAY_SIZE(thermal_alarm_cell_resources),
+	.platform_data	= &thermal_alarm_cdata,
+	.pdata_size	= sizeof(struct pm8xxx_tm_core_data),
+};
+
 static struct pm8xxx_vreg regulator_data[] = {
 	/*   name	     pc_name	    ctrl   test   hpm_min */
 	PLDO("8018_l2",      "8018_l2_pc",  0x0B0, 0x0B1, LDO_50),
@@ -260,7 +284,7 @@
 #define MAX_NAME_COMPARISON_LEN 32
 
 static int __devinit match_regulator(
-	struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+	struct pm8xxx_regulator_core_platform_data *core_data, const char *name)
 {
 	int found = 0;
 	int i;
@@ -475,6 +499,12 @@
 		}
 	}
 
+	ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
+				irq_base);
+	if (ret) {
+		pr_err("Failed to add thermal alarm subdevice, ret=%d\n", ret);
+		goto bail;
+	}
 
 	return 0;
 bail:
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index ac57418..b03b7ac 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -326,7 +326,7 @@
 #define MAX_NAME_COMPARISON_LEN 32
 
 static int __devinit match_regulator(
-	struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+	struct pm8xxx_regulator_core_platform_data *core_data, const char *name)
 {
 	int found = 0;
 	int i;
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 6be3f2d..0f41ba7 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -427,10 +427,28 @@
 	NCP("8921_ncp", 0x090),
 };
 
+/*
+ * PM8917 adds 6 LDOs and a boost regulator beyond those available on PM8921.
+ * It also replaces SMPS 3 with FTSMPS 3.  PM8917 does not have an NCP.
+ */
+static struct pm8xxx_vreg pm8917_regulator_data[] = {
+	/*   name	     pc_name	    ctrl   test   hpm_min */
+	PLDO("8917_l30",     "8917_l30_pc", 0x0A3, 0x0A4, LDO_150),
+	PLDO("8917_l31",     "8917_l31_pc", 0x0A5, 0x0A6, LDO_150),
+	PLDO("8917_l32",     "8917_l32_pc", 0x0A7, 0x0A8, LDO_150),
+	PLDO("8917_l33",     "8917_l33_pc", 0x0C6, 0x0C7, LDO_150),
+	PLDO("8917_l34",     "8917_l34_pc", 0x0D2, 0x0D3, LDO_150),
+	PLDO("8917_l35",     "8917_l35_pc", 0x0D4, 0x0D5, LDO_300),
+	PLDO("8917_l36",     "8917_l36_pc", 0x0A9, 0x0AA, LDO_50),
+
+	/*    name          ctrl */
+	BOOST("8917_boost", 0x04B),
+};
+
 #define MAX_NAME_COMPARISON_LEN 32
 
-static int __devinit match_regulator(
-	struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+static int __devinit match_regulator(enum pm8xxx_version version,
+	struct pm8xxx_regulator_core_platform_data *core_data, const char *name)
 {
 	int found = 0;
 	int i;
@@ -452,6 +470,25 @@
 			break;
 		}
 	}
+	if (version == PM8XXX_VERSION_8917) {
+		for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++) {
+			if (pm8917_regulator_data[i].rdesc.name
+			    && strncmp(pm8917_regulator_data[i].rdesc.name,
+					name, MAX_NAME_COMPARISON_LEN) == 0) {
+				core_data->is_pin_controlled = false;
+				core_data->vreg = &pm8917_regulator_data[i];
+				found = 1;
+				break;
+			} else if (pm8917_regulator_data[i].rdesc_pc.name
+			      && strncmp(pm8917_regulator_data[i].rdesc_pc.name,
+					name, MAX_NAME_COMPARISON_LEN) == 0) {
+				core_data->is_pin_controlled = true;
+				core_data->vreg = &pm8917_regulator_data[i];
+				found = 1;
+				break;
+			}
+		}
+	}
 
 	if (!found)
 		pr_err("could not find a match for regulator: %s\n", name);
@@ -466,8 +503,11 @@
 	int ret = 0;
 	struct mfd_cell *mfd_regulators;
 	struct pm8xxx_regulator_core_platform_data *cdata;
+	enum pm8xxx_version version;
 	int i;
 
+	version = pm8xxx_get_version(pmic->dev);
+
 	/* Add one device for each regulator used by the board. */
 	mfd_regulators = kzalloc(sizeof(struct mfd_cell)
 				 * (pdata->num_regulators), GFP_KERNEL);
@@ -488,6 +528,8 @@
 	}
 	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
 		mutex_init(&regulator_data[i].pc_lock);
+	for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+		mutex_init(&pm8917_regulator_data[i].pc_lock);
 
 	for (i = 0; i < pdata->num_regulators; i++) {
 		if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
@@ -495,7 +537,7 @@
 			ret = -EINVAL;
 			goto bail;
 		}
-		if (!match_regulator(&cdata[i],
+		if (!match_regulator(version, &cdata[i],
 		      pdata->regulator_pdatas[i].init_data.constraints.name)) {
 			ret = -ENODEV;
 			goto bail;
@@ -519,6 +561,8 @@
 bail:
 	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
 		mutex_destroy(&regulator_data[i].pc_lock);
+	for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+		mutex_destroy(&pm8917_regulator_data[i].pc_lock);
 	kfree(mfd_regulators);
 	kfree(cdata);
 	return ret;
@@ -711,6 +755,11 @@
 	}
 
 	if (version != PM8XXX_VERSION_8917) {
+		if (pdata->pwm_pdata) {
+			pwm_cell.platform_data = pdata->pwm_pdata;
+			pwm_cell.pdata_size =
+				sizeof(struct pm8xxx_pwm_platform_data);
+		}
 		ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
 		if (ret) {
 			pr_err("Failed to add pwm subdevice ret=%d\n", ret);
@@ -908,6 +957,9 @@
 		if (pmic->mfd_regulators) {
 			for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
 				mutex_destroy(&regulator_data[i].pc_lock);
+			for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+				mutex_destroy(
+					&pm8917_regulator_data[i].pc_lock);
 		}
 		kfree(pmic->mfd_regulators);
 		kfree(pmic->regulator_cdata);
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index 14c9ec4..ac39e80 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -102,6 +102,7 @@
 		goto bail;
 	}
 
+	cp &= ~PM_IRQF_WRITE;
 	rc = pm8xxx_writeb(chip->dev,
 			SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
 	if (rc)
@@ -127,7 +128,10 @@
 		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
 		goto bail;
 	}
-
+	/*
+	 * Set the write bit here as this could be a unrequested irq
+	 * whose PM_IRQF_WRITE bit is not set
+	 */
 	cp |= PM_IRQF_WRITE;
 	rc = pm8xxx_writeb(chip->dev,
 			SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
@@ -222,7 +226,7 @@
 	irq_bit = pmirq % 8;
 
 	if (chip->config[pmirq] == 0) {
-		pr_warn("masking rouge irq=%d pmirq=%d\n", d->irq, pmirq);
+		pr_warn("masking rogue irq=%d pmirq=%d\n", d->irq, pmirq);
 		chip->config[pmirq] = irq_bit << PM_IRQF_BITS_SHIFT;
 	}
 
@@ -242,7 +246,7 @@
 	irq_bit = pmirq % 8;
 
 	if (chip->config[pmirq] == 0) {
-		pr_warn("mask acking rouge irq=%d pmirq=%d\n", d->irq, pmirq);
+		pr_warn("mask acking rogue irq=%d pmirq=%d\n", d->irq, pmirq);
 		chip->config[pmirq] = irq_bit << PM_IRQF_BITS_SHIFT;
 	}
 
@@ -295,6 +299,12 @@
 			chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
 	}
 
+	/*
+	 * The PM_IRQF_WRITE flag serves as an indication that this interrupt
+	 * been requested
+	 */
+	chip->config[pmirq] |= PM_IRQF_WRITE;
+
 	config = chip->config[pmirq] | PM_IRQF_CLR;
 	return pm8xxx_write_config_irq(chip, block, config);
 }
@@ -439,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-misc.c b/drivers/mfd/pm8xxx-misc.c
index b655848..64c0bd1 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -999,6 +999,10 @@
 {
 	int rc;
 
+	/* dVdd preloading is not needed for PMIC PM8901 rev 2.3 and beyond. */
+	if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8901_2p3)
+		return 0;
+
 	rc = pm8xxx_writeb(chip->dev->parent, 0x0BD, 0x0F);
 	if (rc)
 		pr_err("pm8xxx_writeb failed for 0x0BD, rc=%d\n", rc);
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index 05f02c4..022cfb6 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -64,6 +64,7 @@
 #define SSBI_REG_ADDR_LPG_BANK_EN	0x144
 #define SSBI_REG_ADDR_LPG_LUT_CFG0	0x145
 #define SSBI_REG_ADDR_LPG_LUT_CFG1	0x146
+#define SSBI_REG_ADDR_LPG_TEST		0x147
 
 /* LPG Control 0 */
 #define PM8XXX_PWM_1KHZ_COUNT_MASK	0xF0
@@ -137,6 +138,10 @@
 /* LPG LUT_CFG1 */
 #define PM8XXX_PWM_LUT_READ			0x40
 
+/* TEST */
+#define PM8XXX_PWM_DTEST_MASK		0x38
+#define PM8XXX_PWM_DTEST_SHIFT		3
+#define PM8XXX_PWM_DTEST_BANK_MASK	0x07
 
 /*
  * PWM Frequency = Clock Frequency / (N * T)
@@ -200,6 +205,7 @@
 	int			irq;
 	struct pm8xxx_pwm_chip	*chip;
 	int			bypass_lut;
+	int			dtest_mode_supported;
 };
 
 struct pm8xxx_pwm_chip {
@@ -638,6 +644,28 @@
 	return rc;
 }
 
+static int pm8xxx_pwm_set_dtest(struct pwm_device *pwm, int enable)
+{
+	int	rc;
+	u8	reg;
+
+	reg = pwm->pwm_id & PM8XXX_PWM_DTEST_BANK_MASK;
+
+	if (enable) {
+		/* Observe LPG_OUT on DTEST1*/
+		reg |= (1 << PM8XXX_PWM_DTEST_SHIFT) &
+				PM8XXX_PWM_DTEST_MASK;
+	}
+
+	rc = pm8xxx_writeb(pwm->chip->dev->parent,
+			SSBI_REG_ADDR_LPG_TEST, reg);
+	if (rc)
+		pr_err("pm8xxx_write(DTEST=0x%x) failed: rc=%d\n",
+							reg, rc);
+
+	return rc;
+}
+
 /* APIs */
 /**
  * pwm_request - request a PWM device
@@ -785,6 +813,8 @@
 		rc = -EINVAL;
 	} else {
 		if (pwm_chip->is_lpg_supported) {
+			if (pwm->dtest_mode_supported)
+				pm8xxx_pwm_set_dtest(pwm, 1);
 			rc = pm8xxx_pwm_bank_enable(pwm, 1);
 			pm8xxx_pwm_bank_sel(pwm);
 			pm8xxx_pwm_start(pwm, 1, 0);
@@ -811,6 +841,8 @@
 	mutex_lock(&pwm->chip->pwm_mutex);
 	if (pwm->in_use) {
 		if (pwm_chip->is_lpg_supported) {
+			if (pwm->dtest_mode_supported)
+				pm8xxx_pwm_set_dtest(pwm, 0);
 			pm8xxx_pwm_bank_sel(pwm);
 			pm8xxx_pwm_start(pwm, 0, 0);
 			pm8xxx_pwm_bank_enable(pwm, 0);
@@ -1030,11 +1062,17 @@
 
 	mutex_lock(&pwm->chip->pwm_mutex);
 	if (start) {
+		if (pwm->dtest_mode_supported)
+			pm8xxx_pwm_set_dtest(pwm, 1);
+
 		pm8xxx_pwm_bank_enable(pwm, 1);
 
 		pm8xxx_pwm_bank_sel(pwm);
 		pm8xxx_pwm_start(pwm, 1, 1);
 	} else {
+		if (pwm->dtest_mode_supported)
+			pm8xxx_pwm_set_dtest(pwm, 0);
+
 		pm8xxx_pwm_bank_sel(pwm);
 		pm8xxx_pwm_start(pwm, 0, 0);
 
@@ -1324,8 +1362,9 @@
 
 static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
 {
+	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);
@@ -1334,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;
@@ -1374,6 +1418,8 @@
 	for (i = 0; i < chip->pwm_channels; i++) {
 		chip->pwm_dev[i].pwm_id = i;
 		chip->pwm_dev[i].chip = chip;
+		if (i == dtest_channel)
+			chip->pwm_dev[i].dtest_mode_supported = 1;
 	}
 
 	platform_set_drvdata(pdev, chip);
diff --git a/drivers/mfd/pmic8901.c b/drivers/mfd/pmic8901.c
index 080a3e3..63ea55a 100644
--- a/drivers/mfd/pmic8901.c
+++ b/drivers/mfd/pmic8901.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
@@ -270,11 +270,23 @@
 	return rc;
 }
 
-static int pm8901_probe(struct platform_device *pdev)
+static const char * const pm8901_rev_names[] = {
+	[PM8XXX_REVISION_8901_TEST]	= "test",
+	[PM8XXX_REVISION_8901_1p0]	= "1.0",
+	[PM8XXX_REVISION_8901_1p1]	= "1.1",
+	[PM8XXX_REVISION_8901_2p0]	= "2.0",
+	[PM8XXX_REVISION_8901_2p1]	= "2.1",
+	[PM8XXX_REVISION_8901_2p2]	= "2.2",
+	[PM8XXX_REVISION_8901_2p3]	= "2.3",
+};
+
+static int __devinit pm8901_probe(struct platform_device *pdev)
 {
 	int rc;
 	struct pm8901_platform_data *pdata = pdev->dev.platform_data;
+	const char *revision_name = "unknown";
 	struct pm8901_chip *pmic;
+	int revision;
 
 	if (pdata == NULL) {
 		pr_err("%s: No platform_data or IRQ.\n", __func__);
@@ -298,7 +310,11 @@
 		pr_err("%s: Failed reading version register rc=%d.\n",
 			__func__, rc);
 
-	pr_info("%s: PMIC REVISION = %X\n", __func__, pmic->revision);
+	pr_info("%s: PMIC revision reg: %02X\n", __func__, pmic->revision);
+	revision =  pm8xxx_get_revision(pmic->dev);
+	if (revision >= 0 && revision < ARRAY_SIZE(pm8901_rev_names))
+		revision_name = pm8901_rev_names[revision];
+	pr_info("%s: PMIC version: PM8901 rev %s\n", __func__, revision_name);
 
 	(void) memcpy((void *)&pmic->pdata, (const void *)pdata,
 		      sizeof(pmic->pdata));
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index a2eddc7..ec5c76d 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -362,13 +362,13 @@
 		pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
 		return -EPERM;
 	}
+	if (unlikely(!inuse)) {
+		pr_err("%s: not initialized\n", DRIVER_NAME);
+		return -EPERM;
+	}
 	sid = twl_map[mod_no].sid;
 	twl = &twl_modules[sid];
 
-	if (unlikely(!inuse)) {
-		pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
-		return -EPERM;
-	}
 	mutex_lock(&twl->xfer_lock);
 	/*
 	 * [MSG1]: fill the register address data
@@ -419,13 +419,13 @@
 		pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
 		return -EPERM;
 	}
+	if (unlikely(!inuse)) {
+		pr_err("%s: not initialized\n", DRIVER_NAME);
+		return -EPERM;
+	}
 	sid = twl_map[mod_no].sid;
 	twl = &twl_modules[sid];
 
-	if (unlikely(!inuse)) {
-		pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
-		return -EPERM;
-	}
 	mutex_lock(&twl->xfer_lock);
 	/* [MSG1] fill the register address data */
 	msg = &twl->xfer_msg[0];
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index 3941ddc..834f824 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -510,8 +510,9 @@
 	u8 ch_msb, ch_lsb;
 	int ret;
 
-	if (!req)
+	if (!req || !twl4030_madc)
 		return -EINVAL;
+
 	mutex_lock(&twl4030_madc->lock);
 	if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
 		ret = -EINVAL;
@@ -530,13 +531,13 @@
 	if (ret) {
 		dev_err(twl4030_madc->dev,
 			"unable to write sel register 0x%X\n", method->sel + 1);
-		return ret;
+		goto out;
 	}
 	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
 	if (ret) {
 		dev_err(twl4030_madc->dev,
 			"unable to write sel register 0x%X\n", method->sel + 1);
-		return ret;
+		goto out;
 	}
 	/* Select averaging for all channels if do_avg is set */
 	if (req->do_avg) {
@@ -546,7 +547,7 @@
 			dev_err(twl4030_madc->dev,
 				"unable to write avg register 0x%X\n",
 				method->avg + 1);
-			return ret;
+			goto out;
 		}
 		ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
 				       ch_lsb, method->avg);
@@ -554,7 +555,7 @@
 			dev_err(twl4030_madc->dev,
 				"unable to write sel reg 0x%X\n",
 				method->sel + 1);
-			return ret;
+			goto out;
 		}
 	}
 	if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
@@ -706,6 +707,8 @@
 	if (!madc)
 		return -ENOMEM;
 
+	madc->dev = &pdev->dev;
+
 	/*
 	 * Phoenix provides 2 interrupt lines. The first one is connected to
 	 * the OMAP. The other one can be connected to the other processor such
@@ -737,6 +740,28 @@
 			TWL4030_BCI_BCICTL1);
 		goto err_i2c;
 	}
+
+	/* Check that MADC clock is on */
+	ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
+				TWL4030_REG_GPBR1);
+		goto err_i2c;
+	}
+
+	/* If MADC clk is not on, turn it on */
+	if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
+		dev_info(&pdev->dev, "clk disabled, enabling\n");
+		regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
+		ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
+				       TWL4030_REG_GPBR1);
+		if (ret) {
+			dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
+					TWL4030_REG_GPBR1);
+			goto err_i2c;
+		}
+	}
+
 	platform_set_drvdata(pdev, madc);
 	mutex_init(&madc->lock);
 	ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
deleted file mode 100644
index 56774e9..0000000
--- a/drivers/mfd/wcd9310-core.c
+++ /dev/null
@@ -1,1166 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/wcd9310/pdata.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/debugfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/i2c.h>
-#include <sound/soc.h>
-
-#define TABLA_SLIM_GLA_MAX_RETRIES 5
-#define TABLA_REGISTER_START_OFFSET 0x800
-#define TABLA_SLIM_RW_MAX_TRIES 3
-
-#define MAX_TABLA_DEVICE	4
-#define TABLA_I2C_MODE	0x03
-
-struct tabla_i2c {
-	struct i2c_client *client;
-	struct i2c_msg xfer_msg[2];
-	struct mutex xfer_lock;
-	int mod_id;
-};
-
-struct tabla_i2c tabla_modules[MAX_TABLA_DEVICE];
-static int tabla_intf;
-
-static int tabla_read(struct tabla *tabla, unsigned short reg,
-		       int bytes, void *dest, bool interface_reg)
-{
-	int ret;
-	u8 *buf = dest;
-
-	if (bytes <= 0) {
-		dev_err(tabla->dev, "Invalid byte read length %d\n", bytes);
-		return -EINVAL;
-	}
-
-	ret = tabla->read_dev(tabla, reg, bytes, dest, interface_reg);
-	if (ret < 0) {
-		dev_err(tabla->dev, "Tabla read failed\n");
-		return ret;
-	} else
-		dev_dbg(tabla->dev, "Read 0x%02x from R%d(0x%x)\n",
-			 *buf, reg, reg);
-
-	return 0;
-}
-int tabla_reg_read(struct tabla *tabla, unsigned short reg)
-{
-	u8 val;
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_read(tabla, reg, 1, &val, false);
-	mutex_unlock(&tabla->io_lock);
-
-	if (ret < 0)
-		return ret;
-	else
-		return val;
-}
-EXPORT_SYMBOL_GPL(tabla_reg_read);
-
-static int tabla_write(struct tabla *tabla, unsigned short reg,
-			int bytes, void *src, bool interface_reg)
-{
-	u8 *buf = src;
-
-	if (bytes <= 0) {
-		pr_err("%s: Error, invalid write length\n", __func__);
-		return -EINVAL;
-	}
-
-	dev_dbg(tabla->dev, "Write %02x to R%d(0x%x)\n",
-		 *buf, reg, reg);
-
-	return tabla->write_dev(tabla, reg, bytes, src, interface_reg);
-}
-
-int tabla_reg_write(struct tabla *tabla, unsigned short reg,
-		     u8 val)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_write(tabla, reg, 1, &val, false);
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_reg_write);
-
-static u8 tabla_pgd_la;
-static u8 tabla_inf_la;
-
-int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la)
-{
-	*pgd_la = tabla_pgd_la;
-	*inf_la = tabla_inf_la;
-	return 0;
-
-}
-EXPORT_SYMBOL_GPL(tabla_get_logical_addresses);
-
-int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg)
-{
-	u8 val;
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_read(tabla, reg, 1, &val, true);
-	mutex_unlock(&tabla->io_lock);
-
-	if (ret < 0)
-		return ret;
-	else
-		return val;
-}
-EXPORT_SYMBOL_GPL(tabla_interface_reg_read);
-
-int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg,
-		     u8 val)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_write(tabla, reg, 1, &val, true);
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_interface_reg_write);
-
-int tabla_bulk_read(struct tabla *tabla, unsigned short reg,
-		     int count, u8 *buf)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-
-	ret = tabla_read(tabla, reg, count, buf, false);
-
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_bulk_read);
-
-int tabla_bulk_write(struct tabla *tabla, unsigned short reg,
-		     int count, u8 *buf)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-
-	ret = tabla_write(tabla, reg, count, buf, false);
-
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_bulk_write);
-
-static int tabla_slim_read_device(struct tabla *tabla, unsigned short reg,
-				int bytes, void *dest, bool interface)
-{
-	int ret;
-	struct slim_ele_access msg;
-	int slim_read_tries = TABLA_SLIM_RW_MAX_TRIES;
-	msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
-	msg.num_bytes = bytes;
-	msg.comp = NULL;
-
-	while (1) {
-		mutex_lock(&tabla->xfer_lock);
-		ret = slim_request_val_element(interface ?
-					       tabla->slim_slave : tabla->slim,
-					       &msg, dest, bytes);
-		mutex_unlock(&tabla->xfer_lock);
-		if (likely(ret == 0) || (--slim_read_tries == 0))
-			break;
-		usleep_range(5000, 5000);
-	}
-
-	if (ret)
-		pr_err("%s: Error, Tabla read failed (%d)\n", __func__, ret);
-
-	return ret;
-}
-/* Interface specifies whether the write is to the interface or general
- * registers.
- */
-static int tabla_slim_write_device(struct tabla *tabla, unsigned short reg,
-				   int bytes, void *src, bool interface)
-{
-	int ret;
-	struct slim_ele_access msg;
-	int slim_write_tries = TABLA_SLIM_RW_MAX_TRIES;
-	msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
-	msg.num_bytes = bytes;
-	msg.comp = NULL;
-
-	while (1) {
-		mutex_lock(&tabla->xfer_lock);
-		ret = slim_change_val_element(interface ?
-					      tabla->slim_slave : tabla->slim,
-					      &msg, src, bytes);
-		mutex_unlock(&tabla->xfer_lock);
-		if (likely(ret == 0) || (--slim_write_tries == 0))
-			break;
-		usleep_range(5000, 5000);
-	}
-
-	if (ret)
-		pr_err("%s: Error, Tabla write failed (%d)\n", __func__, ret);
-
-	return ret;
-}
-
-static struct mfd_cell tabla_devs[] = {
-	{
-		.name = "tabla_codec",
-	},
-};
-
-static struct mfd_cell tabla1x_devs[] = {
-	{
-		.name = "tabla1x_codec",
-	},
-};
-
-static void tabla_bring_up(struct tabla *tabla)
-{
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x4);
-	tabla_reg_write(tabla, TABLA_A_CDC_CTL, 0);
-	usleep_range(5000, 5000);
-	tabla_reg_write(tabla, TABLA_A_CDC_CTL, 3);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 3);
-}
-
-static void tabla_bring_down(struct tabla *tabla)
-{
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x7);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x6);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0xe);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x8);
-}
-
-static int tabla_reset(struct tabla *tabla)
-{
-	int ret;
-	struct pm_gpio param = {
-		.direction      = PM_GPIO_DIR_OUT,
-		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
-		.output_value   = 1,
-		.pull	   = PM_GPIO_PULL_NO,
-		.vin_sel	= PM_GPIO_VIN_S4,
-		.out_strength   = PM_GPIO_STRENGTH_MED,
-		.function       = PM_GPIO_FUNC_NORMAL,
-	};
-
-	if (tabla->reset_gpio) {
-		ret = gpio_request(tabla->reset_gpio, "CDC_RESET");
-		if (ret) {
-			pr_err("%s: Failed to request gpio %d\n", __func__,
-				tabla->reset_gpio);
-			tabla->reset_gpio = 0;
-			return ret;
-		}
-
-		ret = pm8xxx_gpio_config(tabla->reset_gpio, &param);
-		if (ret)
-			pr_err("%s: Failed to configure gpio\n", __func__);
-
-		gpio_direction_output(tabla->reset_gpio, 1);
-		msleep(20);
-		gpio_direction_output(tabla->reset_gpio, 0);
-		msleep(20);
-		gpio_direction_output(tabla->reset_gpio, 1);
-		msleep(20);
-	}
-	return 0;
-}
-
-static void tabla_free_reset(struct tabla *tabla)
-{
-	if (tabla->reset_gpio) {
-		gpio_free(tabla->reset_gpio);
-		tabla->reset_gpio = 0;
-	}
-}
-
-struct tabla_regulator {
-	const char *name;
-	int min_uV;
-	int max_uV;
-	int optimum_uA;
-	struct regulator *regulator;
-};
-
-
-/*
- *	format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
- *
- *	<POWER_SUPPLY_PIN_NAME> from Tabla objective spec
-*/
-
-#define  TABLA_CDC_VDDA_CP_CUR_MAX	500000
-#define  TABLA_CDC_VDDA_RX_CUR_MAX	20000
-#define  TABLA_CDC_VDDA_TX_CUR_MAX	20000
-#define  TABLA_VDDIO_CDC_CUR_MAX	5000
-
-#define  TABLA_VDDD_CDC_D_CUR_MAX	5000
-#define  TABLA_VDDD_CDC_A_CUR_MAX	5000
-
-static struct tabla_regulator tabla_regulators[] = {
-	{
-		.name = "CDC_VDD_CP",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_CDC_VDDA_CP_CUR_MAX,
-	},
-	{
-		.name = "CDC_VDDA_RX",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_CDC_VDDA_RX_CUR_MAX,
-	},
-	{
-		.name = "CDC_VDDA_TX",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_CDC_VDDA_TX_CUR_MAX,
-	},
-	{
-		.name = "VDDIO_CDC",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_VDDIO_CDC_CUR_MAX,
-	},
-	{
-		.name = "VDDD_CDC_D",
-		.min_uV = 1225000,
-		.max_uV = 1225000,
-		.optimum_uA = TABLA_VDDD_CDC_D_CUR_MAX,
-	},
-	{
-		.name = "CDC_VDDA_A_1P2V",
-		.min_uV = 1225000,
-		.max_uV = 1225000,
-		.optimum_uA = TABLA_VDDD_CDC_A_CUR_MAX,
-	},
-};
-
-static int tabla_device_init(struct tabla *tabla, int irq)
-{
-	int ret;
-	struct mfd_cell *tabla_dev;
-	int tabla_dev_size;
-
-	mutex_init(&tabla->io_lock);
-	mutex_init(&tabla->xfer_lock);
-
-	mutex_init(&tabla->pm_lock);
-	tabla->wlock_holders = 0;
-	tabla->pm_state = TABLA_PM_SLEEPABLE;
-	init_waitqueue_head(&tabla->pm_wq);
-	wake_lock_init(&tabla->wlock, WAKE_LOCK_IDLE, "wcd9310-irq");
-
-	dev_set_drvdata(tabla->dev, tabla);
-
-	tabla_bring_up(tabla);
-
-	ret = tabla_irq_init(tabla);
-	if (ret) {
-		pr_err("IRQ initialization failed\n");
-		goto err;
-	}
-	tabla->version = tabla_reg_read(tabla, TABLA_A_CHIP_VERSION) & 0x1F;
-	pr_info("%s : Tabla version %u initialized\n",
-		__func__, tabla->version);
-
-	if (TABLA_IS_1_X(tabla->version)) {
-		tabla_dev = tabla1x_devs;
-		tabla_dev_size = ARRAY_SIZE(tabla1x_devs);
-	} else {
-		tabla_dev = tabla_devs;
-		tabla_dev_size = ARRAY_SIZE(tabla_devs);
-	}
-	ret = mfd_add_devices(tabla->dev, -1,
-			      tabla_dev, tabla_dev_size,
-			      NULL, 0);
-	if (ret != 0) {
-		dev_err(tabla->dev, "Failed to add children: %d\n", ret);
-		goto err_irq;
-	}
-
-	tabla->version = tabla_reg_read(tabla, TABLA_A_CHIP_VERSION) & 0x1F;
-	pr_info("%s : Tabla version %u initialized\n",
-		__func__, tabla->version);
-
-	return ret;
-err_irq:
-	tabla_irq_exit(tabla);
-err:
-	tabla_bring_down(tabla);
-	wake_lock_destroy(&tabla->wlock);
-	mutex_destroy(&tabla->pm_lock);
-	mutex_destroy(&tabla->io_lock);
-	mutex_destroy(&tabla->xfer_lock);
-	return ret;
-}
-
-static void tabla_device_exit(struct tabla *tabla)
-{
-	tabla_irq_exit(tabla);
-	tabla_bring_down(tabla);
-	tabla_free_reset(tabla);
-	mutex_destroy(&tabla->pm_lock);
-	wake_lock_destroy(&tabla->wlock);
-	mutex_destroy(&tabla->io_lock);
-	mutex_destroy(&tabla->xfer_lock);
-}
-
-
-#ifdef CONFIG_DEBUG_FS
-struct tabla *debugTabla;
-
-static struct dentry *debugfs_tabla_dent;
-static struct dentry *debugfs_peek;
-static struct dentry *debugfs_poke;
-
-static unsigned char read_data;
-
-static int codec_debug_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static int get_parameters(char *buf, long int *param1, int num_of_par)
-{
-	char *token;
-	int base, cnt;
-
-	token = strsep(&buf, " ");
-
-	for (cnt = 0; cnt < num_of_par; cnt++) {
-		if (token != NULL) {
-			if ((token[1] == 'x') || (token[1] == 'X'))
-				base = 16;
-			else
-				base = 10;
-
-			if (strict_strtoul(token, base, &param1[cnt]) != 0)
-				return -EINVAL;
-
-			token = strsep(&buf, " ");
-		} else
-			return -EINVAL;
-	}
-	return 0;
-}
-
-static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
-				size_t count, loff_t *ppos)
-{
-	char lbuf[8];
-
-	snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
-	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
-		strnlen(lbuf, 7));
-}
-
-
-static ssize_t codec_debug_write(struct file *filp,
-	const char __user *ubuf, size_t cnt, loff_t *ppos)
-{
-	char *access_str = filp->private_data;
-	char lbuf[32];
-	int rc;
-	long int param[5];
-
-	if (cnt > sizeof(lbuf) - 1)
-		return -EINVAL;
-
-	rc = copy_from_user(lbuf, ubuf, cnt);
-	if (rc)
-		return -EFAULT;
-
-	lbuf[cnt] = '\0';
-
-	if (!strncmp(access_str, "poke", 6)) {
-		/* write */
-		rc = get_parameters(lbuf, param, 2);
-		if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) &&
-			(rc == 0))
-			tabla_interface_reg_write(debugTabla, param[0],
-				param[1]);
-		else
-			rc = -EINVAL;
-	} else if (!strncmp(access_str, "peek", 6)) {
-		/* read */
-		rc = get_parameters(lbuf, param, 1);
-		if ((param[0] <= 0x3FF) && (rc == 0))
-			read_data = tabla_interface_reg_read(debugTabla,
-				param[0]);
-		else
-			rc = -EINVAL;
-	}
-
-	if (rc == 0)
-		rc = cnt;
-	else
-		pr_err("%s: rc = %d\n", __func__, rc);
-
-	return rc;
-}
-
-static const struct file_operations codec_debug_ops = {
-	.open = codec_debug_open,
-	.write = codec_debug_write,
-	.read = codec_debug_read
-};
-#endif
-
-static int tabla_enable_supplies(struct tabla *tabla)
-{
-	int ret;
-	int i;
-
-	tabla->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
-				   ARRAY_SIZE(tabla_regulators),
-				   GFP_KERNEL);
-	if (!tabla->supplies) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++)
-		tabla->supplies[i].supply = tabla_regulators[i].name;
-
-	ret = regulator_bulk_get(tabla->dev, ARRAY_SIZE(tabla_regulators),
-				 tabla->supplies);
-	if (ret != 0) {
-		dev_err(tabla->dev, "Failed to get supplies: err = %d\n", ret);
-		goto err_supplies;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
-		ret = regulator_set_voltage(tabla->supplies[i].consumer,
-			tabla_regulators[i].min_uV, tabla_regulators[i].max_uV);
-		if (ret) {
-			pr_err("%s: Setting regulator voltage failed for "
-				"regulator %s err = %d\n", __func__,
-				tabla->supplies[i].supply, ret);
-			goto err_get;
-		}
-
-		ret = regulator_set_optimum_mode(tabla->supplies[i].consumer,
-			tabla_regulators[i].optimum_uA);
-		if (ret < 0) {
-			pr_err("%s: Setting regulator optimum mode failed for "
-				"regulator %s err = %d\n", __func__,
-				tabla->supplies[i].supply, ret);
-			goto err_get;
-		}
-	}
-
-	ret = regulator_bulk_enable(ARRAY_SIZE(tabla_regulators),
-				    tabla->supplies);
-	if (ret != 0) {
-		dev_err(tabla->dev, "Failed to enable supplies: err = %d\n",
-				ret);
-		goto err_configure;
-	}
-	return ret;
-
-err_configure:
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
-		regulator_set_voltage(tabla->supplies[i].consumer, 0,
-			tabla_regulators[i].max_uV);
-		regulator_set_optimum_mode(tabla->supplies[i].consumer, 0);
-	}
-err_get:
-	regulator_bulk_free(ARRAY_SIZE(tabla_regulators), tabla->supplies);
-err_supplies:
-	kfree(tabla->supplies);
-err:
-	return ret;
-}
-
-static void tabla_disable_supplies(struct tabla *tabla)
-{
-	int i;
-
-	regulator_bulk_disable(ARRAY_SIZE(tabla_regulators),
-				    tabla->supplies);
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
-		regulator_set_voltage(tabla->supplies[i].consumer, 0,
-			tabla_regulators[i].max_uV);
-		regulator_set_optimum_mode(tabla->supplies[i].consumer, 0);
-	}
-	regulator_bulk_free(ARRAY_SIZE(tabla_regulators), tabla->supplies);
-	kfree(tabla->supplies);
-}
-
-int tabla_get_intf_type(void)
-{
-	return tabla_intf;
-}
-EXPORT_SYMBOL_GPL(tabla_get_intf_type);
-
-struct tabla_i2c *get_i2c_tabla_device_info(u16 reg)
-{
-	u16 mask = 0x0f00;
-	int value = 0;
-	struct tabla_i2c *tabla = NULL;
-	value = ((reg & mask) >> 8) & 0x000f;
-	switch (value) {
-	case 0:
-		tabla = &tabla_modules[0];
-		break;
-	case 1:
-		tabla = &tabla_modules[1];
-		break;
-	case 2:
-		tabla = &tabla_modules[2];
-		break;
-	case 3:
-		tabla = &tabla_modules[3];
-		break;
-	default:
-		break;
-	}
-	return tabla;
-}
-
-int tabla_i2c_write_device(u16 reg, u8 *value,
-				u32 bytes)
-{
-
-	struct i2c_msg *msg;
-	int ret = 0;
-	u8 reg_addr = 0;
-	u8 data[bytes + 1];
-	struct tabla_i2c *tabla;
-
-	tabla = get_i2c_tabla_device_info(reg);
-	if (tabla->client == NULL) {
-		pr_err("failed to get device info\n");
-		return -ENODEV;
-	}
-	reg_addr = (u8)reg;
-	msg = &tabla->xfer_msg[0];
-	msg->addr = tabla->client->addr;
-	msg->len = bytes + 1;
-	msg->flags = 0;
-	data[0] = reg;
-	data[1] = *value;
-	msg->buf = data;
-	ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 1);
-	/* Try again if the write fails */
-	if (ret != 1) {
-		ret = i2c_transfer(tabla->client->adapter,
-						tabla->xfer_msg, 1);
-		if (ret != 1) {
-			pr_err("failed to write the device\n");
-			return ret;
-		}
-	}
-	pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
-	return 0;
-}
-
-
-int tabla_i2c_read_device(unsigned short reg,
-				  int bytes, unsigned char *dest)
-{
-	struct i2c_msg *msg;
-	int ret = 0;
-	u8 reg_addr = 0;
-	struct tabla_i2c *tabla;
-	u8 i = 0;
-
-	tabla = get_i2c_tabla_device_info(reg);
-	if (tabla->client == NULL) {
-		pr_err("failed to get device info\n");
-		return -ENODEV;
-	}
-	for (i = 0; i < bytes; i++) {
-		reg_addr = (u8)reg++;
-		msg = &tabla->xfer_msg[0];
-		msg->addr = tabla->client->addr;
-		msg->len = 1;
-		msg->flags = 0;
-		msg->buf = &reg_addr;
-
-		msg = &tabla->xfer_msg[1];
-		msg->addr = tabla->client->addr;
-		msg->len = 1;
-		msg->flags = I2C_M_RD;
-		msg->buf = dest++;
-		ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 2);
-
-		/* Try again if read fails first time */
-		if (ret != 2) {
-			ret = i2c_transfer(tabla->client->adapter,
-							tabla->xfer_msg, 2);
-			if (ret != 2) {
-				pr_err("failed to read tabla register\n");
-				return ret;
-			}
-		}
-	}
-	return 0;
-}
-
-int tabla_i2c_read(struct tabla *tabla, unsigned short reg,
-		   int bytes, void *dest, bool interface_reg)
-{
-	return tabla_i2c_read_device(reg, bytes, dest);
-}
-
-int tabla_i2c_write(struct tabla *tabla, unsigned short reg,
-		    int bytes, void *src, bool interface_reg)
-{
-	return tabla_i2c_write_device(reg, src, bytes);
-}
-
-static int __devinit tabla_i2c_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
-{
-	struct tabla *tabla;
-	struct tabla_pdata *pdata = client->dev.platform_data;
-	int val = 0;
-	int ret = 0;
-	static int device_id;
-
-	if (device_id > 0) {
-		tabla_modules[device_id++].client = client;
-		pr_info("probe for other slaves devices of tabla\n");
-		return ret;
-	}
-
-	tabla = kzalloc(sizeof(struct tabla), GFP_KERNEL);
-	if (tabla == NULL) {
-		pr_err("%s: error, allocation failed\n", __func__);
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	if (!pdata) {
-		dev_dbg(&client->dev, "no platform data?\n");
-		ret = -EINVAL;
-		goto fail;
-	}
-	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
-		dev_dbg(&client->dev, "can't talk I2C?\n");
-		ret = -EIO;
-		goto fail;
-	}
-	tabla->dev = &client->dev;
-	tabla->reset_gpio = pdata->reset_gpio;
-
-	ret = tabla_enable_supplies(tabla);
-	if (ret) {
-		pr_err("%s: Fail to enable Tabla supplies\n", __func__);
-		goto err_tabla;
-	}
-
-	usleep_range(5, 5);
-	ret = tabla_reset(tabla);
-	if (ret) {
-		pr_err("%s: Resetting Tabla failed\n", __func__);
-		goto err_supplies;
-	}
-	tabla_modules[device_id++].client = client;
-
-	tabla->read_dev = tabla_i2c_read;
-	tabla->write_dev = tabla_i2c_write;
-	tabla->irq = pdata->irq;
-	tabla->irq_base = pdata->irq_base;
-
-	/*read the tabla status before initializing the device type*/
-	ret = tabla_read(tabla, TABLA_A_CHIP_STATUS, 1, &val, 0);
-	if ((ret < 0) || (val != TABLA_I2C_MODE)) {
-		pr_err("failed to read the tabla status\n");
-		goto err_device_init;
-	}
-
-	ret = tabla_device_init(tabla, tabla->irq);
-	if (ret) {
-		pr_err("%s: error, initializing device failed\n", __func__);
-		goto err_device_init;
-	}
-	tabla_intf = TABLA_INTERFACE_TYPE_I2C;
-
-	return ret;
-err_device_init:
-	tabla_free_reset(tabla);
-err_supplies:
-	tabla_disable_supplies(tabla);
-err_tabla:
-	kfree(tabla);
-fail:
-	return ret;
-}
-
-static int __devexit tabla_i2c_remove(struct i2c_client *client)
-{
-	struct tabla *tabla;
-
-	pr_debug("exit\n");
-	tabla = dev_get_drvdata(&client->dev);
-	tabla_device_exit(tabla);
-	tabla_disable_supplies(tabla);
-	kfree(tabla);
-	return 0;
-}
-
-static int tabla_slim_probe(struct slim_device *slim)
-{
-	struct tabla *tabla;
-	struct tabla_pdata *pdata;
-	int ret = 0;
-	int sgla_retry_cnt;
-
-	dev_info(&slim->dev, "Initialized slim device %s\n", slim->name);
-	pdata = slim->dev.platform_data;
-
-	if (!pdata) {
-		dev_err(&slim->dev, "Error, no platform data\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
-	tabla = kzalloc(sizeof(struct tabla), GFP_KERNEL);
-	if (tabla == NULL) {
-		pr_err("%s: error, allocation failed\n", __func__);
-		ret = -ENOMEM;
-		goto err;
-	}
-	if (!slim->ctrl) {
-		pr_err("Error, no SLIMBUS control data\n");
-		ret = -EINVAL;
-		goto err_tabla;
-	}
-	tabla->slim = slim;
-	slim_set_clientdata(slim, tabla);
-	tabla->reset_gpio = pdata->reset_gpio;
-	tabla->dev = &slim->dev;
-
-	ret = tabla_enable_supplies(tabla);
-	if (ret) {
-		pr_err("%s: Fail to enable Tabla supplies\n", __func__);
-		goto err_tabla;
-	}
-	usleep_range(5, 5);
-
-	ret = tabla_reset(tabla);
-	if (ret) {
-		pr_err("%s: Resetting Tabla failed\n", __func__);
-		goto err_supplies;
-	}
-
-	ret = slim_get_logical_addr(tabla->slim, tabla->slim->e_addr,
-		ARRAY_SIZE(tabla->slim->e_addr), &tabla->slim->laddr);
-	if (ret) {
-		pr_err("fail to get slimbus logical address %d\n", ret);
-		goto err_reset;
-	}
-	tabla->read_dev = tabla_slim_read_device;
-	tabla->write_dev = tabla_slim_write_device;
-	tabla->irq = pdata->irq;
-	tabla->irq_base = pdata->irq_base;
-	tabla_pgd_la = tabla->slim->laddr;
-
-	if (pdata->num_irqs < TABLA_NUM_IRQS) {
-		pr_err("%s: Error, not enough interrupt lines allocated\n",
-			__func__);
-		goto err_reset;
-	}
-
-	tabla->slim_slave = &pdata->slimbus_slave_device;
-
-	ret = slim_add_device(slim->ctrl, tabla->slim_slave);
-	if (ret) {
-		pr_err("%s: error, adding SLIMBUS device failed\n", __func__);
-		goto err_reset;
-	}
-
-	sgla_retry_cnt = 0;
-
-	while (1) {
-		ret = slim_get_logical_addr(tabla->slim_slave,
-			tabla->slim_slave->e_addr,
-			ARRAY_SIZE(tabla->slim_slave->e_addr),
-			&tabla->slim_slave->laddr);
-		if (ret) {
-			if (sgla_retry_cnt++ < TABLA_SLIM_GLA_MAX_RETRIES) {
-				/* Give SLIMBUS slave time to report present
-				   and be ready.
-				 */
-				usleep_range(1000, 1000);
-				pr_debug("%s: retry slim_get_logical_addr()\n",
-					__func__);
-				continue;
-			}
-			pr_err("fail to get slimbus slave logical address"
-				" %d\n", ret);
-			goto err_slim_add;
-		}
-		break;
-	}
-	tabla_inf_la = tabla->slim_slave->laddr;
-	tabla_intf = TABLA_INTERFACE_TYPE_SLIMBUS;
-
-	ret = tabla_device_init(tabla, tabla->irq);
-	if (ret) {
-		pr_err("%s: error, initializing device failed\n", __func__);
-		goto err_slim_add;
-	}
-	tabla_init_slimslave(tabla, tabla_pgd_la);
-#ifdef CONFIG_DEBUG_FS
-	debugTabla = tabla;
-
-	debugfs_tabla_dent = debugfs_create_dir
-		("wcd9310_slimbus_interface_device", 0);
-	if (!IS_ERR(debugfs_tabla_dent)) {
-		debugfs_peek = debugfs_create_file("peek",
-		S_IFREG | S_IRUGO, debugfs_tabla_dent,
-		(void *) "peek", &codec_debug_ops);
-
-		debugfs_poke = debugfs_create_file("poke",
-		S_IFREG | S_IRUGO, debugfs_tabla_dent,
-		(void *) "poke", &codec_debug_ops);
-	}
-#endif
-
-	return ret;
-
-err_slim_add:
-	slim_remove_device(tabla->slim_slave);
-err_reset:
-	tabla_free_reset(tabla);
-err_supplies:
-	tabla_disable_supplies(tabla);
-err_tabla:
-	kfree(tabla);
-err:
-	return ret;
-}
-
-static int tabla_slim_remove(struct slim_device *pdev)
-{
-	struct tabla *tabla;
-
-#ifdef CONFIG_DEBUG_FS
-	debugfs_remove(debugfs_peek);
-	debugfs_remove(debugfs_poke);
-	debugfs_remove(debugfs_tabla_dent);
-#endif
-
-	tabla = slim_get_devicedata(pdev);
-	tabla_deinit_slimslave(tabla);
-	tabla_device_exit(tabla);
-	tabla_disable_supplies(tabla);
-	slim_remove_device(tabla->slim_slave);
-	kfree(tabla);
-
-	return 0;
-}
-
-static int tabla_resume(struct tabla *tabla)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	mutex_lock(&tabla->pm_lock);
-	if (tabla->pm_state == TABLA_PM_ASLEEP) {
-		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
-			 tabla->pm_state, tabla->wlock_holders);
-		tabla->pm_state = TABLA_PM_SLEEPABLE;
-	} else {
-		pr_warn("%s: system is already awake, state %d wlock %d\n",
-			__func__, tabla->pm_state, tabla->wlock_holders);
-	}
-	mutex_unlock(&tabla->pm_lock);
-	wake_up_all(&tabla->pm_wq);
-
-	return ret;
-}
-
-static int tabla_slim_resume(struct slim_device *sldev)
-{
-	struct tabla *tabla = slim_get_devicedata(sldev);
-	return tabla_resume(tabla);
-}
-
-static int tabla_i2c_resume(struct i2c_client *i2cdev)
-{
-	struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
-	return tabla_resume(tabla);
-}
-
-static int tabla_suspend(struct tabla *tabla, pm_message_t pmesg)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	/* wake_lock() can be called after this suspend chain call started.
-	 * thus suspend can be called while wlock is being held */
-	mutex_lock(&tabla->pm_lock);
-	if (tabla->pm_state == TABLA_PM_SLEEPABLE) {
-		pr_debug("%s: suspending system, state %d, wlock %d\n",
-			 __func__, tabla->pm_state, tabla->wlock_holders);
-		tabla->pm_state = TABLA_PM_ASLEEP;
-	} else if (tabla->pm_state == TABLA_PM_AWAKE) {
-		/* unlock to wait for pm_state == TABLA_PM_SLEEPABLE
-		 * then set to TABLA_PM_ASLEEP */
-		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
-			 __func__, tabla->pm_state, tabla->wlock_holders);
-		mutex_unlock(&tabla->pm_lock);
-		if (!(wait_event_timeout(tabla->pm_wq,
-					 tabla_pm_cmpxchg(tabla,
-							  TABLA_PM_SLEEPABLE,
-							  TABLA_PM_ASLEEP) ==
-							     TABLA_PM_SLEEPABLE,
-					 HZ))) {
-			pr_debug("%s: suspend failed state %d, wlock %d\n",
-				 __func__, tabla->pm_state,
-				 tabla->wlock_holders);
-			ret = -EBUSY;
-		} else {
-			pr_debug("%s: done, state %d, wlock %d\n", __func__,
-				 tabla->pm_state, tabla->wlock_holders);
-		}
-		mutex_lock(&tabla->pm_lock);
-	} else if (tabla->pm_state == TABLA_PM_ASLEEP) {
-		pr_warn("%s: system is already suspended, state %d, wlock %dn",
-			__func__, tabla->pm_state, tabla->wlock_holders);
-	}
-	mutex_unlock(&tabla->pm_lock);
-
-	return ret;
-}
-
-static int tabla_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
-{
-	struct tabla *tabla = slim_get_devicedata(sldev);
-	return tabla_suspend(tabla, pmesg);
-}
-
-static int tabla_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
-{
-	struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
-	return tabla_suspend(tabla, pmesg);
-}
-
-static const struct slim_device_id slimtest_id[] = {
-	{"tabla-slim", 0},
-	{}
-};
-
-static struct slim_driver tabla_slim_driver = {
-	.driver = {
-		.name = "tabla-slim",
-		.owner = THIS_MODULE,
-	},
-	.probe = tabla_slim_probe,
-	.remove = tabla_slim_remove,
-	.id_table = slimtest_id,
-	.resume = tabla_slim_resume,
-	.suspend = tabla_slim_suspend,
-};
-
-static const struct slim_device_id slimtest2x_id[] = {
-	{"tabla2x-slim", 0},
-	{}
-};
-
-static struct slim_driver tabla2x_slim_driver = {
-	.driver = {
-		.name = "tabla2x-slim",
-		.owner = THIS_MODULE,
-	},
-	.probe = tabla_slim_probe,
-	.remove = tabla_slim_remove,
-	.id_table = slimtest2x_id,
-	.resume = tabla_slim_resume,
-	.suspend = tabla_slim_suspend,
-};
-
-#define TABLA_I2C_TOP_LEVEL 0
-#define TABLA_I2C_ANALOG       1
-#define TABLA_I2C_DIGITAL_1    2
-#define TABLA_I2C_DIGITAL_2    3
-
-static struct i2c_device_id tabla_id_table[] = {
-	{"tabla top level", TABLA_I2C_TOP_LEVEL},
-	{"tabla analog", TABLA_I2C_TOP_LEVEL},
-	{"tabla digital1", TABLA_I2C_TOP_LEVEL},
-	{"tabla digital2", TABLA_I2C_TOP_LEVEL},
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, tabla_id_table);
-
-static struct i2c_driver tabla_i2c_driver = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = "tabla-i2c-core",
-	},
-	.id_table = tabla_id_table,
-	.probe = tabla_i2c_probe,
-	.remove = __devexit_p(tabla_i2c_remove),
-	.resume	= tabla_i2c_resume,
-	.suspend = tabla_i2c_suspend,
-};
-
-static int __init tabla_init(void)
-{
-	int ret1, ret2, ret3;
-
-	ret1 = slim_driver_register(&tabla_slim_driver);
-	if (ret1 != 0)
-		pr_err("Failed to register tabla SB driver: %d\n", ret1);
-
-	ret2 = slim_driver_register(&tabla2x_slim_driver);
-	if (ret2 != 0)
-		pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
-
-	ret3 = i2c_add_driver(&tabla_i2c_driver);
-	if (ret3 != 0)
-		pr_err("failed to add the I2C driver\n");
-
-	return (ret1 && ret2 && ret3) ? -1 : 0;
-}
-module_init(tabla_init);
-
-static void __exit tabla_exit(void)
-{
-}
-module_exit(tabla_exit);
-
-MODULE_DESCRIPTION("Tabla core driver");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
deleted file mode 100644
index c6a9c23..0000000
--- a/drivers/mfd/wcd9310-irq.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* 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
- * 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/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/irq.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/interrupt.h>
-
-#define BYTE_BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_BYTE))
-#define BIT_BYTE(nr)			((nr) / BITS_PER_BYTE)
-
-struct tabla_irq {
-	bool level;
-};
-
-static struct tabla_irq tabla_irqs[TABLA_NUM_IRQS] = {
-	[0] = { .level = 1},
-/* All other tabla interrupts are edge triggered */
-};
-
-static inline int irq_to_tabla_irq(struct tabla *tabla, int irq)
-{
-	return irq - tabla->irq_base;
-}
-
-static void tabla_irq_lock(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	mutex_lock(&tabla->irq_lock);
-}
-
-static void tabla_irq_sync_unlock(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(tabla->irq_masks_cur); i++) {
-		/* If there's been a change in the mask write it back
-		 * to the hardware.
-		 */
-		if (tabla->irq_masks_cur[i] != tabla->irq_masks_cache[i]) {
-			tabla->irq_masks_cache[i] = tabla->irq_masks_cur[i];
-			tabla_reg_write(tabla, TABLA_A_INTR_MASK0+i,
-				tabla->irq_masks_cur[i]);
-		}
-	}
-
-	mutex_unlock(&tabla->irq_lock);
-}
-
-static void tabla_irq_enable(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	int tabla_irq = irq_to_tabla_irq(tabla, data->irq);
-	tabla->irq_masks_cur[BIT_BYTE(tabla_irq)] &=
-		~(BYTE_BIT_MASK(tabla_irq));
-}
-
-static void tabla_irq_disable(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	int tabla_irq = irq_to_tabla_irq(tabla, data->irq);
-	tabla->irq_masks_cur[BIT_BYTE(tabla_irq)] |= BYTE_BIT_MASK(tabla_irq);
-}
-
-static struct irq_chip tabla_irq_chip = {
-	.name = "tabla",
-	.irq_bus_lock = tabla_irq_lock,
-	.irq_bus_sync_unlock = tabla_irq_sync_unlock,
-	.irq_disable = tabla_irq_disable,
-	.irq_enable = tabla_irq_enable,
-};
-
-enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
-				     enum tabla_pm_state n)
-{
-	enum tabla_pm_state old;
-	mutex_lock(&tabla->pm_lock);
-	old = tabla->pm_state;
-	if (old == o)
-		tabla->pm_state = n;
-	mutex_unlock(&tabla->pm_lock);
-	return old;
-}
-EXPORT_SYMBOL_GPL(tabla_pm_cmpxchg);
-
-void tabla_lock_sleep(struct tabla *tabla)
-{
-	enum tabla_pm_state os;
-
-	/* tabla_{lock/unlock}_sleep will be called by tabla_irq_thread
-	 * and its subroutines only motly.
-	 * but btn0_lpress_fn is not tabla_irq_thread's subroutine and
-	 * it can race with tabla_irq_thread.
-	 * so need to embrace wlock_holders with mutex.
-	 */
-	mutex_lock(&tabla->pm_lock);
-	if (tabla->wlock_holders++ == 0)
-		wake_lock(&tabla->wlock);
-	mutex_unlock(&tabla->pm_lock);
-	while (!wait_event_timeout(tabla->pm_wq,
-			((os = tabla_pm_cmpxchg(tabla, TABLA_PM_SLEEPABLE,
-						TABLA_PM_AWAKE)) ==
-						    TABLA_PM_SLEEPABLE ||
-			 (os == TABLA_PM_AWAKE)),
-			5 * HZ)) {
-		pr_err("%s: system didn't resume within 5000ms, state %d, "
-		       "wlock %d\n", __func__, tabla->pm_state,
-		       tabla->wlock_holders);
-		WARN_ON_ONCE(1);
-	}
-	wake_up_all(&tabla->pm_wq);
-}
-EXPORT_SYMBOL_GPL(tabla_lock_sleep);
-
-void tabla_unlock_sleep(struct tabla *tabla)
-{
-	mutex_lock(&tabla->pm_lock);
-	if (--tabla->wlock_holders == 0) {
-		tabla->pm_state = TABLA_PM_SLEEPABLE;
-		wake_unlock(&tabla->wlock);
-	}
-	mutex_unlock(&tabla->pm_lock);
-	wake_up_all(&tabla->pm_wq);
-}
-EXPORT_SYMBOL_GPL(tabla_unlock_sleep);
-
-static irqreturn_t tabla_irq_thread(int irq, void *data)
-{
-	int ret;
-	struct tabla *tabla = data;
-	u8 status[TABLA_NUM_IRQ_REGS];
-	unsigned int i;
-
-	tabla_lock_sleep(tabla);
-	ret = tabla_bulk_read(tabla, TABLA_A_INTR_STATUS0,
-			       TABLA_NUM_IRQ_REGS, status);
-	if (ret < 0) {
-		dev_err(tabla->dev, "Failed to read interrupt status: %d\n",
-			ret);
-		tabla_unlock_sleep(tabla);
-		return IRQ_NONE;
-	}
-	/* Apply masking */
-	for (i = 0; i < TABLA_NUM_IRQ_REGS; i++)
-		status[i] &= ~tabla->irq_masks_cur[i];
-
-	/* Find out which interrupt was triggered and call that interrupt's
-	 * handler function
-	 */
-	for (i = 0; i < TABLA_NUM_IRQS; i++) {
-		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
-			if ((i <= TABLA_IRQ_MBHC_INSERTION) &&
-				(i >= TABLA_IRQ_MBHC_REMOVAL)) {
-				tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
-					BIT_BYTE(i), BYTE_BIT_MASK(i));
-				if (tabla_get_intf_type() ==
-					TABLA_INTERFACE_TYPE_I2C)
-					tabla_reg_write(tabla,
-						TABLA_A_INTR_MODE, 0x02);
-				handle_nested_irq(tabla->irq_base + i);
-			} else {
-				handle_nested_irq(tabla->irq_base + i);
-				tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
-					BIT_BYTE(i), BYTE_BIT_MASK(i));
-				if (tabla_get_intf_type() ==
-					TABLA_INTERFACE_TYPE_I2C)
-					tabla_reg_write(tabla,
-						TABLA_A_INTR_MODE, 0x02);
-			}
-			break;
-		}
-	}
-	tabla_unlock_sleep(tabla);
-
-	return IRQ_HANDLED;
-}
-
-int tabla_irq_init(struct tabla *tabla)
-{
-	int ret;
-	unsigned int i, cur_irq;
-
-	mutex_init(&tabla->irq_lock);
-
-	if (!tabla->irq) {
-		dev_warn(tabla->dev,
-			 "No interrupt specified, no interrupts\n");
-		tabla->irq_base = 0;
-		return 0;
-	}
-
-	if (!tabla->irq_base) {
-		dev_err(tabla->dev,
-			"No interrupt base specified, no interrupts\n");
-		return 0;
-	}
-	/* Mask the individual interrupt sources */
-	for (i = 0, cur_irq = tabla->irq_base; i < TABLA_NUM_IRQS; i++,
-		cur_irq++) {
-
-		irq_set_chip_data(cur_irq, tabla);
-
-		if (tabla_irqs[i].level)
-			irq_set_chip_and_handler(cur_irq, &tabla_irq_chip,
-					 handle_level_irq);
-		else
-			irq_set_chip_and_handler(cur_irq, &tabla_irq_chip,
-					 handle_edge_irq);
-
-		irq_set_nested_thread(cur_irq, 1);
-
-		/* ARM needs us to explicitly flag the IRQ as valid
-		 * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
-		set_irq_flags(cur_irq, IRQF_VALID);
-#else
-		set_irq_noprobe(cur_irq);
-#endif
-
-		tabla->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
-		tabla->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
-		tabla->irq_level[BIT_BYTE(i)] |= tabla_irqs[i].level <<
-			(i % BITS_PER_BYTE);
-	}
-	for (i = 0; i < TABLA_NUM_IRQ_REGS; i++) {
-		/* Initialize interrupt mask and level registers */
-		tabla_reg_write(tabla, TABLA_A_INTR_LEVEL0 + i,
-			tabla->irq_level[i]);
-		tabla_reg_write(tabla, TABLA_A_INTR_MASK0 + i,
-			tabla->irq_masks_cur[i]);
-	}
-
-	ret = request_threaded_irq(tabla->irq, NULL, tabla_irq_thread,
-				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-				   "tabla", tabla);
-	if (ret != 0)
-		dev_err(tabla->dev, "Failed to request IRQ %d: %d\n",
-			tabla->irq, ret);
-	else {
-		ret = enable_irq_wake(tabla->irq);
-		if (ret == 0) {
-			ret = device_init_wakeup(tabla->dev, 1);
-			if (ret) {
-				dev_err(tabla->dev, "Failed to init device"
-					"wakeup : %d\n", ret);
-				disable_irq_wake(tabla->irq);
-			}
-		} else
-			dev_err(tabla->dev, "Failed to set wake interrupt on"
-				" IRQ %d: %d\n", tabla->irq, ret);
-		if (ret)
-			free_irq(tabla->irq, tabla);
-	}
-
-	if (ret)
-		mutex_destroy(&tabla->irq_lock);
-
-	return ret;
-}
-
-void tabla_irq_exit(struct tabla *tabla)
-{
-	if (tabla->irq) {
-		disable_irq_wake(tabla->irq);
-		free_irq(tabla->irq, tabla);
-		device_init_wakeup(tabla->dev, 0);
-	}
-	mutex_destroy(&tabla->irq_lock);
-}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
new file mode 100644
index 0000000..59a4283
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -0,0 +1,1126 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/i2c.h>
+#include <sound/soc.h>
+
+#define WCD9XXX_SLIM_GLA_MAX_RETRIES 5
+#define WCD9XXX_REGISTER_START_OFFSET 0x800
+#define WCD9XXX_SLIM_RW_MAX_TRIES 3
+
+#define MAX_WCD9XXX_DEVICE	4
+#define WCD9XXX_I2C_MODE	0x03
+
+struct wcd9xxx_i2c {
+	struct i2c_client *client;
+	struct i2c_msg xfer_msg[2];
+	struct mutex xfer_lock;
+	int mod_id;
+};
+
+struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
+static int wcd9xxx_intf;
+
+static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		       int bytes, void *dest, bool interface_reg)
+{
+	int ret;
+	u8 *buf = dest;
+
+	if (bytes <= 0) {
+		dev_err(wcd9xxx->dev, "Invalid byte read length %d\n", bytes);
+		return -EINVAL;
+	}
+
+	ret = wcd9xxx->read_dev(wcd9xxx, reg, bytes, dest, interface_reg);
+	if (ret < 0) {
+		dev_err(wcd9xxx->dev, "Codec read failed\n");
+		return ret;
+	} else
+		dev_dbg(wcd9xxx->dev, "Read 0x%02x from R%d(0x%x)\n",
+			 *buf, reg, reg);
+
+	return 0;
+}
+int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+{
+	u8 val;
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, false);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	if (ret < 0)
+		return ret;
+	else
+		return val;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_reg_read);
+
+static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *src, bool interface_reg)
+{
+	u8 *buf = src;
+
+	if (bytes <= 0) {
+		pr_err("%s: Error, invalid write length\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(wcd9xxx->dev, "Write %02x to R%d(0x%x)\n",
+		 *buf, reg, reg);
+
+	return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
+}
+
+int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     u8 val)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, false);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_reg_write);
+
+static u8 wcd9xxx_pgd_la;
+static u8 wcd9xxx_inf_la;
+
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+{
+	u8 val;
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, true);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	if (ret < 0)
+		return ret;
+	else
+		return val;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_read);
+
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     u8 val)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, true);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_write);
+
+int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     int count, u8 *buf)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+
+	ret = wcd9xxx_read(wcd9xxx, reg, count, buf, false);
+
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_bulk_read);
+
+int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     int count, u8 *buf)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+
+	ret = wcd9xxx_write(wcd9xxx, reg, count, buf, false);
+
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_bulk_write);
+
+static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
+				int bytes, void *dest, bool interface)
+{
+	int ret;
+	struct slim_ele_access msg;
+	int slim_read_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+	msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+	msg.num_bytes = bytes;
+	msg.comp = NULL;
+
+	while (1) {
+		mutex_lock(&wcd9xxx->xfer_lock);
+		ret = slim_request_val_element(interface ?
+			       wcd9xxx->slim_slave : wcd9xxx->slim,
+			       &msg, dest, bytes);
+		mutex_unlock(&wcd9xxx->xfer_lock);
+		if (likely(ret == 0) || (--slim_read_tries == 0))
+			break;
+		usleep_range(5000, 5000);
+	}
+
+	if (ret)
+		pr_err("%s: Error, Codec read failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+/* Interface specifies whether the write is to the interface or general
+ * registers.
+ */
+static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx,
+		unsigned short reg, int bytes, void *src, bool interface)
+{
+	int ret;
+	struct slim_ele_access msg;
+	int slim_write_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+	msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+	msg.num_bytes = bytes;
+	msg.comp = NULL;
+
+	while (1) {
+		mutex_lock(&wcd9xxx->xfer_lock);
+		ret = slim_change_val_element(interface ?
+			      wcd9xxx->slim_slave : wcd9xxx->slim,
+			      &msg, src, bytes);
+		mutex_unlock(&wcd9xxx->xfer_lock);
+		if (likely(ret == 0) || (--slim_write_tries == 0))
+			break;
+		usleep_range(5000, 5000);
+	}
+
+	if (ret)
+		pr_err("%s: Error, Codec write failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static struct mfd_cell tabla1x_devs[] = {
+	{
+		.name = "tabla1x_codec",
+	},
+};
+
+static struct mfd_cell tabla_devs[] = {
+	{
+		.name = "tabla_codec",
+	},
+};
+
+static struct mfd_cell sitar_devs[] = {
+	{
+		.name = "sitar_codec",
+	},
+};
+
+static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
+{
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
+	usleep_range(5000, 5000);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
+}
+
+static void wcd9xxx_bring_down(struct wcd9xxx *wcd9xxx)
+{
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
+}
+
+static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
+{
+	int ret;
+
+	if (wcd9xxx->reset_gpio) {
+		ret = gpio_request(wcd9xxx->reset_gpio, "CDC_RESET");
+		if (ret) {
+			pr_err("%s: Failed to request gpio %d\n", __func__,
+				wcd9xxx->reset_gpio);
+			wcd9xxx->reset_gpio = 0;
+			return ret;
+		}
+
+		gpio_direction_output(wcd9xxx->reset_gpio, 1);
+		msleep(20);
+		gpio_direction_output(wcd9xxx->reset_gpio, 0);
+		msleep(20);
+		gpio_direction_output(wcd9xxx->reset_gpio, 1);
+		msleep(20);
+	}
+	return 0;
+}
+
+static void wcd9xxx_free_reset(struct wcd9xxx *wcd9xxx)
+{
+	if (wcd9xxx->reset_gpio) {
+		gpio_free(wcd9xxx->reset_gpio);
+		wcd9xxx->reset_gpio = 0;
+	}
+}
+
+static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
+{
+	int ret;
+	u8 idbyte_0, idbyte_1, idbyte_2, idbyte_3;
+	struct mfd_cell *wcd9xxx_dev = NULL;
+	int wcd9xxx_dev_size = 0;
+
+	mutex_init(&wcd9xxx->io_lock);
+	mutex_init(&wcd9xxx->xfer_lock);
+
+	mutex_init(&wcd9xxx->pm_lock);
+	wcd9xxx->wlock_holders = 0;
+	wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+	init_waitqueue_head(&wcd9xxx->pm_wq);
+	wake_lock_init(&wcd9xxx->wlock, WAKE_LOCK_IDLE, "wcd9310-irq");
+
+	dev_set_drvdata(wcd9xxx->dev, wcd9xxx);
+
+	wcd9xxx_bring_up(wcd9xxx);
+
+	ret = wcd9xxx_irq_init(wcd9xxx);
+	if (ret) {
+		pr_err("IRQ initialization failed\n");
+		goto err;
+	}
+
+	idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
+	idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
+	idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
+	idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
+
+	wcd9xxx->version = wcd9xxx_reg_read(wcd9xxx,
+			WCD9XXX_A_CHIP_VERSION) & 0x1F;
+	pr_info("%s : Codec version %u initialized\n",
+		__func__, wcd9xxx->version);
+	pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
+			idbyte_0, idbyte_1, idbyte_2, idbyte_3);
+
+	if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+		if (TABLA_IS_1_X(wcd9xxx->version)) {
+			wcd9xxx_dev = tabla1x_devs;
+			wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+		} else {
+			wcd9xxx_dev = tabla_devs;
+			wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+		}
+	} else {
+		wcd9xxx_dev = sitar_devs;
+		wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+	}
+
+	ret = mfd_add_devices(wcd9xxx->dev, -1,
+		      wcd9xxx_dev, wcd9xxx_dev_size,
+		      NULL, 0);
+	if (ret != 0) {
+		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
+		goto err_irq;
+	}
+	return ret;
+err_irq:
+	wcd9xxx_irq_exit(wcd9xxx);
+err:
+	wcd9xxx_bring_down(wcd9xxx);
+	wake_lock_destroy(&wcd9xxx->wlock);
+	mutex_destroy(&wcd9xxx->pm_lock);
+	mutex_destroy(&wcd9xxx->io_lock);
+	mutex_destroy(&wcd9xxx->xfer_lock);
+	return ret;
+}
+
+static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
+{
+	wcd9xxx_irq_exit(wcd9xxx);
+	wcd9xxx_bring_down(wcd9xxx);
+	wcd9xxx_free_reset(wcd9xxx);
+	mutex_destroy(&wcd9xxx->pm_lock);
+	wake_lock_destroy(&wcd9xxx->wlock);
+	mutex_destroy(&wcd9xxx->io_lock);
+	mutex_destroy(&wcd9xxx->xfer_lock);
+	slim_remove_device(wcd9xxx->slim_slave);
+	kfree(wcd9xxx);
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+struct wcd9xxx *debugCodec;
+
+static struct dentry *debugfs_wcd9xxx_dent;
+static struct dentry *debugfs_peek;
+static struct dentry *debugfs_poke;
+
+static unsigned char read_data;
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token != NULL) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (strict_strtoul(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[8];
+
+	snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
+	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+		strnlen(lbuf, 7));
+}
+
+
+static ssize_t codec_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *access_str = filp->private_data;
+	char lbuf[32];
+	int rc;
+	long int param[5];
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+
+	if (!strncmp(access_str, "poke", 6)) {
+		/* write */
+		rc = get_parameters(lbuf, param, 2);
+		if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) &&
+			(rc == 0))
+			wcd9xxx_interface_reg_write(debugCodec, param[0],
+				param[1]);
+		else
+			rc = -EINVAL;
+	} else if (!strncmp(access_str, "peek", 6)) {
+		/* read */
+		rc = get_parameters(lbuf, param, 1);
+		if ((param[0] <= 0x3FF) && (rc == 0))
+			read_data = wcd9xxx_interface_reg_read(debugCodec,
+				param[0]);
+		else
+			rc = -EINVAL;
+	}
+
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+	.read = codec_debug_read
+};
+#endif
+
+static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx)
+{
+	int ret;
+	int i;
+	struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
+
+	wcd9xxx->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
+				   ARRAY_SIZE(pdata->regulator),
+				   GFP_KERNEL);
+	if (!wcd9xxx->supplies) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++)
+		wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
+
+	ret = regulator_bulk_get(wcd9xxx->dev, ARRAY_SIZE(pdata->regulator),
+				 wcd9xxx->supplies);
+	if (ret != 0) {
+		dev_err(wcd9xxx->dev, "Failed to get supplies: err = %d\n",
+							ret);
+		goto err_supplies;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		ret = regulator_set_voltage(wcd9xxx->supplies[i].consumer,
+			pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+		if (ret) {
+			pr_err("%s: Setting regulator voltage failed for "
+				"regulator %s err = %d\n", __func__,
+				wcd9xxx->supplies[i].supply, ret);
+			goto err_get;
+		}
+
+		ret = regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer,
+			pdata->regulator[i].optimum_uA);
+		if (ret < 0) {
+			pr_err("%s: Setting regulator optimum mode failed for "
+				"regulator %s err = %d\n", __func__,
+				wcd9xxx->supplies[i].supply, ret);
+			goto err_get;
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pdata->regulator),
+				    wcd9xxx->supplies);
+	if (ret != 0) {
+		dev_err(wcd9xxx->dev, "Failed to enable supplies: err = %d\n",
+				ret);
+		goto err_configure;
+	}
+	return ret;
+
+err_configure:
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
+			pdata->regulator[i].max_uV);
+		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
+	}
+err_get:
+	regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+err_supplies:
+	kfree(wcd9xxx->supplies);
+err:
+	return ret;
+}
+
+static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx)
+{
+	int i;
+	struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
+
+	regulator_bulk_disable(ARRAY_SIZE(pdata->regulator),
+				    wcd9xxx->supplies);
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
+			pdata->regulator[i].max_uV);
+		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
+	}
+	regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+	kfree(wcd9xxx->supplies);
+}
+
+int wcd9xxx_get_intf_type(void)
+{
+	return wcd9xxx_intf;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
+
+struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
+{
+	u16 mask = 0x0f00;
+	int value = 0;
+	struct wcd9xxx_i2c *wcd9xxx = NULL;
+	value = ((reg & mask) >> 8) & 0x000f;
+	switch (value) {
+	case 0:
+		wcd9xxx = &wcd9xxx_modules[0];
+		break;
+	case 1:
+		wcd9xxx = &wcd9xxx_modules[1];
+		break;
+	case 2:
+		wcd9xxx = &wcd9xxx_modules[2];
+		break;
+	case 3:
+		wcd9xxx = &wcd9xxx_modules[3];
+		break;
+	default:
+		break;
+	}
+	return wcd9xxx;
+}
+
+int wcd9xxx_i2c_write_device(u16 reg, u8 *value,
+				u32 bytes)
+{
+
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	u8 data[bytes + 1];
+	struct wcd9xxx_i2c *wcd9xxx;
+
+	wcd9xxx = get_i2c_wcd9xxx_device_info(reg);
+	if (wcd9xxx == NULL || wcd9xxx->client == NULL) {
+		pr_err("failed to get device info\n");
+		return -ENODEV;
+	}
+	reg_addr = (u8)reg;
+	msg = &wcd9xxx->xfer_msg[0];
+	msg->addr = wcd9xxx->client->addr;
+	msg->len = bytes + 1;
+	msg->flags = 0;
+	data[0] = reg;
+	data[1] = *value;
+	msg->buf = data;
+	ret = i2c_transfer(wcd9xxx->client->adapter, wcd9xxx->xfer_msg, 1);
+	/* Try again if the write fails */
+	if (ret != 1) {
+		ret = i2c_transfer(wcd9xxx->client->adapter,
+						wcd9xxx->xfer_msg, 1);
+		if (ret != 1) {
+			pr_err("failed to write the device\n");
+			return ret;
+		}
+	}
+	pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
+	return 0;
+}
+
+
+int wcd9xxx_i2c_read_device(unsigned short reg,
+				  int bytes, unsigned char *dest)
+{
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	struct wcd9xxx_i2c *wcd9xxx;
+	u8 i = 0;
+
+	wcd9xxx = get_i2c_wcd9xxx_device_info(reg);
+	if (wcd9xxx == NULL || wcd9xxx->client == NULL) {
+		pr_err("failed to get device info\n");
+		return -ENODEV;
+	}
+	for (i = 0; i < bytes; i++) {
+		reg_addr = (u8)reg++;
+		msg = &wcd9xxx->xfer_msg[0];
+		msg->addr = wcd9xxx->client->addr;
+		msg->len = 1;
+		msg->flags = 0;
+		msg->buf = &reg_addr;
+
+		msg = &wcd9xxx->xfer_msg[1];
+		msg->addr = wcd9xxx->client->addr;
+		msg->len = 1;
+		msg->flags = I2C_M_RD;
+		msg->buf = dest++;
+		ret = i2c_transfer(wcd9xxx->client->adapter,
+				wcd9xxx->xfer_msg, 2);
+
+		/* Try again if read fails first time */
+		if (ret != 2) {
+			ret = i2c_transfer(wcd9xxx->client->adapter,
+							wcd9xxx->xfer_msg, 2);
+			if (ret != 2) {
+				pr_err("failed to read wcd9xxx register\n");
+				return ret;
+			}
+		}
+	}
+	return 0;
+}
+
+int wcd9xxx_i2c_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *dest, bool interface_reg)
+{
+	return wcd9xxx_i2c_read_device(reg, bytes, dest);
+}
+
+int wcd9xxx_i2c_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			 int bytes, void *src, bool interface_reg)
+{
+	return wcd9xxx_i2c_write_device(reg, src, bytes);
+}
+
+static int __devinit wcd9xxx_i2c_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata = client->dev.platform_data;
+	int val = 0;
+	int ret = 0;
+	static int device_id;
+
+	if (device_id > 0) {
+		wcd9xxx_modules[device_id++].client = client;
+		pr_info("probe for other slaves devices of tabla\n");
+		return ret;
+	}
+
+	wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+	if (wcd9xxx == NULL) {
+		pr_err("%s: error, allocation failed\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	if (!pdata) {
+		dev_dbg(&client->dev, "no platform data?\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+		dev_dbg(&client->dev, "can't talk I2C?\n");
+		ret = -EIO;
+		goto fail;
+	}
+	dev_set_drvdata(&client->dev, wcd9xxx);
+	wcd9xxx->dev = &client->dev;
+	wcd9xxx->reset_gpio = pdata->reset_gpio;
+
+	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Fail to enable Codec supplies\n", __func__);
+		goto err_codec;
+	}
+
+	usleep_range(5, 5);
+	ret = wcd9xxx_reset(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Resetting Codec failed\n", __func__);
+		goto err_supplies;
+	}
+	wcd9xxx_modules[device_id++].client = client;
+
+	wcd9xxx->read_dev = wcd9xxx_i2c_read;
+	wcd9xxx->write_dev = wcd9xxx_i2c_write;
+	wcd9xxx->irq = pdata->irq;
+	wcd9xxx->irq_base = pdata->irq_base;
+
+	/*read the tabla status before initializing the device type*/
+	ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+	if ((ret < 0) || (val != WCD9XXX_I2C_MODE)) {
+		pr_err("failed to read the wcd9xxx status\n");
+		goto err_device_init;
+	}
+
+	ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+	if (ret) {
+		pr_err("%s: error, initializing device failed\n", __func__);
+		goto err_device_init;
+	}
+	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
+
+	return ret;
+err_device_init:
+	wcd9xxx_free_reset(wcd9xxx);
+err_supplies:
+	wcd9xxx_disable_supplies(wcd9xxx);
+err_codec:
+	kfree(wcd9xxx);
+fail:
+	return ret;
+}
+
+static int __devexit wcd9xxx_i2c_remove(struct i2c_client *client)
+{
+	struct wcd9xxx *wcd9xxx;
+
+	pr_debug("exit\n");
+	wcd9xxx = dev_get_drvdata(&client->dev);
+	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_device_exit(wcd9xxx);
+	return 0;
+}
+
+static int wcd9xxx_slim_probe(struct slim_device *slim)
+{
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata;
+	int ret = 0;
+	int sgla_retry_cnt;
+
+	dev_info(&slim->dev, "Initialized slim device %s\n", slim->name);
+	pdata = slim->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&slim->dev, "Error, no platform data\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+	if (wcd9xxx == NULL) {
+		pr_err("%s: error, allocation failed\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+	if (!slim->ctrl) {
+		pr_err("Error, no SLIMBUS control data\n");
+		ret = -EINVAL;
+		goto err_codec;
+	}
+	wcd9xxx->slim = slim;
+	slim_set_clientdata(slim, wcd9xxx);
+	wcd9xxx->reset_gpio = pdata->reset_gpio;
+	wcd9xxx->dev = &slim->dev;
+
+	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	if (ret)
+		goto err_codec;
+	usleep_range(5, 5);
+
+	ret = wcd9xxx_reset(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Resetting Codec failed\n", __func__);
+		goto err_supplies;
+	}
+
+	ret = slim_get_logical_addr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
+		ARRAY_SIZE(wcd9xxx->slim->e_addr), &wcd9xxx->slim->laddr);
+	if (ret) {
+		pr_err("fail to get slimbus logical address %d\n", ret);
+		goto err_reset;
+	}
+	wcd9xxx->read_dev = wcd9xxx_slim_read_device;
+	wcd9xxx->write_dev = wcd9xxx_slim_write_device;
+	wcd9xxx->irq = pdata->irq;
+	wcd9xxx->irq_base = pdata->irq_base;
+	wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
+
+	if (pdata->num_irqs < TABLA_NUM_IRQS) {
+		pr_err("%s: Error, not enough interrupt lines allocated\n",
+			__func__);
+		goto err_reset;
+	}
+
+	wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
+
+	ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
+	if (ret) {
+		pr_err("%s: error, adding SLIMBUS device failed\n", __func__);
+		goto err_reset;
+	}
+
+	sgla_retry_cnt = 0;
+
+	while (1) {
+		ret = slim_get_logical_addr(wcd9xxx->slim_slave,
+			wcd9xxx->slim_slave->e_addr,
+			ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
+			&wcd9xxx->slim_slave->laddr);
+		if (ret) {
+			if (sgla_retry_cnt++ < WCD9XXX_SLIM_GLA_MAX_RETRIES) {
+				/* Give SLIMBUS slave time to report present
+				   and be ready.
+				 */
+				usleep_range(1000, 1000);
+				pr_debug("%s: retry slim_get_logical_addr()\n",
+					__func__);
+				continue;
+			}
+			pr_err("fail to get slimbus slave logical address"
+				" %d\n", ret);
+			goto err_slim_add;
+		}
+		break;
+	}
+	wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
+	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
+
+	ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+	if (ret) {
+		pr_err("%s: error, initializing device failed\n", __func__);
+		goto err_slim_add;
+	}
+	wcd9xxx_init_slimslave(wcd9xxx, wcd9xxx_pgd_la);
+#ifdef CONFIG_DEBUG_FS
+	debugCodec = wcd9xxx;
+
+	debugfs_wcd9xxx_dent = debugfs_create_dir
+		("wcd9310_slimbus_interface_device", 0);
+	if (!IS_ERR(debugfs_wcd9xxx_dent)) {
+		debugfs_peek = debugfs_create_file("peek",
+		S_IFREG | S_IRUGO, debugfs_wcd9xxx_dent,
+		(void *) "peek", &codec_debug_ops);
+
+		debugfs_poke = debugfs_create_file("poke",
+		S_IFREG | S_IRUGO, debugfs_wcd9xxx_dent,
+		(void *) "poke", &codec_debug_ops);
+	}
+#endif
+
+	return ret;
+
+err_slim_add:
+	slim_remove_device(wcd9xxx->slim_slave);
+err_reset:
+	wcd9xxx_free_reset(wcd9xxx);
+err_supplies:
+	wcd9xxx_disable_supplies(wcd9xxx);
+err_codec:
+	kfree(wcd9xxx);
+err:
+	return ret;
+}
+static int wcd9xxx_slim_remove(struct slim_device *pdev)
+{
+	struct wcd9xxx *wcd9xxx;
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(debugfs_peek);
+	debugfs_remove(debugfs_poke);
+	debugfs_remove(debugfs_wcd9xxx_dent);
+#endif
+	wcd9xxx = slim_get_devicedata(pdev);
+	wcd9xxx_deinit_slimslave(wcd9xxx);
+	slim_remove_device(wcd9xxx->slim_slave);
+	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_device_exit(wcd9xxx);
+	return 0;
+}
+
+static int wcd9xxx_resume(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+			 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+	} else {
+		pr_warn("%s: system is already awake, state %d wlock %d\n",
+			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx->pm_lock);
+	wake_up_all(&wcd9xxx->pm_wq);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_resume(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	return wcd9xxx_resume(wcd9xxx);
+}
+
+static int wcd9xxx_i2c_resume(struct i2c_client *i2cdev)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
+	if (wcd9xxx)
+		return wcd9xxx_resume(wcd9xxx);
+	else
+		return 0;
+}
+
+static int wcd9xxx_suspend(struct wcd9xxx *wcd9xxx, pm_message_t pmesg)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	/* wake_lock() can be called after this suspend chain call started.
+	 * thus suspend can be called while wlock is being held */
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (wcd9xxx->pm_state == WCD9XXX_PM_SLEEPABLE) {
+		pr_debug("%s: suspending system, state %d, wlock %d\n",
+			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		wcd9xxx->pm_state = WCD9XXX_PM_ASLEEP;
+	} else if (wcd9xxx->pm_state == WCD9XXX_PM_AWAKE) {
+		/* unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+		 * then set to WCD9XXX_PM_ASLEEP */
+		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		mutex_unlock(&wcd9xxx->pm_lock);
+		if (!(wait_event_timeout(wcd9xxx->pm_wq,
+					 wcd9xxx_pm_cmpxchg(wcd9xxx,
+						  WCD9XXX_PM_SLEEPABLE,
+						  WCD9XXX_PM_ASLEEP) ==
+							WCD9XXX_PM_SLEEPABLE,
+					 HZ))) {
+			pr_debug("%s: suspend failed state %d, wlock %d\n",
+				 __func__, wcd9xxx->pm_state,
+				 wcd9xxx->wlock_holders);
+			ret = -EBUSY;
+		} else {
+			pr_debug("%s: done, state %d, wlock %d\n", __func__,
+				 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		}
+		mutex_lock(&wcd9xxx->pm_lock);
+	} else if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_warn("%s: system is already suspended, state %d, wlock %dn",
+			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx->pm_lock);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	return wcd9xxx_suspend(wcd9xxx, pmesg);
+}
+
+static int wcd9xxx_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
+	if (wcd9xxx)
+		return wcd9xxx_suspend(wcd9xxx, pmesg);
+	else
+		return 0;
+}
+
+static const struct slim_device_id sitar_slimtest_id[] = {
+	{"sitar-slim", 0},
+	{}
+};
+static struct slim_driver sitar_slim_driver = {
+	.driver = {
+		.name = "sitar-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = sitar_slimtest_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
+static const struct slim_device_id slimtest_id[] = {
+	{"tabla-slim", 0},
+	{}
+};
+
+static struct slim_driver tabla_slim_driver = {
+	.driver = {
+		.name = "tabla-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = slimtest_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
+static const struct slim_device_id slimtest2x_id[] = {
+	{"tabla2x-slim", 0},
+	{}
+};
+
+static struct slim_driver tabla2x_slim_driver = {
+	.driver = {
+		.name = "tabla2x-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = slimtest2x_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
+#define TABLA_I2C_TOP_LEVEL 0
+#define TABLA_I2C_ANALOG       1
+#define TABLA_I2C_DIGITAL_1    2
+#define TABLA_I2C_DIGITAL_2    3
+
+static struct i2c_device_id tabla_id_table[] = {
+	{"tabla top level", TABLA_I2C_TOP_LEVEL},
+	{"tabla analog", TABLA_I2C_TOP_LEVEL},
+	{"tabla digital1", TABLA_I2C_TOP_LEVEL},
+	{"tabla digital2", TABLA_I2C_TOP_LEVEL},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static struct i2c_driver tabla_i2c_driver = {
+	.driver                 = {
+		.owner          =       THIS_MODULE,
+		.name           =       "tabla-i2c-core",
+	},
+	.id_table               =       tabla_id_table,
+	.probe                  =       wcd9xxx_i2c_probe,
+	.remove                 =       __devexit_p(wcd9xxx_i2c_remove),
+	.resume	= wcd9xxx_i2c_resume,
+	.suspend = wcd9xxx_i2c_suspend,
+};
+
+static int __init wcd9xxx_init(void)
+{
+	int ret1, ret2, ret3, ret4;
+
+	ret1 = slim_driver_register(&tabla_slim_driver);
+	if (ret1 != 0)
+		pr_err("Failed to register tabla SB driver: %d\n", ret1);
+
+	ret2 = slim_driver_register(&tabla2x_slim_driver);
+	if (ret2 != 0)
+		pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
+
+	ret3 = i2c_add_driver(&tabla_i2c_driver);
+	if (ret3 != 0)
+		pr_err("failed to add the I2C driver\n");
+
+	ret4 = slim_driver_register(&sitar_slim_driver);
+	if (ret1 != 0)
+		pr_err("Failed to register sitar SB driver: %d\n", ret4);
+
+	return (ret1 && ret2 && ret3 && ret4) ? -1 : 0;
+}
+module_init(wcd9xxx_init);
+
+static void __exit wcd9xxx_exit(void)
+{
+}
+module_exit(wcd9xxx_exit);
+
+MODULE_DESCRIPTION("Codec core driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
new file mode 100644
index 0000000..ba3c1e8
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -0,0 +1,307 @@
+/* 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
+ * 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/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/interrupt.h>
+
+#define BYTE_BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_BYTE))
+#define BIT_BYTE(nr)			((nr) / BITS_PER_BYTE)
+
+struct wcd9xxx_irq {
+	bool level;
+};
+
+static struct wcd9xxx_irq wcd9xxx_irqs[TABLA_NUM_IRQS] = {
+	[0] = { .level = 1},
+/* All other wcd9xxx interrupts are edge triggered */
+};
+
+static inline int irq_to_wcd9xxx_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+	return irq - wcd9xxx->irq_base;
+}
+
+static void wcd9xxx_irq_lock(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	mutex_lock(&wcd9xxx->irq_lock);
+}
+
+static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
+		/* If there's been a change in the mask write it back
+		 * to the hardware.
+		 */
+		if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
+			wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
+			wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0+i,
+				wcd9xxx->irq_masks_cur[i]);
+		}
+	}
+
+	mutex_unlock(&wcd9xxx->irq_lock);
+}
+
+static void wcd9xxx_irq_enable(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
+		~(BYTE_BIT_MASK(wcd9xxx_irq));
+}
+
+static void wcd9xxx_irq_disable(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
+			|= BYTE_BIT_MASK(wcd9xxx_irq);
+}
+
+static struct irq_chip wcd9xxx_irq_chip = {
+	.name = "wcd9xxx",
+	.irq_bus_lock = wcd9xxx_irq_lock,
+	.irq_bus_sync_unlock = wcd9xxx_irq_sync_unlock,
+	.irq_disable = wcd9xxx_irq_disable,
+	.irq_enable = wcd9xxx_irq_enable,
+};
+
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
+		enum wcd9xxx_pm_state o,
+		enum wcd9xxx_pm_state n)
+{
+	enum wcd9xxx_pm_state old;
+	mutex_lock(&wcd9xxx->pm_lock);
+	old = wcd9xxx->pm_state;
+	if (old == o)
+		wcd9xxx->pm_state = n;
+	mutex_unlock(&wcd9xxx->pm_lock);
+	return old;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_pm_cmpxchg);
+
+bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx)
+{
+	enum wcd9xxx_pm_state os;
+
+	/* wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+	 * and its subroutines only motly.
+	 * but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
+	 * it can race with wcd9xxx_irq_thread.
+	 * so need to embrace wlock_holders with mutex.
+	 */
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (wcd9xxx->wlock_holders++ == 0) {
+		pr_debug("%s: holding wake lock\n", __func__);
+		wake_lock(&wcd9xxx->wlock);
+	}
+	mutex_unlock(&wcd9xxx->pm_lock);
+	if (!wait_event_timeout(wcd9xxx->pm_wq,
+			((os = wcd9xxx_pm_cmpxchg(wcd9xxx, WCD9XXX_PM_SLEEPABLE,
+						WCD9XXX_PM_AWAKE)) ==
+						    WCD9XXX_PM_SLEEPABLE ||
+			 (os == WCD9XXX_PM_AWAKE)),
+			5 * HZ)) {
+		pr_err("%s: system didn't resume within 5000ms, state %d, "
+		       "wlock %d\n", __func__, wcd9xxx->pm_state,
+		       wcd9xxx->wlock_holders);
+		WARN_ON(1);
+		wcd9xxx_unlock_sleep(wcd9xxx);
+		return false;
+	}
+	wake_up_all(&wcd9xxx->pm_wq);
+	return true;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_lock_sleep);
+
+void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx)
+{
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (--wcd9xxx->wlock_holders == 0) {
+		wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+		pr_debug("%s: releasing wake lock\n", __func__);
+		wake_unlock(&wcd9xxx->wlock);
+	}
+	mutex_unlock(&wcd9xxx->pm_lock);
+	wake_up_all(&wcd9xxx->pm_wq);
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep);
+
+static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
+{
+	if ((irqbit <= TABLA_IRQ_MBHC_INSERTION) &&
+	    (irqbit >= TABLA_IRQ_MBHC_REMOVAL)) {
+		wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
+				  BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit));
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02);
+		handle_nested_irq(wcd9xxx->irq_base + irqbit);
+	} else {
+		handle_nested_irq(wcd9xxx->irq_base + irqbit);
+		wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
+				  BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit));
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02);
+	}
+}
+
+static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
+{
+	int ret;
+	struct wcd9xxx *wcd9xxx = data;
+	u8 status[WCD9XXX_NUM_IRQ_REGS];
+	int i;
+
+	if (unlikely(wcd9xxx_lock_sleep(wcd9xxx) == false)) {
+		dev_err(wcd9xxx->dev, "Failed to hold suspend\n");
+		return IRQ_NONE;
+	}
+	ret = wcd9xxx_bulk_read(wcd9xxx, TABLA_A_INTR_STATUS0,
+			       WCD9XXX_NUM_IRQ_REGS, status);
+	if (ret < 0) {
+		dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
+			ret);
+		wcd9xxx_unlock_sleep(wcd9xxx);
+		return IRQ_NONE;
+	}
+	/* Apply masking */
+	for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++)
+		status[i] &= ~wcd9xxx->irq_masks_cur[i];
+
+	/* Find out which interrupt was triggered and call that interrupt's
+	 * handler function
+	 */
+	if (status[BIT_BYTE(TABLA_IRQ_SLIMBUS)] &
+	    BYTE_BIT_MASK(TABLA_IRQ_SLIMBUS))
+		wcd9xxx_irq_dispatch(wcd9xxx, TABLA_IRQ_SLIMBUS);
+
+	/* Since codec has only one hardware irq line which is shared by
+	 * codec's different internal interrupts, so it's possible master irq
+	 * handler dispatches multiple nested irq handlers after breaking
+	 * order.  Dispatch MBHC interrupts order to follow MBHC state
+	 * machine's order */
+	for (i = TABLA_IRQ_MBHC_INSERTION; i >= TABLA_IRQ_MBHC_REMOVAL; i--) {
+		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
+			wcd9xxx_irq_dispatch(wcd9xxx, i);
+	}
+	for (i = TABLA_IRQ_BG_PRECHARGE; i < TABLA_NUM_IRQS; i++) {
+		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
+			wcd9xxx_irq_dispatch(wcd9xxx, i);
+	}
+	wcd9xxx_unlock_sleep(wcd9xxx);
+
+	return IRQ_HANDLED;
+}
+
+int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
+{
+	int ret;
+	unsigned int i, cur_irq;
+
+	mutex_init(&wcd9xxx->irq_lock);
+
+	if (!wcd9xxx->irq) {
+		dev_warn(wcd9xxx->dev,
+			 "No interrupt specified, no interrupts\n");
+		wcd9xxx->irq_base = 0;
+		return 0;
+	}
+
+	if (!wcd9xxx->irq_base) {
+		dev_err(wcd9xxx->dev,
+			"No interrupt base specified, no interrupts\n");
+		return 0;
+	}
+	/* Mask the individual interrupt sources */
+	for (i = 0, cur_irq = wcd9xxx->irq_base; i < TABLA_NUM_IRQS; i++,
+		cur_irq++) {
+
+		irq_set_chip_data(cur_irq, wcd9xxx);
+
+		if (wcd9xxx_irqs[i].level)
+			irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
+					 handle_level_irq);
+		else
+			irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
+					 handle_edge_irq);
+
+		irq_set_nested_thread(cur_irq, 1);
+
+		/* ARM needs us to explicitly flag the IRQ as valid
+		 * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+		set_irq_flags(cur_irq, IRQF_VALID);
+#else
+		set_irq_noprobe(cur_irq);
+#endif
+
+		wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		wcd9xxx->irq_level[BIT_BYTE(i)] |= wcd9xxx_irqs[i].level <<
+			(i % BITS_PER_BYTE);
+	}
+	for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++) {
+		/* Initialize interrupt mask and level registers */
+		wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_LEVEL0 + i,
+			wcd9xxx->irq_level[i]);
+		wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0 + i,
+			wcd9xxx->irq_masks_cur[i]);
+	}
+
+	ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   "wcd9xxx", wcd9xxx);
+	if (ret != 0)
+		dev_err(wcd9xxx->dev, "Failed to request IRQ %d: %d\n",
+			wcd9xxx->irq, ret);
+	else {
+		ret = enable_irq_wake(wcd9xxx->irq);
+		if (ret == 0) {
+			ret = device_init_wakeup(wcd9xxx->dev, 1);
+			if (ret) {
+				dev_err(wcd9xxx->dev, "Failed to init device"
+					"wakeup : %d\n", ret);
+				disable_irq_wake(wcd9xxx->irq);
+			}
+		} else
+			dev_err(wcd9xxx->dev, "Failed to set wake interrupt on"
+				" IRQ %d: %d\n", wcd9xxx->irq, ret);
+		if (ret)
+			free_irq(wcd9xxx->irq, wcd9xxx);
+	}
+
+	if (ret)
+		mutex_destroy(&wcd9xxx->irq_lock);
+
+	return ret;
+}
+
+void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
+{
+	if (wcd9xxx->irq) {
+		disable_irq_wake(wcd9xxx->irq);
+		free_irq(wcd9xxx->irq, wcd9xxx);
+		device_init_wakeup(wcd9xxx->dev, 0);
+	}
+	mutex_destroy(&wcd9xxx->irq_lock);
+}
diff --git a/drivers/mfd/wcd9310-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
similarity index 71%
rename from drivers/mfd/wcd9310-slimslave.c
rename to drivers/mfd/wcd9xxx-slimslave.c
index dd586fa..acef55e 100644
--- a/drivers/mfd/wcd9310-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -11,45 +11,47 @@
  */
 #include <linux/slab.h>
 #include <linux/mutex.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 
-struct tabla_slim_sch_rx {
+struct wcd9xxx_slim_sch_rx {
 	u32 sph;
 	u32 ch_num;
 	u16 ch_h;
 	u16 grph;
 };
 
-struct tabla_slim_sch_tx {
+struct wcd9xxx_slim_sch_tx {
 	u32 sph;
 	u32 ch_num;
 	u16 ch_h;
 	u16 grph;
 };
 
-struct tabla_slim_sch {
-	struct tabla_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
-	struct tabla_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
+struct wcd9xxx_slim_sch {
+	struct wcd9xxx_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
+	struct wcd9xxx_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
 };
 
-static struct tabla_slim_sch sh_ch;
+static struct wcd9xxx_slim_sch sh_ch;
 
-static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la);
-static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la);
-static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab);
-static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab);
+static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
+					u8 wcd9xxx_pgd_la);
+static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
+					u8 wcd9xxx_pgd_la);
+static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx);
+static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx);
 
-int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la)
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 
-	ret = tabla_alloc_slim_sh_ch_rx(tabla, tabla_pgd_la);
+	ret = wcd9xxx_alloc_slim_sh_ch_rx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc rx slimbus shared channels\n",
 								__func__);
 		goto rx_err;
 	}
-	ret = tabla_alloc_slim_sh_ch_tx(tabla, tabla_pgd_la);
+	ret = wcd9xxx_alloc_slim_sh_ch_tx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc tx slimbus shared channels\n",
 								__func__);
@@ -57,21 +59,21 @@
 	}
 	return 0;
 tx_err:
-	tabla_dealloc_slim_sh_ch_rx(tabla);
+	wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
 rx_err:
 	return ret;
 }
 
 
-int tabla_deinit_slimslave(struct tabla *tabla)
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
-	ret = tabla_dealloc_slim_sh_ch_rx(tabla);
+	ret = wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
 	if (ret < 0) {
 		pr_err("%s: fail to dealloc rx slim ports\n", __func__);
 		goto err;
 	}
-	ret = tabla_dealloc_slim_sh_ch_tx(tabla);
+	ret = wcd9xxx_dealloc_slim_sh_ch_tx(wcd9xxx);
 	if (ret < 0) {
 		pr_err("%s: fail to dealloc tx slim ports\n", __func__);
 		goto err;
@@ -80,13 +82,13 @@
 	return ret;
 }
 
-int tabla_get_channel(struct tabla *tabla,
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
 		unsigned int *rx_ch,
 		unsigned int *tx_ch)
 {
 	int ch_idx = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 
 	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++)
 		rx_ch[ch_idx] = rx[ch_idx].ch_num;
@@ -95,23 +97,23 @@
 	return 0;
 }
 
-static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la)
+static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
+			u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 	u8 ch_idx ;
 	u16 slave_port_id = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 
-	/* DSP requires channel number to be between 128 and 255. For RX port
-	 * use channel numbers from 138 to 144, for TX port
-	 * use channel numbers from 128 to 137
+	/*
+	 * DSP requires channel number to be between 128 and 255.
 	 */
-	pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+	pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
 	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++) {
 		slave_port_id = (ch_idx + 1 +
 				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
 		rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
-		ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
 					&rx[ch_idx].sph, SLIM_SINK);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
@@ -119,7 +121,7 @@
 			goto err;
 		}
 
-		ret = slim_query_ch(tabla->slim, rx[ch_idx].ch_num,
+		ret = slim_query_ch(wcd9xxx->slim, rx[ch_idx].ch_num,
 							&rx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
@@ -131,14 +133,15 @@
 	return ret;
 }
 
-static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la)
+static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
+			u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 	u8 ch_idx ;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	u16 slave_port_id = 0;
 
-	pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+	pr_err("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
 	/* DSP requires channel number to be between 128 and 255. For RX port
 	 * use channel numbers from 138 to 144, for TX port
 	 * use channel numbers from 128 to 137
@@ -146,14 +149,14 @@
 	for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++) {
 		slave_port_id = ch_idx;
 		tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
-		ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
 					&tx[ch_idx].sph, SLIM_SRC);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
 					__func__, slave_port_id, ret);
 			goto err;
 		}
-		ret = slim_query_ch(tabla->slim, tx[ch_idx].ch_num,
+		ret = slim_query_ch(wcd9xxx->slim, tx[ch_idx].ch_num,
 							&tx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
@@ -165,14 +168,14 @@
 	return ret;
 }
 
-static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab)
+static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx)
 {
 	int idx = 0;
 	int ret = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	/* slim_dealloc_ch */
 	for (idx = 0; idx < SLIM_MAX_RX_PORTS; idx++) {
-		ret = slim_dealloc_ch(tab->slim, rx[idx].ch_h);
+		ret = slim_dealloc_ch(wcd9xxx->slim, rx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
 				__func__, ret, rx[idx].ch_h);
@@ -182,14 +185,14 @@
 	return ret;
 }
 
-static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab)
+static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx)
 {
 	int idx = 0;
 	int ret = 0;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	/* slim_dealloc_ch */
 	for (idx = 0; idx < SLIM_MAX_TX_PORTS; idx++) {
-		ret = slim_dealloc_ch(tab->slim, tx[idx].ch_h);
+		ret = slim_dealloc_ch(wcd9xxx->slim, tx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
 				__func__, ret, tx[idx].ch_h);
@@ -200,7 +203,7 @@
 }
 
 /* Enable slimbus slave device for RX path */
-int tabla_cfg_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt, unsigned int rate)
 {
 	u8 i = 0;
@@ -211,15 +214,15 @@
 	u8  payload_rx = 0, wm_payload = 0;
 	int ret, idx = 0;
 	unsigned short  multi_chan_cfg_reg_addr;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	struct slim_ch prop;
 
 	/* Configure slave interface device */
-	pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
+	pr_err("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
 
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
 		ch_h[i] = rx[idx].ch_h;
 		sph[i] = rx[idx].sph;
 		slave_port_id = idx + 1;
@@ -236,7 +239,7 @@
 		 */
 		if ((slave_port_id >
 				SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) &&
-			(slave_port_id <
+			(slave_port_id <=
 			 SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID)) {
 				payload_rx = payload_rx  |
 				(1 <<
@@ -249,7 +252,8 @@
 		multi_chan_cfg_reg_addr =
 				SB_PGD_RX_PORT_MULTI_CHANNEL_0(slave_port_id);
 		/* write to interface device */
-		ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				multi_chan_cfg_reg_addr,
 				payload_rx);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -262,7 +266,7 @@
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
 				SLAVE_PORT_WATER_MARK_SHIFT) +
 				SLAVE_PORT_ENABLE;
-		ret = tabla_interface_reg_write(tab,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
 				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
 				wm_payload);
 		if (ret < 0) {
@@ -279,7 +283,7 @@
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
 
-	ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
 					true, &grph);
 	if (ret < 0) {
 		pr_err("%s: slim_define_ch failed ret[%d]\n",
@@ -287,7 +291,7 @@
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_sink(tab->slim, &sph[i],
+		ret = slim_connect_sink(wcd9xxx->slim, &sph[i],
 							1, ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_sink failed ret[%d]\n",
@@ -296,7 +300,7 @@
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
 					true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
@@ -312,14 +316,14 @@
 
 err_close_slim_sch:
 	/*  release all acquired handles */
-	tabla_close_slim_sch_rx(tab, ch_num, ch_cnt);
+	wcd9xxx_close_slim_sch_rx(wcd9xxx, ch_num, ch_cnt);
 err:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_rx);
+EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_rx);
 
 /* Enable slimbus slave device for RX path */
-int tabla_cfg_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt, unsigned int rate)
 {
 	u8 i = 0;
@@ -331,7 +335,7 @@
 	int ret = 0;
 	unsigned short  multi_chan_cfg_reg_addr;
 
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	struct slim_ch prop;
 
 	pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
@@ -366,7 +370,8 @@
 		multi_chan_cfg_reg_addr =
 				SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
 		/* write to interface device */
-		ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				multi_chan_cfg_reg_addr,
 				payload_tx_0);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -378,7 +383,8 @@
 		multi_chan_cfg_reg_addr =
 				SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
 		/* ports 8,9 */
-		ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				multi_chan_cfg_reg_addr,
 				payload_tx_1);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -391,7 +397,7 @@
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
 				SLAVE_PORT_WATER_MARK_SHIFT) +
 				SLAVE_PORT_ENABLE;
-		ret = tabla_interface_reg_write(tab,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
 				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
 				wm_payload);
 		if (ret < 0) {
@@ -408,7 +414,7 @@
 	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
-	ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
 					true, &grph);
 	if (ret < 0) {
 		pr_err("%s: slim_define_ch failed ret[%d]\n",
@@ -416,7 +422,7 @@
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_src(tab->slim, sph[i],
+		ret = slim_connect_src(wcd9xxx->slim, sph[i],
 							ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_src failed ret[%d]\n",
@@ -425,7 +431,7 @@
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
 					true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
@@ -439,21 +445,21 @@
 	return 0;
 err:
 	/* release all acquired handles */
-	tabla_close_slim_sch_tx(tab, ch_num, ch_cnt);
+	wcd9xxx_close_slim_sch_tx(wcd9xxx, ch_num, ch_cnt);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_tx);
+EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_tx);
 
-int tabla_close_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt)
 {
 	u16 grph = 0;
 	u32 sph[SLIM_MAX_RX_PORTS] = {0};
 	int i = 0 , idx = 0;
 	int ret = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 
-	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+	pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM -
 				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
@@ -462,13 +468,13 @@
 	}
 
 	/* slim_disconnect_port */
-	ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
 	if (ret < 0) {
 		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
 				__func__, ret);
 	}
 	/* slim_control_ch (REMOVE) */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
@@ -482,31 +488,31 @@
 err:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_close_slim_sch_rx);
+EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
 
-int tabla_close_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt)
 {
 	u16 grph = 0;
 	u32 sph[SLIM_MAX_TX_PORTS] = {0};
 	int ret = 0;
 	int i = 0 , idx = 0;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 
-	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+	pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM);
 		sph[i] = tx[idx].sph;
 		grph = tx[idx].grph;
 	}
 	/* slim_disconnect_port */
-	ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
 	if (ret < 0) {
 		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
 				__func__, ret);
 	}
 	/* slim_control_ch (REMOVE) */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
@@ -519,4 +525,4 @@
 err:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_close_slim_sch_tx);
+EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_tx);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 43eb169..e0da766 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -487,7 +487,7 @@
 	  module will be called bmp085.
 
 config PCH_PHUB
-	tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB"
+	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
 	depends on PCI
 	help
 	  This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of
@@ -495,12 +495,13 @@
 	  processor. The Topcliff has MAC address and Option ROM data in SROM.
 	  This driver can access MAC address and Option ROM data in SROM.
 
-	  This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
-	  Output Hub), ML7213 and ML7223.
-	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
-	  for MP(Media Phone) use.
-	  ML7213/ML7223 is companion chip for Intel Atom E6xx series.
-	  ML7213/ML7223 is completely compatible for Intel EG20T PCH.
+	  This driver also can be used for LAPIS Semiconductor's IOH,
+	  ML7213/ML7223/ML7831.
+	  ML7213 which is for IVI(In-Vehicle Infotainment) use.
+	  ML7223 IOH is for MP(Media Phone) use.
+	  ML7831 IOH is for general purpose use.
+	  ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+	  ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
 
 	  To compile this driver as a module, choose M here: the module will
 	  be called pch_phub.
@@ -627,6 +628,13 @@
 	  TrustZone Operating Environment (TZBSP) using Secure Channel
 	  Manager (SCM) interface.
 
+config QSEECOM
+	tristate "Qualcomm Secure Execution Communicator driver"
+	help
+	  Provides a communication interface between userspace and
+	  Qualcomm Secure Execution Environment (QSEE) using Secure Channel
+	  Manager (SCM) interface.
+
 config QFP_FUSE
 	tristate "QFPROM Fuse Read/Write support"
 	help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6b5fdcc..fb78f4e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -64,4 +64,5 @@
 	+= msm_migrate_pages.o
 obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
 obj-$(CONFIG_TZCOM) += tzcom.o
+obj-$(CONFIG_QSEECOM) += qseecom.o
 obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c
index efec413..b1f16d6 100644
--- a/drivers/misc/cb710/core.c
+++ b/drivers/misc/cb710/core.c
@@ -244,6 +244,7 @@
 	if (err)
 		return err;
 
+	spin_lock_init(&chip->irq_lock);
 	chip->pdev = pdev;
 	chip->iobase = pcim_iomap_table(pdev)[0];
 
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index 5fe79df..97e1a1f 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -73,6 +73,9 @@
 #define PCI_DEVICE_ID_ROHM_ML7223_mPHUB	0x8012 /* for Bus-m */
 #define PCI_DEVICE_ID_ROHM_ML7223_nPHUB	0x8002 /* for Bus-n */
 
+/* Macros for ML7831 */
+#define PCI_DEVICE_ID_ROHM_ML7831_PHUB 0x8801
+
 /* SROM ACCESS Macro */
 #define PCH_WORD_ADDR_MASK (~((1 << 2) - 1))
 
@@ -464,7 +467,7 @@
 	int retval;
 	int i;
 
-	if (chip->ioh_type == 1) /* EG20T */
+	if ((chip->ioh_type == 1) || (chip->ioh_type == 5)) /* EG20T or ML7831*/
 		retval = pch_phub_gbe_serial_rom_conf(chip);
 	else	/* ML7223 */
 		retval = pch_phub_gbe_serial_rom_conf_mp(chip);
@@ -754,6 +757,22 @@
 		chip->pch_opt_rom_start_address =\
 						 PCH_PHUB_ROM_START_ADDR_ML7223;
 		chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223;
+	} else if (id->driver_data == 5) { /* ML7831 */
+		retval = sysfs_create_file(&pdev->dev.kobj,
+					   &dev_attr_pch_mac.attr);
+		if (retval)
+			goto err_sysfs_create;
+
+		retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr);
+		if (retval)
+			goto exit_bin_attr;
+
+		/* set the prefech value */
+		iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14);
+		/* set the interrupt delay value */
+		iowrite32(0x25, chip->pch_phub_base_address + 0x44);
+		chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T;
+		chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T;
 	}
 
 	chip->ioh_type = id->driver_data;
@@ -838,6 +857,7 @@
 	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2,  },
 	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3,  },
 	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_nPHUB), 4,  },
+	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7831_PHUB), 5,  },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id);
diff --git a/drivers/misc/pmic8058-xoadc.c b/drivers/misc/pmic8058-xoadc.c
index 14b790f..3452672 100644
--- a/drivers/misc/pmic8058-xoadc.c
+++ b/drivers/misc/pmic8058-xoadc.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
@@ -650,23 +650,6 @@
 #define PM8058_XOADC_DEV_PM_OPS NULL
 #endif
 
-static int __devexit pm8058_xoadc_teardown(struct platform_device *pdev)
-{
-	struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
-
-	if (adc_pmic->pdata->xoadc_vreg_shutdown != NULL)
-		adc_pmic->pdata->xoadc_vreg_shutdown();
-
-	wake_lock_destroy(&adc_pmic->adc_wakelock);
-	msm_xo_put(adc_pmic->adc_voter);
-	platform_set_drvdata(pdev, NULL);
-	device_init_wakeup(&pdev->dev, 0);
-	kfree(adc_pmic);
-	xoadc_initialized = false;
-
-	return 0;
-}
-
 static int __devinit pm8058_xoadc_probe(struct platform_device *pdev)
 {
 	struct xoadc_platform_data *pdata = pdev->dev.platform_data;
@@ -678,7 +661,7 @@
 		return -EINVAL;
 	}
 
-	adc_pmic = kzalloc(sizeof(struct pmic8058_adc), GFP_KERNEL);
+	adc_pmic = devm_kzalloc(&pdev->dev, sizeof(*adc_pmic), GFP_KERNEL);
 	if (!adc_pmic) {
 		dev_err(&pdev->dev, "Unable to allocate memory\n");
 		return -ENOMEM;
@@ -693,17 +676,16 @@
 
 	if (adc_pmic->xoadc_num > XOADC_PMIC_0) {
 		dev_err(&pdev->dev, "ADC device not supported\n");
-		rc = -EINVAL;
-		goto err_cleanup;
+		return -EINVAL;
 	}
 
 	adc_pmic->pdata = pdata;
-	adc_pmic->adc_graph = kzalloc(sizeof(struct linear_graph)
-			* MAX_CHANNEL_PROPERTIES_QUEUE, GFP_KERNEL);
+	adc_pmic->adc_graph = devm_kzalloc(&pdev->dev,
+		sizeof(struct linear_graph) * MAX_CHANNEL_PROPERTIES_QUEUE,
+		GFP_KERNEL);
 	if (!adc_pmic->adc_graph) {
 		dev_err(&pdev->dev, "Unable to allocate memory\n");
-		rc = -ENOMEM;
-		goto err_cleanup;
+		return -ENOMEM;
 	}
 
 	/* Will be replaced by individual channel calibration */
@@ -739,32 +721,29 @@
 	INIT_LIST_HEAD(&adc_pmic->conv_queue_list->slots);
 
 	adc_pmic->adc_irq = platform_get_irq(pdev, 0);
-	if (adc_pmic->adc_irq < 0) {
-		rc = -ENXIO;
-		goto err_cleanup;
-	}
+	if (adc_pmic->adc_irq < 0)
+		return -ENXIO;
 
 	rc = request_threaded_irq(adc_pmic->adc_irq,
 				NULL, pm8058_xoadc,
 		IRQF_TRIGGER_RISING, "pm8058_adc_interrupt", adc_pmic);
 	if (rc) {
 		dev_err(&pdev->dev, "failed to request adc irq\n");
-		goto err_cleanup;
+		return rc;
 	}
 
 	disable_irq(adc_pmic->adc_irq);
 
-	device_init_wakeup(&pdev->dev, pdata->xoadc_wakeup);
-
 	if (adc_pmic->adc_voter == NULL) {
 		adc_pmic->adc_voter = msm_xo_get(MSM_XO_TCXO_D1,
 							"pmic8058_xoadc");
 		if (IS_ERR(adc_pmic->adc_voter)) {
 			dev_err(&pdev->dev, "Failed to get XO vote\n");
-			goto err_cleanup;
+			return PTR_ERR(adc_pmic->adc_voter);
 		}
 	}
 
+	device_init_wakeup(&pdev->dev, pdata->xoadc_wakeup);
 	wake_lock_init(&adc_pmic->adc_wakelock, WAKE_LOCK_SUSPEND,
 					"pmic8058_xoadc_wakelock");
 
@@ -777,11 +756,21 @@
 	xoadc_calib_first_adc = false;
 
 	return 0;
+}
 
-err_cleanup:
-	pm8058_xoadc_teardown(pdev);
+static int __devexit pm8058_xoadc_teardown(struct platform_device *pdev)
+{
+	struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
 
-	return rc;
+	if (adc_pmic->pdata->xoadc_vreg_shutdown != NULL)
+		adc_pmic->pdata->xoadc_vreg_shutdown();
+
+	wake_lock_destroy(&adc_pmic->adc_wakelock);
+	msm_xo_put(adc_pmic->adc_voter);
+	device_init_wakeup(&pdev->dev, 0);
+	xoadc_initialized = false;
+
+	return 0;
 }
 
 static struct platform_driver pm8058_xoadc_driver = {
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
new file mode 100644
index 0000000..60e1e55
--- /dev/null
+++ b/drivers/misc/qseecom.c
@@ -0,0 +1,1528 @@
+
+/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+ *
+ * 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) "QSEECOM: %s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/qseecom.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include "qseecom_legacy.h"
+
+#define QSEECOM_DEV			"qseecom"
+#define QSEOS_VERSION_13		0x13
+#define QSEOS_VERSION_14		0x14
+#define QSEOS_CHECK_VERSION_CMD		0x00001803;
+
+enum qseecom_command_scm_resp_type {
+	QSEOS_APP_ID = 0xEE01,
+	QSEOS_LISTENER_ID
+};
+
+enum qseecom_qceos_cmd_id {
+	QSEOS_APP_START_COMMAND      = 0x01,
+	QSEOS_APP_SHUTDOWN_COMMAND,
+	QSEOS_APP_LOOKUP_COMMAND,
+	QSEOS_REGISTER_LISTENER,
+	QSEOS_DEREGISTER_LISTENER,
+	QSEOS_CLIENT_SEND_DATA_COMMAND,
+	QSEOS_LISTENER_DATA_RSP_COMMAND,
+	QSEOS_CMD_MAX     = 0xEFFFFFFF
+};
+
+enum qseecom_qceos_cmd_status {
+	QSEOS_RESULT_SUCCESS = 0,
+	QSEOS_RESULT_INCOMPLETE,
+	QSEOS_RESULT_FAILURE  = 0xFFFFFFFF
+};
+
+__packed struct qseecom_check_app_ireq {
+	uint32_t qsee_cmd_id;
+	char     app_name[MAX_APP_NAME_SIZE];
+};
+
+__packed struct qseecom_load_app_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t mdt_len;		/* Length of the mdt file */
+	uint32_t img_len;		/* Length of .bxx and .mdt files */
+	uint32_t phy_addr;		/* phy addr of the start of image */
+	char     app_name[MAX_APP_NAME_SIZE];	/* application name*/
+};
+
+__packed struct qseecom_unload_app_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t  app_id;
+};
+
+__packed struct qseecom_register_listener_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t listener_id;
+	void *sb_ptr;
+	uint32_t sb_len;
+};
+
+__packed struct qseecom_unregister_listener_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t  listener_id;
+};
+
+__packed struct qseecom_client_send_data_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t app_id;
+	void *req_ptr;
+	uint32_t req_len;
+	void *rsp_ptr;   /* First 4 bytes should always be the return status */
+	uint32_t rsp_len;
+};
+
+/* send_data resp */
+__packed struct qseecom_client_listener_data_irsp {
+	uint32_t qsee_cmd_id;
+	uint32_t listener_id;
+};
+
+/*
+ * struct qseecom_command_scm_resp - qseecom response buffer
+ * @cmd_status: value from enum tz_sched_cmd_status
+ * @sb_in_rsp_addr: points to physical location of response
+ *                buffer
+ * @sb_in_rsp_len: length of command response
+ */
+__packed struct qseecom_command_scm_resp {
+	uint32_t result;
+	enum qseecom_command_scm_resp_type resp_type;
+	unsigned int data;
+};
+
+static struct class *driver_class;
+static dev_t qseecom_device_no;
+static struct cdev qseecom_cdev;
+
+/* Data structures used in legacy support */
+static void *pil;
+static uint32_t pil_ref_cnt;
+static DEFINE_MUTEX(pil_access_lock);
+
+static DEFINE_MUTEX(send_msg_lock);
+static DEFINE_MUTEX(qsee_bw_mutex);
+static DEFINE_MUTEX(app_access_lock);
+
+static int qsee_bw_count;
+static struct clk *qseecom_bus_clk;
+static uint32_t qsee_perf_client;
+
+struct qseecom_registered_listener_list {
+	struct list_head                 list;
+	struct qseecom_register_listener_req svc;
+	u8  *sb_reg_req;
+	u8 *sb_virt;
+	s32 sb_phys;
+	size_t sb_length;
+	struct ion_handle *ihandle; /* Retrieve phy addr */
+
+	wait_queue_head_t          rcv_req_wq;
+	int                        rcv_req_flag;
+};
+
+struct qseecom_registered_app_list {
+	struct list_head                 list;
+	u32  app_id;
+	u32  ref_cnt;
+};
+
+struct qseecom_control {
+	struct ion_client *ion_clnt;		/* Ion client */
+	struct list_head  registered_listener_list_head;
+	spinlock_t        registered_listener_list_lock;
+
+	struct list_head  registered_app_list_head;
+	spinlock_t        registered_app_list_lock;
+
+	wait_queue_head_t send_resp_wq;
+	int               send_resp_flag;
+
+	uint32_t          qseos_version;
+};
+
+struct qseecom_client_handle {
+	u32  app_id;
+	u8 *sb_virt;
+	s32 sb_phys;
+	uint32_t user_virt_sb_base;
+	size_t sb_length;
+	struct ion_handle *ihandle;		/* Retrieve phy addr */
+};
+
+struct qseecom_listener_handle {
+	u32               id;
+};
+
+static struct qseecom_control qseecom;
+
+struct qseecom_dev_handle {
+	bool               service;
+	union {
+		struct qseecom_client_handle client;
+		struct qseecom_listener_handle listener;
+	};
+	bool released;
+	int               abort;
+	wait_queue_head_t abort_wq;
+	atomic_t          ioctl_count;
+};
+
+static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
+		struct qseecom_register_listener_req *svc)
+{
+	struct qseecom_registered_listener_list *ptr;
+	int unique = 1;
+	unsigned long flags;
+
+	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) {
+			pr_err("Service id: %u is already registered\n",
+					ptr->svc.listener_id);
+			unique = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+	return unique;
+}
+
+static struct qseecom_registered_listener_list *__qseecom_find_svc(
+						int32_t listener_id)
+{
+	struct qseecom_registered_listener_list *entry = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
+	{
+		if (entry->svc.listener_id == listener_id)
+			break;
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+	return entry;
+}
+
+static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
+				struct qseecom_dev_handle *handle,
+				struct qseecom_register_listener_req *listener)
+{
+	int ret = 0;
+	unsigned int flags = 0;
+	struct qseecom_register_listener_ireq req;
+	struct qseecom_command_scm_resp resp;
+	ion_phys_addr_t pa;
+
+	/* Get the handle of the shared fd */
+	svc->ihandle = ion_import_fd(qseecom.ion_clnt, listener->ifd_data_fd);
+	if (svc->ihandle == NULL) {
+		pr_err("Ion client could not retrieve the handle\n");
+		return -ENOMEM;
+	}
+
+	/* Get the physical address of the ION BUF */
+	ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
+
+	/* Populate the structure for sending scm call to load image */
+	svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
+							svc->ihandle, flags);
+	svc->sb_phys = pa;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_14) {
+		req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
+		req.listener_id = svc->svc.listener_id;
+		req.sb_len = svc->sb_length;
+		req.sb_ptr = (void *)svc->sb_phys;
+
+		resp.result = QSEOS_RESULT_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+					sizeof(req), &resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return -EINVAL;
+		}
+
+		if (resp.result != QSEOS_RESULT_SUCCESS) {
+			pr_err("Error SB registration req: resp.result = %d\n",
+					resp.result);
+			return -EPERM;
+		}
+	} else {
+		struct qseecom_command cmd;
+		struct qseecom_response resp;
+		struct qse_pr_init_sb_req_s sb_init_req;
+		struct qse_pr_init_sb_rsp_s sb_init_rsp;
+
+		svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
+					sizeof(sb_init_rsp)), GFP_KERNEL);
+
+		sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
+		sb_init_req.listener_id = svc->svc.listener_id;
+		sb_init_req.sb_len = svc->sb_length;
+		sb_init_req.sb_ptr = svc->sb_phys;
+
+		memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
+
+		/* It will always be a new cmd from this method */
+		cmd.cmd_type = TZ_SCHED_CMD_NEW;
+		cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
+		cmd.sb_in_cmd_len = sizeof(sb_init_req);
+
+		resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
+				, &resp, sizeof(resp));
+
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return -EINVAL;
+		}
+
+		if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+			pr_err("SB registration fail resp.cmd_status %d\n",
+							resp.cmd_status);
+			return -EINVAL;
+		}
+		memset(svc->sb_virt, 0, svc->sb_length);
+	}
+	return 0;
+}
+
+static int qseecom_register_listener(struct qseecom_dev_handle *data,
+					void __user *argp)
+{
+	int ret = 0;
+	unsigned long flags;
+	struct qseecom_register_listener_req rcvd_lstnr;
+	struct qseecom_registered_listener_list *new_entry;
+
+	ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+	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");
+		data->released = true;
+		return -EBUSY;
+	}
+
+	new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
+	if (!new_entry) {
+		pr_err("kmalloc failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
+	new_entry->rcv_req_flag = 0;
+
+	new_entry->svc.listener_id = rcvd_lstnr.listener_id;
+	new_entry->sb_length = rcvd_lstnr.sb_size;
+	if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
+		pr_err("qseecom_set_sb_memoryfailed\n");
+		kzfree(new_entry);
+		return -ENOMEM;
+	}
+
+	data->listener.id = rcvd_lstnr.listener_id;
+	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;
+}
+
+static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+{
+	int ret = 0;
+	unsigned long flags;
+	uint32_t unmap_mem = 0;
+	struct qseecom_register_listener_ireq req;
+	struct qseecom_registered_listener_list *ptr_svc = NULL;
+	struct qseecom_command_scm_resp resp;
+	struct ion_handle *ihandle = NULL;		/* Retrieve phy addr */
+
+	if (qseecom.qseos_version == QSEOS_VERSION_14) {
+		req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
+		req.listener_id = data->listener.id;
+		resp.result = QSEOS_RESULT_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+					sizeof(req), &resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+
+		if (resp.result != QSEOS_RESULT_SUCCESS) {
+			pr_err("SB deregistartion: result=%d\n", resp.result);
+			return -EPERM;
+		}
+	} else {
+		struct qse_pr_init_sb_req_s sb_init_req;
+		struct qseecom_command cmd;
+		struct qseecom_response resp;
+		struct qseecom_registered_listener_list *svc;
+
+		svc = __qseecom_find_svc(data->listener.id);
+		sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
+		sb_init_req.listener_id = data->listener.id;
+		sb_init_req.sb_len = 0;
+		sb_init_req.sb_ptr = 0;
+
+		memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
+
+		/* It will always be a new cmd from this method */
+		cmd.cmd_type = TZ_SCHED_CMD_NEW;
+		cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
+		cmd.sb_in_cmd_len = sizeof(sb_init_req);
+		resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
+					&resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+		kzfree(svc->sb_reg_req);
+		if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+			pr_err("Error with SB initialization\n");
+			return -EPERM;
+		}
+	}
+	data->abort = 1;
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
+			list) {
+		if (ptr_svc->svc.listener_id == data->listener.id) {
+			wake_up_all(&ptr_svc->rcv_req_wq);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+	while (atomic_read(&data->ioctl_count) > 1) {
+		if (wait_event_interruptible(data->abort_wq,
+				atomic_read(&data->ioctl_count) <= 1)) {
+			pr_err("Interrupted from abort\n");
+			ret = -ERESTARTSYS;
+			break;
+		}
+	}
+
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_for_each_entry(ptr_svc,
+			&qseecom.registered_listener_list_head,
+			list)
+	{
+		if (ptr_svc->svc.listener_id == data->listener.id) {
+			if (ptr_svc->sb_virt) {
+				unmap_mem = 1;
+				ihandle = ptr_svc->ihandle;
+				}
+			list_del(&ptr_svc->list);
+			kzfree(ptr_svc);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+	/* Unmap the memory */
+	if (unmap_mem) {
+		if (!IS_ERR_OR_NULL(ihandle)) {
+			ion_unmap_kernel(qseecom.ion_clnt, ihandle);
+			ion_free(qseecom.ion_clnt, ihandle);
+			}
+	}
+	data->released = true;
+	return ret;
+}
+
+static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
+						void __user *argp)
+{
+	ion_phys_addr_t pa;
+	int32_t ret;
+	unsigned int flags = 0;
+	struct qseecom_set_sb_mem_param_req req;
+	uint32_t len;
+
+	/* Copy the relevant information needed for loading the image */
+	if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
+		return -EFAULT;
+
+	/* Get the handle of the shared fd */
+	data->client.ihandle = ion_import_fd(qseecom.ion_clnt, req.ifd_data_fd);
+	if (IS_ERR_OR_NULL(data->client.ihandle)) {
+		pr_err("Ion client could not retrieve the handle\n");
+		return -ENOMEM;
+	}
+	/* Get the physical address of the ION BUF */
+	ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+	/* Populate the structure for sending scm call to load image */
+	data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
+							data->client.ihandle,
+							flags);
+	data->client.sb_phys = pa;
+	data->client.sb_length = req.sb_len;
+	data->client.user_virt_sb_base = req.virt_sb_base;
+	return 0;
+}
+
+
+static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
+{
+	int ret;
+	ret = (qseecom.send_resp_flag != 0);
+	return ret || data->abort;
+}
+
+static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
+					struct qseecom_command_scm_resp *resp)
+{
+	int ret = 0;
+	uint32_t lstnr;
+	unsigned long flags;
+	struct qseecom_client_listener_data_irsp send_data_rsp;
+	struct qseecom_registered_listener_list *ptr_svc = NULL;
+
+
+	while (resp->result == QSEOS_RESULT_INCOMPLETE) {
+		lstnr = resp->data;
+		/*
+		 * Wake up blocking lsitener service with the lstnr id
+		 */
+		spin_lock_irqsave(&qseecom.registered_listener_list_lock,
+					flags);
+		list_for_each_entry(ptr_svc,
+				&qseecom.registered_listener_list_head, list) {
+			if (ptr_svc->svc.listener_id == lstnr) {
+				ptr_svc->rcv_req_flag = 1;
+				wake_up_interruptible(&ptr_svc->rcv_req_wq);
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
+				flags);
+		if (ptr_svc->svc.listener_id != lstnr) {
+			pr_warning("Service requested for does on exist\n");
+			return -ERESTARTSYS;
+		}
+		pr_debug("waking up rcv_req_wq and "
+				"waiting for send_resp_wq\n");
+		if (wait_event_interruptible(qseecom.send_resp_wq,
+				__qseecom_listener_has_sent_rsp(data))) {
+			pr_warning("Interrupted: exiting send_cmd loop\n");
+			return -ERESTARTSYS;
+		}
+
+		if (data->abort) {
+			pr_err("Aborting listener service %d\n",
+				data->listener.id);
+			return -ENODEV;
+		}
+		qseecom.send_resp_flag = 0;
+		send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
+		send_data_rsp.listener_id  = lstnr ;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
+					(const void *)&send_data_rsp,
+					sizeof(send_data_rsp), resp,
+					sizeof(*resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
+{
+	struct qseecom_registered_app_list *entry = NULL;
+	unsigned long flags = 0;
+	u32 app_id = 0;
+	struct ion_handle *ihandle;	/* Ion handle */
+	struct qseecom_load_img_req load_img_req;
+	int32_t ret;
+	ion_phys_addr_t pa = 0;
+	uint32_t len;
+	struct qseecom_command_scm_resp resp;
+	struct qseecom_check_app_ireq req;
+	/* Copy the relevant information needed for loading the image */
+	if (__copy_from_user(&load_img_req,
+				(void __user *)argp,
+				sizeof(struct qseecom_load_img_req))) {
+		pr_err("copy_from_user failed\n");
+		return -EFAULT;
+	}
+
+	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+	memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
+
+	/*  SCM_CALL  to check if app_id for the mentioned app exists */
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+				sizeof(struct qseecom_check_app_ireq),
+				&resp, sizeof(resp));
+
+	if (resp.result == QSEOS_RESULT_FAILURE)
+		app_id = 0;
+	else
+		app_id = resp.data;
+
+	if (app_id) {
+		pr_warn("App id %d (%s) already exists\n", app_id,
+			(char *)(req.app_name));
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_for_each_entry(entry,
+				&qseecom.registered_app_list_head, list){
+			if (entry->app_id == app_id) {
+				entry->ref_cnt++;
+				break;
+			}
+		}
+		spin_unlock_irqrestore(
+				&qseecom.registered_app_list_lock, flags);
+	} else {
+		struct qseecom_load_app_ireq load_req;
+
+		pr_warn("App (%s) does not exist, loading apps for first time\n",
+			(char *)(load_req.app_name));
+		/* Get the handle of the shared fd */
+		ihandle = ion_import_fd(qseecom.ion_clnt,
+					load_img_req.ifd_data_fd);
+		if (IS_ERR_OR_NULL(ihandle)) {
+			pr_err("Ion client could not retrieve the handle\n");
+			return -ENOMEM;
+		}
+
+		/* Get the physical address of the ION BUF */
+		ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
+
+		/* Populate the structure for sending scm call to load image */
+		load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
+		load_req.mdt_len = load_img_req.mdt_len;
+		load_req.img_len = load_img_req.img_len;
+		load_req.phy_addr = pa;
+
+		/*  SCM_CALL  to load the app and get the app_id back */
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &load_req,
+				sizeof(struct qseecom_load_app_ireq),
+				&resp, sizeof(resp));
+
+		if (resp.result == QSEOS_RESULT_FAILURE) {
+			pr_err("scm_call failed resp.result QSEOS_RESULT_FAILURE -1\n");
+			if (!IS_ERR_OR_NULL(ihandle))
+				ion_free(qseecom.ion_clnt, ihandle);
+			return -EFAULT;
+		}
+
+		if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+			ret = __qseecom_process_incomplete_cmd(data, &resp);
+			if (ret) {
+				pr_err("process_incomplete_cmd failed err: %d\n",
+						ret);
+				if (!IS_ERR_OR_NULL(ihandle))
+					ion_free(qseecom.ion_clnt, ihandle);
+				return ret;
+			}
+		}
+		if (resp.result != QSEOS_RESULT_SUCCESS) {
+			pr_err("scm_call failed resp.result unknown, %d\n",
+					resp.result);
+			if (!IS_ERR_OR_NULL(ihandle))
+				ion_free(qseecom.ion_clnt, ihandle);
+			return -EFAULT;
+		}
+
+		app_id = resp.data;
+
+		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+		if (!entry) {
+			pr_err("kmalloc failed\n");
+			return -ENOMEM;
+		}
+		entry->app_id = app_id;
+		entry->ref_cnt = 1;
+
+		/* Deallocate the handle */
+		if (!IS_ERR_OR_NULL(ihandle))
+			ion_free(qseecom.ion_clnt, ihandle);
+
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_add_tail(&entry->list, &qseecom.registered_app_list_head);
+		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+					flags);
+
+		pr_warn("App with id %d  (%s) now loaded\n", app_id,
+			(char *)(load_req.app_name));
+	}
+	data->client.app_id = app_id;
+	load_img_req.app_id = app_id;
+	if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
+		pr_err("copy_to_user failed\n");
+		kzfree(entry);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
+{
+	wake_up_all(&qseecom.send_resp_wq);
+	while (atomic_read(&data->ioctl_count) > 1) {
+		if (wait_event_interruptible(data->abort_wq,
+					atomic_read(&data->ioctl_count) <= 1)) {
+			pr_err("Interrupted from abort\n");
+			return -ERESTARTSYS;
+			break;
+		}
+	}
+	/* Set unload app */
+	return 1;
+}
+
+static int qseecom_unload_app(struct qseecom_dev_handle *data)
+{
+	unsigned long flags;
+	int ret = 0;
+	struct qseecom_command_scm_resp resp;
+	struct qseecom_registered_app_list *ptr_app;
+	uint32_t unload = 0;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_14) {
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
+								list) {
+			if (ptr_app->app_id == data->client.app_id) {
+				if (ptr_app->ref_cnt == 1) {
+					unload = __qseecom_cleanup_app(data);
+					list_del(&ptr_app->list);
+					kzfree(ptr_app);
+					pr_warn("App id %d now unloaded\n",
+							ptr_app->app_id);
+					break;
+				} else {
+					ptr_app->ref_cnt--;
+					data->released = true;
+					pr_warn("Can't unload app with id %d (it is inuse)\n",
+							ptr_app->app_id);
+					break;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+								flags);
+	}
+	if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+		ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+		ion_free(qseecom.ion_clnt, data->client.ihandle);
+	}
+
+	if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
+		struct qseecom_unload_app_ireq req;
+
+		/* Populate the structure for sending scm call to load image */
+		req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
+		req.app_id = data->client.app_id;
+
+		/* SCM_CALL to unload the app */
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+				sizeof(struct qseecom_unload_app_ireq),
+				&resp, sizeof(resp));
+		if (ret) {
+			pr_err("Fail to unload app id %d\n", req.app_id);
+			return -EFAULT;
+		}
+		if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+			ret = __qseecom_process_incomplete_cmd(data, &resp);
+			if (ret) {
+				pr_err("process_incomplete_cmd fail err: %d\n",
+						ret);
+				return ret;
+			}
+		}
+	}
+
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		data->abort = 1;
+		wake_up_all(&qseecom.send_resp_wq);
+		while (atomic_read(&data->ioctl_count) > 0) {
+			if (wait_event_interruptible(data->abort_wq,
+					atomic_read(&data->ioctl_count) <= 0)) {
+				pr_err("Interrupted from abort\n");
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+	}
+	data->released = true;
+	return ret;
+}
+
+static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
+						uint32_t virt)
+{
+	return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
+}
+
+static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
+				struct qseecom_send_cmd_req *req)
+{
+	int ret = 0;
+	unsigned long flags;
+	u32 reqd_len_sb_in = 0;
+	struct qseecom_command cmd;
+	struct qseecom_response resp;
+
+
+	if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+		pr_err("cmd buffer or response buffer is null\n");
+		return -EINVAL;
+	}
+
+	if (req->cmd_req_len <= 0 ||
+		req->resp_len <= 0 ||
+		req->cmd_req_len > data->client.sb_length ||
+		req->resp_len > data->client.sb_length) {
+		pr_err("cmd buffer length or "
+				"response buffer length not valid\n");
+		return -EINVAL;
+	}
+
+	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
+	if (reqd_len_sb_in > data->client.sb_length) {
+		pr_debug("Not enough memory to fit cmd_buf and "
+			"resp_buf. Required: %u, Available: %u\n",
+				reqd_len_sb_in, data->client.sb_length);
+		return -ENOMEM;
+	}
+	cmd.cmd_type = TZ_SCHED_CMD_NEW;
+	cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
+	cmd.sb_in_cmd_len = req->cmd_req_len;
+
+	resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+	resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
+	resp.sb_in_rsp_len = req->resp_len;
+
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
+					sizeof(cmd), &resp, sizeof(resp));
+
+	if (ret) {
+		pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
+		return ret;
+	}
+
+	while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+		/*
+		 * If cmd is incomplete, get the callback cmd out from SB out
+		 * and put it on the list
+		 */
+		struct qseecom_registered_listener_list *ptr_svc = NULL;
+		/*
+		 * We don't know which service can handle the command. so we
+		 * wake up all blocking services and let them figure out if
+		 * they can handle the given command.
+		 */
+		spin_lock_irqsave(&qseecom.registered_listener_list_lock,
+					flags);
+		list_for_each_entry(ptr_svc,
+				&qseecom.registered_listener_list_head, list) {
+				ptr_svc->rcv_req_flag = 1;
+				wake_up_interruptible(&ptr_svc->rcv_req_wq);
+		}
+		spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
+				flags);
+
+		pr_debug("waking up rcv_req_wq and "
+				"waiting for send_resp_wq\n");
+		if (wait_event_interruptible(qseecom.send_resp_wq,
+				__qseecom_listener_has_sent_rsp(data))) {
+			pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
+			return -ERESTARTSYS;
+		}
+
+		if (data->abort) {
+			pr_err("Aborting driver\n");
+			return -ENODEV;
+		}
+		qseecom.send_resp_flag = 0;
+		cmd.cmd_type = TZ_SCHED_CMD_PENDING;
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
+					sizeof(cmd), &resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
+				struct qseecom_send_cmd_req *req)
+{
+	int ret = 0;
+	u32 reqd_len_sb_in = 0;
+	struct qseecom_client_send_data_ireq send_data_req;
+	struct qseecom_command_scm_resp resp;
+
+	if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+		pr_err("cmd buffer or response buffer is null\n");
+		return -EINVAL;
+	}
+
+	if (req->cmd_req_len <= 0 ||
+		req->resp_len <= 0 ||
+		req->cmd_req_len > data->client.sb_length ||
+		req->resp_len > data->client.sb_length) {
+		pr_err("cmd buffer length or "
+				"response buffer length not valid\n");
+		return -EINVAL;
+	}
+
+	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
+	if (reqd_len_sb_in > data->client.sb_length) {
+		pr_debug("Not enough memory to fit cmd_buf and "
+			"resp_buf. Required: %u, Available: %u\n",
+				reqd_len_sb_in, data->client.sb_length);
+		return -ENOMEM;
+	}
+
+	send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
+	send_data_req.app_id = data->client.app_id;
+	send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
+					(uint32_t)req->cmd_req_buf));
+	send_data_req.req_len = req->cmd_req_len;
+	send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
+					(uint32_t)req->resp_buf));
+	send_data_req.rsp_len = req->resp_len;
+
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
+					sizeof(send_data_req),
+					&resp, sizeof(resp));
+	if (ret) {
+		pr_err("qseecom_scm_call failed with err: %d\n", ret);
+		return ret;
+	}
+
+	if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+		ret = __qseecom_process_incomplete_cmd(data, &resp);
+		if (ret) {
+			pr_err("process_incomplete_cmd failed err: %d\n", ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+
+static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
+{
+	int ret = 0;
+	struct qseecom_send_cmd_req req;
+
+	ret = copy_from_user(&req, argp, sizeof(req));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+	if (qseecom.qseos_version == QSEOS_VERSION_14)
+		ret = __qseecom_send_cmd(data, &req);
+	else
+		ret = __qseecom_send_cmd_legacy(data, &req);
+	if (ret)
+		return ret;
+
+	pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+			req.resp_len, req.resp_buf);
+	return ret;
+}
+
+static int __qseecom_send_cmd_req_clean_up(
+			struct qseecom_send_modfd_cmd_req *req)
+{
+	char *field;
+	uint32_t *update;
+	int ret = 0;
+	int i = 0;
+
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (req->ifd_data[i].fd > 0) {
+			field = (char *)req->cmd_req_buf +
+					req->ifd_data[i].cmd_buf_offset;
+			update = (uint32_t *) field;
+			*update = 0;
+		}
+	}
+	return ret;
+}
+
+static int __qseecom_update_with_phy_addr(
+			struct qseecom_send_modfd_cmd_req *req)
+{
+	struct ion_handle *ihandle;
+	char *field;
+	uint32_t *update;
+	ion_phys_addr_t pa;
+	int ret = 0;
+	int i = 0;
+	uint32_t length;
+
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (req->ifd_data[i].fd > 0) {
+			/* Get the handle of the shared fd */
+			ihandle = ion_import_fd(qseecom.ion_clnt,
+						req->ifd_data[i].fd);
+			if (IS_ERR_OR_NULL(ihandle)) {
+				pr_err("Ion client can't retrieve the handle\n");
+				return -ENOMEM;
+			}
+			field = (char *) req->cmd_req_buf +
+						req->ifd_data[i].cmd_buf_offset;
+			update = (uint32_t *) field;
+
+			/* Populate the cmd data structure with the phys_addr */
+			ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &length);
+			if (ret)
+				return -ENOMEM;
+
+			*update = (uint32_t)pa;
+			/* Deallocate the handle */
+			if (!IS_ERR_OR_NULL(ihandle))
+				ion_free(qseecom.ion_clnt, ihandle);
+		}
+	}
+	return ret;
+}
+
+static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
+					void __user *argp)
+{
+	int ret = 0;
+	struct qseecom_send_modfd_cmd_req req;
+	struct qseecom_send_cmd_req send_cmd_req;
+
+	ret = copy_from_user(&req, argp, sizeof(req));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+	send_cmd_req.cmd_req_buf = req.cmd_req_buf;
+	send_cmd_req.cmd_req_len = req.cmd_req_len;
+	send_cmd_req.resp_buf = req.resp_buf;
+	send_cmd_req.resp_len = req.resp_len;
+
+	ret = __qseecom_update_with_phy_addr(&req);
+	if (ret)
+		return ret;
+	if (qseecom.qseos_version == QSEOS_VERSION_14)
+		ret = __qseecom_send_cmd(data, &send_cmd_req);
+	else
+		ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
+	__qseecom_send_cmd_req_clean_up(&req);
+
+	if (ret)
+		return ret;
+
+	pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+			req.resp_len, req.resp_buf);
+	return ret;
+}
+
+static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
+		struct qseecom_registered_listener_list *svc)
+{
+	int ret;
+	ret = (svc->rcv_req_flag != 0);
+	return ret || data->abort;
+}
+
+static int qseecom_receive_req(struct qseecom_dev_handle *data)
+{
+	int ret = 0;
+	struct qseecom_registered_listener_list *this_lstnr;
+
+	this_lstnr = __qseecom_find_svc(data->listener.id);
+	while (1) {
+		if (wait_event_interruptible(this_lstnr->rcv_req_wq,
+				__qseecom_listener_has_rcvd_req(data,
+				this_lstnr))) {
+			pr_warning("Interrupted: exiting wait_rcv_req loop\n");
+			/* woken up for different reason */
+			return -ERESTARTSYS;
+		}
+
+		if (data->abort) {
+			pr_err("Aborting driver!\n");
+			return -ENODEV;
+		}
+		this_lstnr->rcv_req_flag = 0;
+		if (qseecom.qseos_version == QSEOS_VERSION_13) {
+			if (*((uint32_t *)this_lstnr->sb_virt) != 0)
+				break;
+		} else {
+			break;
+		}
+	}
+	return ret;
+}
+
+static int qseecom_send_resp(void)
+{
+	qseecom.send_resp_flag = 1;
+	wake_up_interruptible(&qseecom.send_resp_wq);
+	return 0;
+}
+
+static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
+						void __user *argp)
+{
+	struct qseecom_qseos_version_req req;
+
+	if (copy_from_user(&req, argp, sizeof(req))) {
+		pr_err("copy_from_user failed");
+		return -EINVAL;
+	}
+	req.qseos_version = qseecom.qseos_version;
+	if (copy_to_user(argp, &req, sizeof(req))) {
+		pr_err("copy_to_user failed");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int qsee_vote_for_clock(void)
+{
+	int ret = 0;
+
+	if (!qsee_perf_client)
+		return ret;
+
+	/* Check if the clk is valid */
+	if (IS_ERR_OR_NULL(qseecom_bus_clk)) {
+		pr_warn("qseecom bus clock is null or error");
+		return -EINVAL;
+	}
+
+	mutex_lock(&qsee_bw_mutex);
+	if (!qsee_bw_count) {
+		ret = msm_bus_scale_client_update_request(
+				qsee_perf_client, 1);
+		if (ret) {
+			pr_err("Bandwidth request failed (%d)\n", ret);
+		} else {
+			ret = clk_enable(qseecom_bus_clk);
+			if (ret)
+				pr_err("Clock enable failed\n");
+		}
+	}
+	if (ret)
+		msm_bus_scale_client_update_request(qsee_perf_client, 0);
+	else
+		qsee_bw_count++;
+
+	mutex_unlock(&qsee_bw_mutex);
+	return ret;
+}
+
+static void qsee_disable_clock_vote(void)
+{
+
+	if (!qsee_perf_client)
+		return;
+
+	/* Check if the clk is valid */
+	if (IS_ERR_OR_NULL(qseecom_bus_clk)) {
+		pr_warn("qseecom bus clock is null or error");
+		return;
+	}
+
+	mutex_lock(&qsee_bw_mutex);
+	if (qsee_bw_count > 0) {
+		if (qsee_bw_count-- == 1) {
+			msm_bus_scale_client_update_request(qsee_perf_client,
+							0);
+			clk_disable(qseecom_bus_clk);
+		}
+	}
+	mutex_unlock(&qsee_bw_mutex);
+}
+
+
+static long qseecom_ioctl(struct file *file, unsigned cmd,
+		unsigned long arg)
+{
+	int ret = 0;
+	struct qseecom_dev_handle *data = file->private_data;
+	void __user *argp = (void __user *) arg;
+
+	if (data->abort) {
+		pr_err("Aborting qseecom driver\n");
+		return -ENODEV;
+	}
+
+	switch (cmd) {
+	case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
+		pr_debug("ioctl register_listener_req()\n");
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_register_listener(data, argp);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_register_listener: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
+		pr_debug("ioctl unregister_listener_req()\n");
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_unregister_listener(data);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_unregister_listener: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SEND_CMD_REQ: {
+		/* Only one client allowed here at a time */
+		mutex_lock(&send_msg_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_send_cmd(data, argp);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		mutex_unlock(&send_msg_lock);
+		if (ret)
+			pr_err("failed qseecom_send_cmd: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+		/* Only one client allowed here at a time */
+		mutex_lock(&send_msg_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_send_modfd_cmd(data, argp);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		mutex_unlock(&send_msg_lock);
+		if (ret)
+			pr_err("failed qseecom_send_cmd: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_RECEIVE_REQ: {
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_receive_req(data);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_receive_req: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SEND_RESP_REQ: {
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_send_resp();
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_send_resp: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
+		ret = qseecom_set_client_mem_param(data, argp);
+		if (ret)
+			pr_err("failed Qqseecom_set_mem_param request: %d\n",
+								ret);
+		break;
+	}
+	case QSEECOM_IOCTL_LOAD_APP_REQ: {
+		mutex_lock(&app_access_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_load_app(data, argp);
+		atomic_dec(&data->ioctl_count);
+		mutex_unlock(&app_access_lock);
+		if (ret)
+			pr_err("failed load_app request: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
+		mutex_lock(&app_access_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_unload_app(data);
+		atomic_dec(&data->ioctl_count);
+		mutex_unlock(&app_access_lock);
+		if (ret)
+			pr_err("failed unload_app request: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_get_qseos_version(data, argp);
+		if (ret)
+			pr_err("qseecom_get_qseos_version: %d\n", ret);
+		atomic_dec(&data->ioctl_count);
+		break;
+	}
+	case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
+		atomic_inc(&data->ioctl_count);
+		ret = qsee_vote_for_clock();
+		if (ret)
+			pr_err("Failed to vote for clock%d\n", ret);
+		atomic_dec(&data->ioctl_count);
+		break;
+	}
+	case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
+		atomic_inc(&data->ioctl_count);
+		qsee_disable_clock_vote();
+		atomic_dec(&data->ioctl_count);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static int qseecom_open(struct inode *inode, struct file *file)
+{
+	int ret = 0;
+	struct qseecom_dev_handle *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		pr_err("kmalloc failed\n");
+		return -ENOMEM;
+	}
+	file->private_data = data;
+	data->abort = 0;
+	data->service = false;
+	data->released = false;
+	init_waitqueue_head(&data->abort_wq);
+	atomic_set(&data->ioctl_count, 0);
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		int pil_error;
+		mutex_lock(&pil_access_lock);
+		if (pil_ref_cnt == 0) {
+			pil = pil_get("tzapps");
+			if (IS_ERR(pil)) {
+				pr_err("Playready PIL image load failed\n");
+				pil_error = PTR_ERR(pil);
+				pil = NULL;
+				pr_debug("tzapps image load FAILED\n");
+				mutex_unlock(&pil_access_lock);
+				return pil_error;
+			}
+		}
+		pil_ref_cnt++;
+		mutex_unlock(&pil_access_lock);
+	}
+	return ret;
+}
+
+static int qseecom_release(struct inode *inode, struct file *file)
+{
+	struct qseecom_dev_handle *data = file->private_data;
+	int ret = 0;
+
+	if (data->released == false) {
+		pr_warn("data->released == false\n");
+		if (data->service)
+			ret = qseecom_unregister_listener(data);
+		else
+			ret = qseecom_unload_app(data);
+		if (ret) {
+			pr_err("Close failed\n");
+			return ret;
+		}
+	}
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		mutex_lock(&pil_access_lock);
+		if (pil_ref_cnt == 1)
+			pil_put(pil);
+		pil_ref_cnt--;
+		mutex_unlock(&pil_access_lock);
+	}
+	kfree(data);
+	qsee_disable_clock_vote();
+
+	return ret;
+}
+
+/* qseecom bus scaling */
+static struct msm_bus_paths qsee_bw_table[] = {
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+			},
+		},
+		.num_paths = 1,
+	},
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+				.ib = (492 * 8) * 1000000UL,
+				.ab = (492 * 8) *  100000UL,
+			},
+		},
+		.num_paths = 1,
+	},
+};
+
+static struct msm_bus_scale_pdata qsee_bus_pdata = {
+	.usecase = qsee_bw_table,
+	.num_usecases = ARRAY_SIZE(qsee_bw_table),
+	.name = "qsee",
+};
+
+static const struct file_operations qseecom_fops = {
+		.owner = THIS_MODULE,
+		.unlocked_ioctl = qseecom_ioctl,
+		.open = qseecom_open,
+		.release = qseecom_release
+};
+
+static int __init qseecom_init(void)
+{
+	int rc;
+	struct device *class_dev;
+	char qsee_not_legacy = 0;
+	uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
+
+	qsee_bw_count = 0;
+	qseecom_bus_clk = NULL;
+	qsee_perf_client = 0;
+
+	rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
+	if (rc < 0) {
+		pr_err("alloc_chrdev_region failed %d\n", rc);
+		return rc;
+	}
+
+	driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
+	if (IS_ERR(driver_class)) {
+		rc = -ENOMEM;
+		pr_err("class_create failed %d\n", rc);
+		goto unregister_chrdev_region;
+	}
+
+	class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
+			QSEECOM_DEV);
+	if (!class_dev) {
+		pr_err("class_device_create failed %d\n", rc);
+		rc = -ENOMEM;
+		goto class_destroy;
+	}
+
+	cdev_init(&qseecom_cdev, &qseecom_fops);
+	qseecom_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
+	if (rc < 0) {
+		pr_err("cdev_add failed %d\n", rc);
+		goto err;
+	}
+
+	INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
+	spin_lock_init(&qseecom.registered_listener_list_lock);
+	INIT_LIST_HEAD(&qseecom.registered_app_list_head);
+	spin_lock_init(&qseecom.registered_app_list_lock);
+	init_waitqueue_head(&qseecom.send_resp_wq);
+	qseecom.send_resp_flag = 0;
+
+	rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
+				&qsee_not_legacy, sizeof(qsee_not_legacy));
+	if (rc) {
+		pr_err("Failed to retrieve QSEE version information %d\n", rc);
+		goto err;
+	}
+	if (qsee_not_legacy)
+		qseecom.qseos_version = QSEOS_VERSION_14;
+	else {
+		qseecom.qseos_version = QSEOS_VERSION_13;
+		pil = NULL;
+		pil_ref_cnt = 0;
+	}
+	/* Create ION msm client */
+	qseecom.ion_clnt = msm_ion_client_create(0x03, "qseecom-kernel");
+	if (qseecom.ion_clnt == NULL) {
+		pr_err("Ion client cannot be created\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	/* register client for bus scaling */
+	qsee_perf_client = msm_bus_scale_register_client(
+					&qsee_bus_pdata);
+	if (!qsee_perf_client) {
+		pr_err("Unable to register bus client\n");
+	} else {
+		qseecom_bus_clk = clk_get(class_dev, "bus_clk");
+		if (IS_ERR(qseecom_bus_clk)) {
+			qseecom_bus_clk = NULL;
+		} else if (qseecom_bus_clk != NULL) {
+			pr_debug("Enabled DFAB clock");
+			clk_set_rate(qseecom_bus_clk, 64000000);
+		}
+	}
+	return 0;
+
+err:
+	device_destroy(driver_class, qseecom_device_no);
+class_destroy:
+	class_destroy(driver_class);
+unregister_chrdev_region:
+	unregister_chrdev_region(qseecom_device_no, 1);
+	return rc;
+}
+
+static void __exit qseecom_exit(void)
+{
+	clk_put(qseecom_bus_clk);
+
+	device_destroy(driver_class, qseecom_device_no);
+	class_destroy(driver_class);
+	unregister_chrdev_region(qseecom_device_no, 1);
+	ion_client_destroy(qseecom.ion_clnt);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
+
+module_init(qseecom_init);
+module_exit(qseecom_exit);
diff --git a/drivers/misc/qseecom_legacy.h b/drivers/misc/qseecom_legacy.h
new file mode 100644
index 0000000..66f87e9
--- /dev/null
+++ b/drivers/misc/qseecom_legacy.h
@@ -0,0 +1,79 @@
+/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+ *
+ * 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 __QSEECOM_LEGACY_H_
+#define __QSEECOM_LEGACY_H_
+
+#include <linux/types.h>
+
+#define TZ_SCHED_CMD_ID_REGISTER_LISTENER    0x04
+
+enum tz_sched_cmd_type {
+	TZ_SCHED_CMD_INVALID = 0,
+	TZ_SCHED_CMD_NEW,      /* New TZ Scheduler Command */
+	TZ_SCHED_CMD_PENDING,  /* Pending cmd...sched will restore stack */
+	TZ_SCHED_CMD_COMPLETE, /* TZ sched command is complete */
+	TZ_SCHED_CMD_MAX     = 0x7FFFFFFF
+};
+
+enum tz_sched_cmd_status {
+	TZ_SCHED_STATUS_INCOMPLETE = 0,
+	TZ_SCHED_STATUS_COMPLETE,
+	TZ_SCHED_STATUS_MAX  = 0x7FFFFFFF
+};
+/* Command structure for initializing shared buffers */
+__packed struct qse_pr_init_sb_req_s {
+	/* First 4 bytes should always be command id */
+	uint32_t                  pr_cmd;
+	/* Pointer to the physical location of sb buffer */
+	uint32_t                  sb_ptr;
+	/* length of shared buffer */
+	uint32_t                  sb_len;
+	uint32_t                  listener_id;
+};
+
+__packed struct qse_pr_init_sb_rsp_s {
+	/* First 4 bytes should always be command id */
+	uint32_t                  pr_cmd;
+	/* Return code, 0 for success, Approp error code otherwise */
+	int32_t                   ret;
+};
+
+/*
+ * struct QSEECom_command - QSECom command buffer
+ * @cmd_type: value from enum tz_sched_cmd_type
+ * @sb_in_cmd_addr: points to physical location of command
+ *                buffer
+ * @sb_in_cmd_len: length of command buffer
+ */
+__packed struct qseecom_command {
+	uint32_t               cmd_type;
+	uint8_t                *sb_in_cmd_addr;
+	uint32_t               sb_in_cmd_len;
+};
+
+/*
+ * struct QSEECom_response - QSECom response buffer
+ * @cmd_status: value from enum tz_sched_cmd_status
+ * @sb_in_rsp_addr: points to physical location of response
+ *                buffer
+ * @sb_in_rsp_len: length of command response
+ */
+__packed struct qseecom_response {
+	uint32_t                 cmd_status;
+	uint8_t                  *sb_in_rsp_addr;
+	uint32_t                 sb_in_rsp_len;
+};
+
+#endif /* __QSEECOM_LEGACY_H_ */
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c
index cfbddbe..43d073b 100644
--- a/drivers/misc/spear13xx_pcie_gadget.c
+++ b/drivers/misc/spear13xx_pcie_gadget.c
@@ -903,6 +903,6 @@
 }
 module_exit(spear_pcie_gadget_exit);
 
-MODULE_ALIAS("pcie-gadget-spear");
+MODULE_ALIAS("platform:pcie-gadget-spear");
 MODULE_AUTHOR("Pratyush Anand");
 MODULE_LICENSE("GPL");
diff --git a/drivers/misc/tzcom.c b/drivers/misc/tzcom.c
index 2b1484c..3b943c8 100644
--- a/drivers/misc/tzcom.c
+++ b/drivers/misc/tzcom.c
@@ -29,9 +29,13 @@
 #include <linux/android_pmem.h>
 #include <linux/io.h>
 #include <linux/ion.h>
+#include <linux/tzcom.h>
+#include <linux/clk.h>
 #include <mach/scm.h>
 #include <mach/peripheral-loader.h>
-#include <linux/tzcom.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
 #include "tzcomi.h"
 
 #define TZCOM_DEV "tzcom"
@@ -51,6 +55,7 @@
 		__func__, current->pid, current->comm, ## args)
 
 
+static uint32_t tzcom_perf_client;
 static struct class *driver_class;
 static dev_t tzcom_device_no;
 static struct cdev tzcom_cdev;
@@ -68,7 +73,9 @@
 static DEFINE_MUTEX(sb_in_lock);
 static DEFINE_MUTEX(sb_out_lock);
 static DEFINE_MUTEX(send_cmd_lock);
-
+static DEFINE_MUTEX(tzcom_bw_mutex);
+static int tzcom_bw_count;
+static struct clk *tzcom_bus_clk;
 struct tzcom_callback_list {
 	struct list_head      list;
 	struct tzcom_callback callback;
@@ -94,6 +101,53 @@
 	atomic_t          ioctl_count;
 };
 
+static int tzcom_enable_bus_scaling(void)
+{
+	int ret = 0;
+	if (!tzcom_perf_client)
+		return -EINVAL;
+
+	if (IS_ERR_OR_NULL(tzcom_bus_clk))
+		return -EINVAL;
+
+	mutex_lock(&tzcom_bw_mutex);
+	if (!tzcom_bw_count) {
+		ret = msm_bus_scale_client_update_request(
+				tzcom_perf_client, 1);
+		if (ret) {
+			pr_err("Bandwidth request failed (%d)\n", ret);
+		} else {
+			ret = clk_enable(tzcom_bus_clk);
+			if (ret)
+				pr_err("Clock enable failed\n");
+		}
+	}
+	if (ret)
+		msm_bus_scale_client_update_request(tzcom_perf_client, 0);
+	else
+		tzcom_bw_count++;
+	mutex_unlock(&tzcom_bw_mutex);
+	return ret;
+}
+
+static void tzcom_disable_bus_scaling(void)
+{
+	if (!tzcom_perf_client)
+		return ;
+
+	if (IS_ERR_OR_NULL(tzcom_bus_clk))
+		return ;
+
+	mutex_lock(&tzcom_bw_mutex);
+	if (tzcom_bw_count > 0)
+		if (tzcom_bw_count-- == 1) {
+			msm_bus_scale_client_update_request(tzcom_perf_client,
+								0);
+			clk_disable(tzcom_bus_clk);
+		}
+	mutex_unlock(&tzcom_bw_mutex);
+}
+
 static int tzcom_scm_call(const void *cmd_buf, size_t cmd_len,
 		void *resp_buf, size_t resp_len)
 {
@@ -878,6 +932,9 @@
 	struct tzcom_data_t *tzcom_data;
 
 	PDEBUG("In here");
+
+	ret = tzcom_enable_bus_scaling();
+
 	if (pil == NULL) {
 		pil = pil_get("tzapps");
 		if (IS_ERR(pil)) {
@@ -1008,9 +1065,39 @@
 	}
 	PDEBUG("Freeing tzcom data");
 	kfree(tzcom_data);
+	tzcom_disable_bus_scaling();
 	return 0;
 }
 
+static struct msm_bus_paths tzcom_bw_table[] = {
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+			},
+		},
+		.num_paths = 1,
+	},
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+				.ib = (492 * 8) * 1000000UL,
+				.ab = (492 * 8) *  100000UL,
+			},
+		},
+		.num_paths = 1,
+	},
+
+};
+
+static struct msm_bus_scale_pdata tzcom_bus_pdata = {
+	.usecase = tzcom_bw_table,
+	.num_usecases = ARRAY_SIZE(tzcom_bw_table),
+	.name = "tzcom",
+};
 static const struct file_operations tzcom_fops = {
 		.owner = THIS_MODULE,
 		.unlocked_ioctl = tzcom_ioctl,
@@ -1098,6 +1185,18 @@
 	/* Initialized in tzcom_open */
 	pil = NULL;
 
+	tzcom_perf_client = msm_bus_scale_register_client(
+					&tzcom_bus_pdata);
+	if (!tzcom_perf_client)
+		pr_err("Unable to register bus client");
+
+	tzcom_bus_clk = clk_get(class_dev, "bus_clk");
+	if (IS_ERR(tzcom_bus_clk)) {
+		tzcom_bus_clk = NULL;
+	} else  if (tzcom_bus_clk != NULL) {
+		pr_debug("Enabled DFAB clock\n");
+		clk_set_rate(tzcom_bus_clk, 64000000);
+	}
 	return 0;
 
 class_device_destroy:
@@ -1132,6 +1231,7 @@
 		pil_put(pil);
 		pil = NULL;
 	}
+	clk_put(tzcom_bus_clk);
 	device_destroy(driver_class, tzcom_device_no);
 	class_destroy(driver_class);
 	unregister_chrdev_region(tzcom_device_no, 1);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 48f3f2d..5dbf839 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -94,6 +94,11 @@
 	unsigned int	read_only;
 	unsigned int	part_type;
 	unsigned int	name_idx;
+	unsigned int	reset_done;
+#define MMC_BLK_READ		BIT(0)
+#define MMC_BLK_WRITE		BIT(1)
+#define MMC_BLK_DISCARD		BIT(2)
+#define MMC_BLK_SECDISCARD	BIT(3)
 
 	/*
 	 * Only set in main mmc_blk_data associated
@@ -106,6 +111,16 @@
 
 static DEFINE_MUTEX(open_lock);
 
+enum mmc_blk_status {
+	MMC_BLK_SUCCESS = 0,
+	MMC_BLK_PARTIAL,
+	MMC_BLK_CMD_ERR,
+	MMC_BLK_RETRY,
+	MMC_BLK_ABORT,
+	MMC_BLK_DATA_ERR,
+	MMC_BLK_ECC_ERR,
+};
+
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
@@ -277,7 +292,7 @@
 	struct mmc_card *card;
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct scatterlist sg;
 	int err;
 
@@ -423,32 +438,29 @@
 #endif
 };
 
-struct mmc_blk_request {
-	struct mmc_request	mrq;
-	struct mmc_command	sbc;
-	struct mmc_command	cmd;
-	struct mmc_command	stop;
-	struct mmc_data		data;
-};
-
 static inline int mmc_blk_part_switch(struct mmc_card *card,
 				      struct mmc_blk_data *md)
 {
 	int ret;
 	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+
 	if (main_md->part_curr == md->part_type)
 		return 0;
 
 	if (mmc_card_mmc(card)) {
-		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
-		card->ext_csd.part_config |= md->part_type;
+		u8 part_config = card->ext_csd.part_config;
+
+		part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		part_config |= md->part_type;
 
 		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+				 EXT_CSD_PART_CONFIG, part_config,
 				 card->ext_csd.part_time);
 		if (ret)
 			return ret;
-}
+
+		card->ext_csd.part_config = part_config;
+	}
 
 	main_md->part_curr = md->part_type;
 	return 0;
@@ -460,7 +472,7 @@
 	u32 result;
 	__be32 *blocks;
 
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	unsigned int timeout_us;
@@ -615,7 +627,7 @@
  * Otherwise we don't understand what happened, so abort.
  */
 static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
-	struct mmc_blk_request *brq)
+	struct mmc_blk_request *brq, int *ecc_err)
 {
 	bool prev_cmd_status_valid = true;
 	u32 status, stop_status = 0;
@@ -647,6 +659,12 @@
 		return ERR_ABORT;
 	}
 
+	/* Flag ECC errors */
+	if ((status & R1_CARD_ECC_FAILED) ||
+	    (brq->stop.resp[0] & R1_CARD_ECC_FAILED) ||
+	    (brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
+		*ecc_err = 1;
+
 	/*
 	 * Check the current card state.  If it is in some data transfer
 	 * mode, tell it to stop (and hopefully transition back to TRAN.)
@@ -664,6 +682,8 @@
 		 */
 		if (err)
 			return ERR_ABORT;
+		if (stop_status & R1_CARD_ECC_FAILED)
+			*ecc_err = 1;
 	}
 
 	/* Check for set block count errors */
@@ -676,6 +696,10 @@
 		return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
 				prev_cmd_status_valid, status);
 
+	/* Data errors */
+	if (!brq->stop.error)
+		return ERR_CONTINUE;
+
 	/* Now for stop errors.  These aren't fatal to the transfer. */
 	pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
 	       req->rq_disk->disk_name, brq->stop.error,
@@ -692,12 +716,45 @@
 	return ERR_CONTINUE;
 }
 
+static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
+			 int type)
+{
+	int err;
+
+	if (md->reset_done & type)
+		return -EEXIST;
+
+	md->reset_done |= type;
+	err = mmc_hw_reset(host);
+	/* Ensure we switch back to the correct partition */
+	if (err != -EOPNOTSUPP) {
+		struct mmc_blk_data *main_md = mmc_get_drvdata(host->card);
+		int part_err;
+
+		main_md->part_curr = main_md->part_type;
+		part_err = mmc_blk_part_switch(host->card, md);
+		if (part_err) {
+			/*
+			 * We have failed to get back into the correct
+			 * partition, so we need to abort the whole request.
+			 */
+			return -ENODEV;
+		}
+	}
+	return err;
+}
+
+static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
+{
+	md->reset_done &= ~type;
+}
+
 static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	unsigned int from, nr, arg;
-	int err = 0;
+	int err = 0, type = MMC_BLK_DISCARD;
 
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
@@ -707,11 +764,13 @@
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
-	if (mmc_can_trim(card))
+	if (mmc_can_discard(card))
+		arg = MMC_DISCARD_ARG;
+	else if (mmc_can_trim(card))
 		arg = MMC_TRIM_ARG;
 	else
 		arg = MMC_ERASE_ARG;
-
+retry:
 	if (card->quirks & MMC_QUIRK_INAND_CMD38) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 INAND_CMD38_ARG_EXT_CSD,
@@ -724,6 +783,10 @@
 	}
 	err = mmc_erase(card, from, nr, arg);
 out:
+	if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+		goto retry;
+	if (!err)
+		mmc_blk_reset_success(md, type);
 	spin_lock_irq(&md->lock);
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
@@ -737,13 +800,20 @@
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	unsigned int from, nr, arg;
-	int err = 0;
+	int err = 0, type = MMC_BLK_SECDISCARD;
 
-	if (!mmc_can_secure_erase_trim(card)) {
+	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
 		err = -EOPNOTSUPP;
 		goto out;
 	}
 
+	/* The sanitize operation is supported at v4.5 only */
+	if (mmc_can_sanitize(card)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_SANITIZE_START, 1, 0);
+		goto out;
+	}
+
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
@@ -751,7 +821,7 @@
 		arg = MMC_SECURE_TRIM1_ARG;
 	else
 		arg = MMC_SECURE_ERASE_ARG;
-
+retry:
 	if (card->quirks & MMC_QUIRK_INAND_CMD38) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 INAND_CMD38_ARG_EXT_CSD,
@@ -775,6 +845,10 @@
 		err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
 	}
 out:
+	if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+		goto retry;
+	if (!err)
+		mmc_blk_reset_success(md, type);
 	spin_lock_irq(&md->lock);
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
@@ -785,16 +859,18 @@
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	int ret = 0;
 
-	/*
-	 * No-op, only service this because we need REQ_FUA for reliable
-	 * writes.
-	 */
+	ret = mmc_flush_cache(card);
+	if (ret)
+		ret = -EIO;
+
 	spin_lock_irq(&md->lock);
-	__blk_end_request_all(req, 0);
+	__blk_end_request_all(req, ret);
 	spin_unlock_irq(&md->lock);
 
-	return 1;
+	return ret ? 0 : 1;
 }
 
 /*
@@ -828,12 +904,106 @@
 	 R1_CC_ERROR |		/* Card controller error */		\
 	 R1_ERROR)		/* General/unknown error */
 
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+static int mmc_blk_err_check(struct mmc_card *card,
+			     struct mmc_async_req *areq)
 {
+	struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
+						    mmc_active);
+	struct mmc_blk_request *brq = &mq_mrq->brq;
+	struct request *req = mq_mrq->req;
+	int ecc_err = 0;
+
+	/*
+	 * sbc.error indicates a problem with the set block count
+	 * command.  No data will have been transferred.
+	 *
+	 * cmd.error indicates a problem with the r/w command.  No
+	 * data will have been transferred.
+	 *
+	 * stop.error indicates a problem with the stop command.  Data
+	 * may have been transferred, or may still be transferring.
+	 */
+	if (brq->sbc.error || brq->cmd.error || brq->stop.error ||
+	    brq->data.error) {
+		switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) {
+		case ERR_RETRY:
+			return MMC_BLK_RETRY;
+		case ERR_ABORT:
+		case ERR_NOMEDIUM:
+			return MMC_BLK_ABORT;
+		case ERR_CONTINUE:
+			break;
+		}
+	}
+
+	/*
+	 * Check for errors relating to the execution of the
+	 * initial command - such as address errors.  No data
+	 * has been transferred.
+	 */
+	if (brq->cmd.resp[0] & CMD_ERRORS) {
+		pr_err("%s: r/w command failed, status = %#x\n",
+		       req->rq_disk->disk_name, brq->cmd.resp[0]);
+		return MMC_BLK_ABORT;
+	}
+
+	/*
+	 * Everything else is either success, or a data error of some
+	 * kind.  If it was a write, we may have transitioned to
+	 * program mode, which we have to wait for it to complete.
+	 */
+	if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+		u32 status;
+		do {
+			int err = get_card_status(card, &status, 5);
+			if (err) {
+				printk(KERN_ERR "%s: error %d requesting status\n",
+				       req->rq_disk->disk_name, err);
+				return MMC_BLK_CMD_ERR;
+			}
+			/*
+			 * Some cards mishandle the status bits,
+			 * so make sure to check both the busy
+			 * indication and the card state.
+			 */
+		} while (!(status & R1_READY_FOR_DATA) ||
+			 (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+	}
+
+	if (brq->data.error) {
+		pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
+		       req->rq_disk->disk_name, brq->data.error,
+		       (unsigned)blk_rq_pos(req),
+		       (unsigned)blk_rq_sectors(req),
+		       brq->cmd.resp[0], brq->stop.resp[0]);
+
+		if (rq_data_dir(req) == READ) {
+			if (ecc_err)
+				return MMC_BLK_ECC_ERR;
+			return MMC_BLK_DATA_ERR;
+		} else {
+			return MMC_BLK_CMD_ERR;
+		}
+	}
+
+	if (!brq->data.bytes_xfered)
+		return MMC_BLK_RETRY;
+
+	if (blk_rq_bytes(req) != brq->data.bytes_xfered)
+		return MMC_BLK_PARTIAL;
+
+	return MMC_BLK_SUCCESS;
+}
+
+static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+			       struct mmc_card *card,
+			       int disable_multi,
+			       struct mmc_queue *mq)
+{
+	u32 readcmd, writecmd;
+	struct mmc_blk_request *brq = &mqrq->brq;
+	struct request *req = mqrq->req;
 	struct mmc_blk_data *md = mq->data;
-	struct mmc_card *card = md->queue.card;
-	struct mmc_blk_request brq;
-	int ret = 1, disable_multi = 0, retry = 0;
 
 	/*
 	 * Reliable writes are used to implement Forced Unit Access and
@@ -844,225 +1014,135 @@
 		(rq_data_dir(req) == WRITE) &&
 		(md->flags & MMC_BLK_REL_WR);
 
-	do {
-		u32 readcmd, writecmd;
+	memset(brq, 0, sizeof(struct mmc_blk_request));
+	brq->mrq.cmd = &brq->cmd;
+	brq->mrq.data = &brq->data;
 
-		memset(&brq, 0, sizeof(struct mmc_blk_request));
-		brq.mrq.cmd = &brq.cmd;
-		brq.mrq.data = &brq.data;
+	brq->cmd.arg = blk_rq_pos(req);
+	if (!mmc_card_blockaddr(card))
+		brq->cmd.arg <<= 9;
+	brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+	brq->data.blksz = 512;
+	brq->stop.opcode = MMC_STOP_TRANSMISSION;
+	brq->stop.arg = 0;
+	brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+	brq->data.blocks = blk_rq_sectors(req);
 
-		brq.cmd.arg = blk_rq_pos(req);
-		if (!mmc_card_blockaddr(card))
-			brq.cmd.arg <<= 9;
-		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-		brq.data.blksz = 512;
-		brq.stop.opcode = MMC_STOP_TRANSMISSION;
-		brq.stop.arg = 0;
-		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-		brq.data.blocks = blk_rq_sectors(req);
+	/*
+	 * The block layer doesn't support all sector count
+	 * restrictions, so we need to be prepared for too big
+	 * requests.
+	 */
+	if (brq->data.blocks > card->host->max_blk_count)
+		brq->data.blocks = card->host->max_blk_count;
 
+	if (brq->data.blocks > 1) {
 		/*
-		 * The block layer doesn't support all sector count
-		 * restrictions, so we need to be prepared for too big
-		 * requests.
+		 * After a read error, we redo the request one sector
+		 * at a time in order to accurately determine which
+		 * sectors can be read successfully.
 		 */
-		if (brq.data.blocks > card->host->max_blk_count)
-			brq.data.blocks = card->host->max_blk_count;
+		if (disable_multi)
+			brq->data.blocks = 1;
 
-		/*
-		 * After a read error, we redo the request one sector at a time
-		 * in order to accurately determine which sectors can be read
-		 * successfully.
+		/* Some controllers can't do multiblock reads due to hw bugs */
+		if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
+		    rq_data_dir(req) == READ)
+			brq->data.blocks = 1;
+	}
+
+	if (brq->data.blocks > 1 || do_rel_wr) {
+		/* SPI multiblock writes terminate using a special
+		 * token, not a STOP_TRANSMISSION request.
 		 */
-		if (disable_multi && brq.data.blocks > 1)
-			brq.data.blocks = 1;
+		if (!mmc_host_is_spi(card->host) ||
+		    rq_data_dir(req) == READ)
+			brq->mrq.stop = &brq->stop;
+		readcmd = MMC_READ_MULTIPLE_BLOCK;
+		writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+	} else {
+		brq->mrq.stop = NULL;
+		readcmd = MMC_READ_SINGLE_BLOCK;
+		writecmd = MMC_WRITE_BLOCK;
+	}
+	if (rq_data_dir(req) == READ) {
+		brq->cmd.opcode = readcmd;
+		brq->data.flags |= MMC_DATA_READ;
+	} else {
+		brq->cmd.opcode = writecmd;
+		brq->data.flags |= MMC_DATA_WRITE;
+	}
 
-		if (brq.data.blocks > 1 || do_rel_wr) {
-			/* SPI multiblock writes terminate using a special
-			 * token, not a STOP_TRANSMISSION request.
-			 */
-			if (!mmc_host_is_spi(card->host) ||
-			    rq_data_dir(req) == READ)
-				brq.mrq.stop = &brq.stop;
-			readcmd = MMC_READ_MULTIPLE_BLOCK;
-			writecmd = MMC_WRITE_MULTIPLE_BLOCK;
-		} else {
-			brq.mrq.stop = NULL;
-			readcmd = MMC_READ_SINGLE_BLOCK;
-			writecmd = MMC_WRITE_BLOCK;
-		}
-		if (rq_data_dir(req) == READ) {
-			brq.cmd.opcode = readcmd;
-			brq.data.flags |= MMC_DATA_READ;
-		} else {
-			brq.cmd.opcode = writecmd;
-			brq.data.flags |= MMC_DATA_WRITE;
-		}
+	if (do_rel_wr)
+		mmc_apply_rel_rw(brq, card, req);
 
-		if (do_rel_wr)
-			mmc_apply_rel_rw(&brq, card, req);
+	/*
+	 * Pre-defined multi-block transfers are preferable to
+	 * open ended-ones (and necessary for reliable writes).
+	 * However, it is not sufficient to just send CMD23,
+	 * and avoid the final CMD12, as on an error condition
+	 * CMD12 (stop) needs to be sent anyway. This, coupled
+	 * with Auto-CMD23 enhancements provided by some
+	 * hosts, means that the complexity of dealing
+	 * with this is best left to the host. If CMD23 is
+	 * supported by card and host, we'll fill sbc in and let
+	 * the host deal with handling it correctly. This means
+	 * that for hosts that don't expose MMC_CAP_CMD23, no
+	 * change of behavior will be observed.
+	 *
+	 * N.B: Some MMC cards experience perf degradation.
+	 * We'll avoid using CMD23-bounded multiblock writes for
+	 * these, while retaining features like reliable writes.
+	 */
 
-		/*
-		 * Pre-defined multi-block transfers are preferable to
-		 * open ended-ones (and necessary for reliable writes).
-		 * However, it is not sufficient to just send CMD23,
-		 * and avoid the final CMD12, as on an error condition
-		 * CMD12 (stop) needs to be sent anyway. This, coupled
-		 * with Auto-CMD23 enhancements provided by some
-		 * hosts, means that the complexity of dealing
-		 * with this is best left to the host. If CMD23 is
-		 * supported by card and host, we'll fill sbc in and let
-		 * the host deal with handling it correctly. This means
-		 * that for hosts that don't expose MMC_CAP_CMD23, no
-		 * change of behavior will be observed.
-		 *
-		 * N.B: Some MMC cards experience perf degradation.
-		 * We'll avoid using CMD23-bounded multiblock writes for
-		 * these, while retaining features like reliable writes.
-		 */
+	if ((md->flags & MMC_BLK_CMD23) &&
+	    mmc_op_multi(brq->cmd.opcode) &&
+	    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+		brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+		brq->sbc.arg = brq->data.blocks |
+			(do_rel_wr ? (1 << 31) : 0);
+		brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+		brq->mrq.sbc = &brq->sbc;
+	}
 
-		if ((md->flags & MMC_BLK_CMD23) &&
-		    mmc_op_multi(brq.cmd.opcode) &&
-		    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
-			brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
-			brq.sbc.arg = brq.data.blocks |
-				(do_rel_wr ? (1 << 31) : 0);
-			brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
-			brq.mrq.sbc = &brq.sbc;
-		}
+	mmc_set_data_timeout(&brq->data, card);
 
-		mmc_set_data_timeout(&brq.data, card);
+	brq->data.sg = mqrq->sg;
+	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
 
-		brq.data.sg = mq->sg;
-		brq.data.sg_len = mmc_queue_map_sg(mq);
+	/*
+	 * Adjust the sg list so it is the same size as the
+	 * request.
+	 */
+	if (brq->data.blocks != blk_rq_sectors(req)) {
+		int i, data_size = brq->data.blocks << 9;
+		struct scatterlist *sg;
 
-		/*
-		 * Adjust the sg list so it is the same size as the
-		 * request.
-		 */
-		if (brq.data.blocks != blk_rq_sectors(req)) {
-			int i, data_size = brq.data.blocks << 9;
-			struct scatterlist *sg;
-
-			for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
-				data_size -= sg->length;
-				if (data_size <= 0) {
-					sg->length += data_size;
-					i++;
-					break;
-				}
-			}
-			brq.data.sg_len = i;
-		}
-
-		mmc_queue_bounce_pre(mq);
-
-		mmc_wait_for_req(card->host, &brq.mrq);
-
-		mmc_queue_bounce_post(mq);
-
-		/*
-		 * sbc.error indicates a problem with the set block count
-		 * command.  No data will have been transferred.
-		 *
-		 * cmd.error indicates a problem with the r/w command.  No
-		 * data will have been transferred.
-		 *
-		 * stop.error indicates a problem with the stop command.  Data
-		 * may have been transferred, or may still be transferring.
-		 */
-		if (brq.sbc.error || brq.cmd.error || brq.stop.error) {
-			switch (mmc_blk_cmd_recovery(card, req, &brq)) {
-			case ERR_RETRY:
-				if (retry++ < 5)
-					continue;
-			case ERR_ABORT:
-			case ERR_NOMEDIUM:
-				goto cmd_abort;
-			case ERR_CONTINUE:
+		for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
+			data_size -= sg->length;
+			if (data_size <= 0) {
+				sg->length += data_size;
+				i++;
 				break;
 			}
 		}
+		brq->data.sg_len = i;
+	}
 
-		/*
-		 * Check for errors relating to the execution of the
-		 * initial command - such as address errors.  No data
-		 * has been transferred.
-		 */
-		if (brq.cmd.resp[0] & CMD_ERRORS) {
-			pr_err("%s: r/w command failed, status = %#x\n",
-				req->rq_disk->disk_name, brq.cmd.resp[0]);
-			goto cmd_abort;
-		}
+	mqrq->mmc_active.mrq = &brq->mrq;
+	mqrq->mmc_active.err_check = mmc_blk_err_check;
 
-		/*
-		 * Everything else is either success, or a data error of some
-		 * kind.  If it was a write, we may have transitioned to
-		 * program mode, which we have to wait for it to complete.
-		 */
-		if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
-			u32 status;
-			do {
-				int err = get_card_status(card, &status, 5);
-				if (err) {
-					printk(KERN_ERR "%s: error %d requesting status\n",
-					       req->rq_disk->disk_name, err);
-					goto cmd_err;
-				}
-				/*
-				 * Some cards mishandle the status bits,
-				 * so make sure to check both the busy
-				 * indication and the card state.
-				 */
-			} while (!(status & R1_READY_FOR_DATA) ||
-				 (R1_CURRENT_STATE(status) == R1_STATE_PRG));
-		}
+	mmc_queue_bounce_pre(mqrq);
+}
 
-		if (brq.data.error) {
-			pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
-				req->rq_disk->disk_name, brq.data.error,
-				(unsigned)blk_rq_pos(req),
-				(unsigned)blk_rq_sectors(req),
-				brq.cmd.resp[0], brq.stop.resp[0]);
-
-			if (rq_data_dir(req) == READ) {
-				if (brq.data.blocks > 1) {
-					/* Redo read one sector at a time */
-					pr_warning("%s: retrying using single block read\n",
-						req->rq_disk->disk_name);
-					disable_multi = 1;
-					continue;
-				}
-
-				/*
-				 * After an error, we redo I/O one sector at a
-				 * time, so we only reach here after trying to
-				 * read a single sector.
-				 */
-				spin_lock_irq(&md->lock);
-				ret = __blk_end_request(req, -EIO, brq.data.blksz);
-				spin_unlock_irq(&md->lock);
-				continue;
-			} else {
-				goto cmd_err;
-			}
-		}
-
-		/*
-		 * A block was successfully transferred.
-		 */
-		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
-		spin_unlock_irq(&md->lock);
-	} while (ret);
-
-	return 1;
-
- cmd_err:
- 	/*
- 	 * If this is an SD card and we're writing, we can first
- 	 * mark the known good sectors as ok.
- 	 *
+static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
+			   struct mmc_blk_request *brq, struct request *req,
+			   int ret)
+{
+	/*
+	 * If this is an SD card and we're writing, we can first
+	 * mark the known good sectors as ok.
+	 *
 	 * If the card is not SD, we can still ok written sectors
 	 * as reported by the controller (which might be less than
 	 * the real number of written sectors, but never more).
@@ -1078,9 +1158,122 @@
 		}
 	} else {
 		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
+		ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
 		spin_unlock_irq(&md->lock);
 	}
+	return ret;
+}
+
+static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+{
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
+	int ret = 1, disable_multi = 0, retry = 0, type;
+	enum mmc_blk_status status;
+	struct mmc_queue_req *mq_rq;
+	struct request *req;
+	struct mmc_async_req *areq;
+
+	if (!rqc && !mq->mqrq_prev->req)
+		return 0;
+
+	do {
+		if (rqc) {
+			mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+			areq = &mq->mqrq_cur->mmc_active;
+		} else
+			areq = NULL;
+		areq = mmc_start_req(card->host, areq, (int *) &status);
+		if (!areq)
+			return 0;
+
+		mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
+		brq = &mq_rq->brq;
+		req = mq_rq->req;
+		type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+		mmc_queue_bounce_post(mq_rq);
+
+		switch (status) {
+		case MMC_BLK_SUCCESS:
+		case MMC_BLK_PARTIAL:
+			/*
+			 * A block was successfully transferred.
+			 */
+			mmc_blk_reset_success(md, type);
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(req, 0,
+						brq->data.bytes_xfered);
+			spin_unlock_irq(&md->lock);
+			/*
+			 * If the blk_end_request function returns non-zero even
+			 * though all data has been transferred and no errors
+			 * were returned by the host controller, it's a bug.
+			 */
+			if (status == MMC_BLK_SUCCESS && ret) {
+				printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n",
+				       __func__, blk_rq_bytes(req),
+				       brq->data.bytes_xfered);
+				rqc = NULL;
+				goto cmd_abort;
+			}
+			break;
+		case MMC_BLK_CMD_ERR:
+			ret = mmc_blk_cmd_err(md, card, brq, req, ret);
+			if (!mmc_blk_reset(md, card->host, type))
+				break;
+			goto cmd_abort;
+		case MMC_BLK_RETRY:
+			if (retry++ < 5)
+				break;
+			/* Fall through */
+		case MMC_BLK_ABORT:
+			if (!mmc_blk_reset(md, card->host, type))
+				break;
+			goto cmd_abort;
+		case MMC_BLK_DATA_ERR: {
+			int err;
+
+			err = mmc_blk_reset(md, card->host, type);
+			if (!err)
+				break;
+			if (err == -ENODEV)
+				goto cmd_abort;
+			/* Fall through */
+		}
+		case MMC_BLK_ECC_ERR:
+			if (brq->data.blocks > 1) {
+				/* Redo read one sector at a time */
+				pr_warning("%s: retrying using single block read\n",
+					   req->rq_disk->disk_name);
+				disable_multi = 1;
+				break;
+			}
+			/*
+			 * After an error, we redo I/O one sector at a
+			 * time, so we only reach here after trying to
+			 * read a single sector.
+			 */
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(req, -EIO,
+						brq->data.blksz);
+			spin_unlock_irq(&md->lock);
+			if (!ret)
+				goto start_new_req;
+			break;
+		}
+
+		if (ret) {
+			/*
+			 * In case of a incomplete request
+			 * prepare it again and resend.
+			 */
+			mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
+			mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
+		}
+	} while (ret);
+
+	return 1;
 
  cmd_abort:
 	spin_lock_irq(&md->lock);
@@ -1090,6 +1283,12 @@
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
 	spin_unlock_irq(&md->lock);
 
+ start_new_req:
+	if (rqc) {
+		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+		mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
+	}
+
 	return 0;
 }
 
@@ -1109,26 +1308,42 @@
 	}
 #endif
 
-	mmc_claim_host(card->host);
+	if (req && !mq->mqrq_prev->req)
+		/* claim host only for the first request */
+		mmc_claim_host(card->host);
+
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
+		if (req) {
+			spin_lock_irq(&md->lock);
+			__blk_end_request_all(req, -EIO);
+			spin_unlock_irq(&md->lock);
+		}
 		ret = 0;
 		goto out;
 	}
 
-	if (req->cmd_flags & REQ_DISCARD) {
+	if (req && req->cmd_flags & REQ_DISCARD) {
+		/* complete ongoing async transfer before issuing discard */
+		if (card->host->areq)
+			mmc_blk_issue_rw_rq(mq, NULL);
 		if (req->cmd_flags & REQ_SECURE)
 			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
 			ret = mmc_blk_issue_discard_rq(mq, req);
-	} else if (req->cmd_flags & REQ_FLUSH) {
+	} else if (req && req->cmd_flags & REQ_FLUSH) {
+		/* complete ongoing async transfer before issuing flush */
+		if (card->host->areq)
+			mmc_blk_issue_rw_rq(mq, NULL);
 		ret = mmc_blk_issue_flush(mq, req);
 	} else {
 		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
 
 out:
-	mmc_release_host(card->host);
+	if (!req)
+		/* release host only when there are no more requests */
+		mmc_release_host(card->host);
 	return ret;
 }
 
@@ -1302,7 +1517,7 @@
 	if (!mmc_card_mmc(card))
 		return 0;
 
-	if (card->ext_csd.boot_size) {
+	if (card->ext_csd.boot_size && mmc_boot_partition_access(card->host)) {
 		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
 					 card->ext_csd.boot_size >> 9,
 					 true,
@@ -1325,6 +1540,9 @@
 {
 	int err;
 
+	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+		return 0;
+
 	mmc_claim_host(card->host);
 	err = mmc_set_blocklen(card, 512);
 	mmc_release_host(card->host);
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 233cdfa..9063e98 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -22,6 +22,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/seq_file.h>
+#include <linux/module.h>
 
 #define RESULT_OK		0
 #define RESULT_FAIL		1
@@ -148,6 +149,27 @@
 	struct mmc_test_general_result	*gr;
 };
 
+enum mmc_test_prep_media {
+	MMC_TEST_PREP_NONE = 0,
+	MMC_TEST_PREP_WRITE_FULL = 1 << 0,
+	MMC_TEST_PREP_ERASE = 1 << 1,
+};
+
+struct mmc_test_multiple_rw {
+	unsigned int *sg_len;
+	unsigned int *bs;
+	unsigned int len;
+	unsigned int size;
+	bool do_write;
+	bool do_nonblock_req;
+	enum mmc_test_prep_media prepare;
+};
+
+struct mmc_test_async_req {
+	struct mmc_async_req areq;
+	struct mmc_test_card *test;
+};
+
 /*******************************************************************/
 /*  General helper functions                                       */
 /*******************************************************************/
@@ -203,7 +225,7 @@
 static int mmc_test_busy(struct mmc_command *cmd)
 {
 	return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
-		(R1_CURRENT_STATE(cmd->resp[0]) == 7);
+		(R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
 }
 
 /*
@@ -367,21 +389,26 @@
  * Map memory into a scatterlist.  Optionally allow the same memory to be
  * mapped more than once.
  */
-static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
+static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
 			   struct scatterlist *sglist, int repeat,
 			   unsigned int max_segs, unsigned int max_seg_sz,
-			   unsigned int *sg_len)
+			   unsigned int *sg_len, int min_sg_len)
 {
 	struct scatterlist *sg = NULL;
 	unsigned int i;
+	unsigned long sz = size;
 
 	sg_init_table(sglist, max_segs);
+	if (min_sg_len > max_segs)
+		min_sg_len = max_segs;
 
 	*sg_len = 0;
 	do {
 		for (i = 0; i < mem->cnt; i++) {
 			unsigned long len = PAGE_SIZE << mem->arr[i].order;
 
+			if (min_sg_len && (size / min_sg_len < len))
+				len = ALIGN(size / min_sg_len, 512);
 			if (len > sz)
 				len = sz;
 			if (len > max_seg_sz)
@@ -554,11 +581,12 @@
 
 	printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
 			 "%lu.%09lu seconds (%u kB/s, %u KiB/s, "
-			 "%u.%02u IOPS)\n",
+			 "%u.%02u IOPS, sg_len %d)\n",
 			 mmc_hostname(test->card->host), count, sectors, count,
 			 sectors >> 1, (sectors & 1 ? ".5" : ""),
 			 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
-			 rate / 1000, rate / 1024, iops / 100, iops % 100);
+			 rate / 1000, rate / 1024, iops / 100, iops % 100,
+			 test->area.sg_len);
 
 	mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
 }
@@ -661,7 +689,7 @@
  * Checks that a normal transfer didn't have any errors
  */
 static int mmc_test_check_result(struct mmc_test_card *test,
-	struct mmc_request *mrq)
+				 struct mmc_request *mrq)
 {
 	int ret;
 
@@ -685,6 +713,17 @@
 	return ret;
 }
 
+static int mmc_test_check_result_async(struct mmc_card *card,
+				       struct mmc_async_req *areq)
+{
+	struct mmc_test_async_req *test_async =
+		container_of(areq, struct mmc_test_async_req, areq);
+
+	mmc_test_wait_busy(test_async->test);
+
+	return mmc_test_check_result(test_async->test, areq->mrq);
+}
+
 /*
  * Checks that a "short transfer" behaved as expected
  */
@@ -720,6 +759,85 @@
 }
 
 /*
+ * Tests nonblock transfer with certain parameters
+ */
+static void mmc_test_nonblock_reset(struct mmc_request *mrq,
+				    struct mmc_command *cmd,
+				    struct mmc_command *stop,
+				    struct mmc_data *data)
+{
+	memset(mrq, 0, sizeof(struct mmc_request));
+	memset(cmd, 0, sizeof(struct mmc_command));
+	memset(data, 0, sizeof(struct mmc_data));
+	memset(stop, 0, sizeof(struct mmc_command));
+
+	mrq->cmd = cmd;
+	mrq->data = data;
+	mrq->stop = stop;
+}
+static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
+				      struct scatterlist *sg, unsigned sg_len,
+				      unsigned dev_addr, unsigned blocks,
+				      unsigned blksz, int write, int count)
+{
+	struct mmc_request mrq1;
+	struct mmc_command cmd1;
+	struct mmc_command stop1;
+	struct mmc_data data1;
+
+	struct mmc_request mrq2;
+	struct mmc_command cmd2;
+	struct mmc_command stop2;
+	struct mmc_data data2;
+
+	struct mmc_test_async_req test_areq[2];
+	struct mmc_async_req *done_areq;
+	struct mmc_async_req *cur_areq = &test_areq[0].areq;
+	struct mmc_async_req *other_areq = &test_areq[1].areq;
+	int i;
+	int ret;
+
+	test_areq[0].test = test;
+	test_areq[1].test = test;
+
+	mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+	mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+
+	cur_areq->mrq = &mrq1;
+	cur_areq->err_check = mmc_test_check_result_async;
+	other_areq->mrq = &mrq2;
+	other_areq->err_check = mmc_test_check_result_async;
+
+	for (i = 0; i < count; i++) {
+		mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
+				     blocks, blksz, write);
+		done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
+
+		if (ret || (!done_areq && i > 0))
+			goto err;
+
+		if (done_areq) {
+			if (done_areq->mrq == &mrq2)
+				mmc_test_nonblock_reset(&mrq2, &cmd2,
+							&stop2, &data2);
+			else
+				mmc_test_nonblock_reset(&mrq1, &cmd1,
+							&stop1, &data1);
+		}
+		done_areq = cur_areq;
+		cur_areq = other_areq;
+		other_areq = done_areq;
+		dev_addr += blocks;
+	}
+
+	done_areq = mmc_start_req(test->card->host, NULL, &ret);
+
+	return ret;
+err:
+	return ret;
+}
+
+/*
  * Tests a basic transfer with certain parameters
  */
 static int mmc_test_simple_transfer(struct mmc_test_card *test,
@@ -1302,7 +1420,7 @@
  * Map sz bytes so that it can be transferred.
  */
 static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
-			     int max_scatter)
+			     int max_scatter, int min_sg_len)
 {
 	struct mmc_test_area *t = &test->area;
 	int err;
@@ -1315,7 +1433,7 @@
 				       &t->sg_len);
 	} else {
 		err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
-				      t->max_seg_sz, &t->sg_len);
+				      t->max_seg_sz, &t->sg_len, min_sg_len);
 	}
 	if (err)
 		printk(KERN_INFO "%s: Failed to map sg list\n",
@@ -1336,14 +1454,17 @@
 }
 
 /*
- * Map and transfer bytes.
+ * Map and transfer bytes for multiple transfers.
  */
-static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
-			    unsigned int dev_addr, int write, int max_scatter,
-			    int timed)
+static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
+				unsigned int dev_addr, int write,
+				int max_scatter, int timed, int count,
+				bool nonblock, int min_sg_len)
 {
 	struct timespec ts1, ts2;
-	int ret;
+	int ret = 0;
+	int i;
+	struct mmc_test_area *t = &test->area;
 
 	/*
 	 * In the case of a maximally scattered transfer, the maximum transfer
@@ -1361,14 +1482,21 @@
 			sz = max_tfr;
 	}
 
-	ret = mmc_test_area_map(test, sz, max_scatter);
+	ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len);
 	if (ret)
 		return ret;
 
 	if (timed)
 		getnstimeofday(&ts1);
+	if (nonblock)
+		ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
+				 dev_addr, t->blocks, 512, write, count);
+	else
+		for (i = 0; i < count && ret == 0; i++) {
+			ret = mmc_test_area_transfer(test, dev_addr, write);
+			dev_addr += sz >> 9;
+		}
 
-	ret = mmc_test_area_transfer(test, dev_addr, write);
 	if (ret)
 		return ret;
 
@@ -1376,11 +1504,19 @@
 		getnstimeofday(&ts2);
 
 	if (timed)
-		mmc_test_print_rate(test, sz, &ts1, &ts2);
+		mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
 
 	return 0;
 }
 
+static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
+			    unsigned int dev_addr, int write, int max_scatter,
+			    int timed)
+{
+	return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
+				    timed, 1, false, 0);
+}
+
 /*
  * Write the test area entirely.
  */
@@ -1954,6 +2090,270 @@
 	return mmc_test_large_seq_perf(test, 1);
 }
 
+static int mmc_test_rw_multiple(struct mmc_test_card *test,
+				struct mmc_test_multiple_rw *tdata,
+				unsigned int reqsize, unsigned int size,
+				int min_sg_len)
+{
+	unsigned int dev_addr;
+	struct mmc_test_area *t = &test->area;
+	int ret = 0;
+
+	/* Set up test area */
+	if (size > mmc_test_capacity(test->card) / 2 * 512)
+		size = mmc_test_capacity(test->card) / 2 * 512;
+	if (reqsize > t->max_tfr)
+		reqsize = t->max_tfr;
+	dev_addr = mmc_test_capacity(test->card) / 4;
+	if ((dev_addr & 0xffff0000))
+		dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
+	else
+		dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
+	if (!dev_addr)
+		goto err;
+
+	if (reqsize > size)
+		return 0;
+
+	/* prepare test area */
+	if (mmc_can_erase(test->card) &&
+	    tdata->prepare & MMC_TEST_PREP_ERASE) {
+		ret = mmc_erase(test->card, dev_addr,
+				size / 512, MMC_SECURE_ERASE_ARG);
+		if (ret)
+			ret = mmc_erase(test->card, dev_addr,
+					size / 512, MMC_ERASE_ARG);
+		if (ret)
+			goto err;
+	}
+
+	/* Run test */
+	ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
+				   tdata->do_write, 0, 1, size / reqsize,
+				   tdata->do_nonblock_req, min_sg_len);
+	if (ret)
+		goto err;
+
+	return ret;
+ err:
+	printk(KERN_INFO "[%s] error\n", __func__);
+	return ret;
+}
+
+static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
+				     struct mmc_test_multiple_rw *rw)
+{
+	int ret = 0;
+	int i;
+	void *pre_req = test->card->host->ops->pre_req;
+	void *post_req = test->card->host->ops->post_req;
+
+	if (rw->do_nonblock_req &&
+	    ((!pre_req && post_req) || (pre_req && !post_req))) {
+		printk(KERN_INFO "error: only one of pre/post is defined\n");
+		return -EINVAL;
+	}
+
+	for (i = 0 ; i < rw->len && ret == 0; i++) {
+		ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
+				       struct mmc_test_multiple_rw *rw)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0 ; i < rw->len && ret == 0; i++) {
+		ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
+					   rw->sg_len[i]);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+/*
+ * Multiple blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = true,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = true,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = false,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = false,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = true,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = true,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = false,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = false,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * eMMC hardware reset.
+ */
+static int mmc_test_hw_reset(struct mmc_test_card *test)
+{
+	struct mmc_card *card = test->card;
+	struct mmc_host *host = card->host;
+	int err;
+
+	err = mmc_hw_reset_check(host);
+	if (!err)
+		return RESULT_OK;
+
+	if (err == -ENOSYS)
+		return RESULT_FAIL;
+
+	if (err != -EOPNOTSUPP)
+		return err;
+
+	if (!mmc_can_reset(card))
+		return RESULT_UNSUP_CARD;
+
+	return RESULT_UNSUP_HOST;
+}
+
 static const struct mmc_test_case mmc_test_cases[] = {
 	{
 		.name = "Basic write (no data verification)",
@@ -2221,6 +2621,66 @@
 		.cleanup = mmc_test_area_cleanup,
 	},
 
+	{
+		.name = "Write performance with blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_write_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance with non-blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_write_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance with blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_read_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance with non-blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_read_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_wr_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance non-blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_wr_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_r_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance non-blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_r_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "eMMC hardware reset",
+		.run = mmc_test_hw_reset,
+	},
 };
 
 static DEFINE_MUTEX(mmc_test_lock);
@@ -2429,7 +2889,8 @@
 	}
 
 #ifdef CONFIG_HIGHMEM
-	__free_pages(test->highmem, BUFFER_ORDER);
+	if (test->highmem)
+		__free_pages(test->highmem, BUFFER_ORDER);
 #endif
 	kfree(test->buffer);
 	kfree(test);
@@ -2445,6 +2906,32 @@
 	.release	= single_release,
 };
 
+static int mtf_testlist_show(struct seq_file *sf, void *data)
+{
+	int i;
+
+	mutex_lock(&mmc_test_lock);
+
+	for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
+		seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
+
+	mutex_unlock(&mmc_test_lock);
+
+	return 0;
+}
+
+static int mtf_testlist_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mtf_testlist_show, inode->i_private);
+}
+
+static const struct file_operations mmc_test_fops_testlist = {
+	.open		= mtf_testlist_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static void mmc_test_free_file_test(struct mmc_card *card)
 {
 	struct mmc_test_dbgfs_file *df, *dfs;
@@ -2476,7 +2963,18 @@
 
 	if (IS_ERR_OR_NULL(file)) {
 		dev_err(&card->dev,
-			"Can't create file. Perhaps debugfs is disabled.\n");
+			"Can't create test. Perhaps debugfs is disabled.\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (card->debugfs_root)
+		file = debugfs_create_file("testlist", S_IRUGO,
+			card->debugfs_root, card, &mmc_test_fops_testlist);
+
+	if (IS_ERR_OR_NULL(file)) {
+		dev_err(&card->dev,
+			"Can't create testlist. Perhaps debugfs is disabled.\n");
 		ret = -ENODEV;
 		goto err;
 	}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b2fb161..73f63c9 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -53,26 +53,23 @@
 	struct request_queue *q = mq->queue;
 	struct request *req;
 
-#ifdef CONFIG_MMC_PERF_PROFILING
-	ktime_t start, diff;
-	struct mmc_host *host = mq->card->host;
-	unsigned long bytes_xfer;
-#endif
-
-
 	current->flags |= PF_MEMALLOC;
 
 	down(&mq->thread_sem);
 	do {
+		struct mmc_queue_req *tmp;
 		req = NULL;	/* Must be set to NULL at each iteration */
 
 		spin_lock_irq(q->queue_lock);
 		set_current_state(TASK_INTERRUPTIBLE);
 		req = blk_fetch_request(q);
-		mq->req = req;
+		mq->mqrq_cur->req = req;
 		spin_unlock_irq(q->queue_lock);
 
-		if (!req) {
+		if (req || mq->mqrq_prev->req) {
+			set_current_state(TASK_RUNNING);
+			mq->issue_fn(mq, req);
+		} else {
 			if (kthread_should_stop()) {
 				set_current_state(TASK_RUNNING);
 				break;
@@ -80,30 +77,14 @@
 			up(&mq->thread_sem);
 			schedule();
 			down(&mq->thread_sem);
-			continue;
 		}
-		set_current_state(TASK_RUNNING);
 
-#ifdef CONFIG_MMC_PERF_PROFILING
-		bytes_xfer = blk_rq_bytes(req);
-		if (rq_data_dir(req) == READ) {
-			start = ktime_get();
-			mq->issue_fn(mq, req);
-			diff = ktime_sub(ktime_get(), start);
-			host->perf.rbytes_mmcq += bytes_xfer;
-			host->perf.rtime_mmcq =
-				ktime_add(host->perf.rtime_mmcq, diff);
-		} else {
-			start = ktime_get();
-			mq->issue_fn(mq, req);
-			diff = ktime_sub(ktime_get(), start);
-			host->perf.wbytes_mmcq += bytes_xfer;
-			host->perf.wtime_mmcq =
-				ktime_add(host->perf.wtime_mmcq, diff);
-		}
-#else
-			mq->issue_fn(mq, req);
-#endif
+		/* Current request becomes previous request and vice versa. */
+		mq->mqrq_prev->brq.mrq.data = NULL;
+		mq->mqrq_prev->req = NULL;
+		tmp = mq->mqrq_prev;
+		mq->mqrq_prev = mq->mqrq_cur;
+		mq->mqrq_cur = tmp;
 	} while (1);
 	up(&mq->thread_sem);
 
@@ -129,10 +110,46 @@
 		return;
 	}
 
-	if (!mq->req)
+	if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
 		wake_up_process(mq->thread);
 }
 
+struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
+{
+	struct scatterlist *sg;
+
+	sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
+	if (!sg)
+		*err = -ENOMEM;
+	else {
+		*err = 0;
+		sg_init_table(sg, sg_len);
+	}
+
+	return sg;
+}
+
+static void mmc_queue_setup_discard(struct request_queue *q,
+				    struct mmc_card *card)
+{
+	unsigned max_discard;
+
+	max_discard = mmc_calc_max_discard(card);
+	if (!max_discard)
+		return;
+
+	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+	q->limits.max_discard_sectors = max_discard;
+	if (card->erased_byte == 0)
+		q->limits.discard_zeroes_data = 1;
+	q->limits.discard_granularity = card->pref_erase << 9;
+	/* granularity must not be greater than max. discard */
+	if (card->pref_erase > max_discard)
+		q->limits.discard_granularity = 0;
+	if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
@@ -148,6 +165,8 @@
 	struct mmc_host *host = card->host;
 	u64 limit = BLK_BOUNCE_HIGH;
 	int ret;
+	struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+	struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
 
 	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
 		limit = *mmc_dev(host)->dma_mask;
@@ -157,21 +176,16 @@
 	if (!mq->queue)
 		return -ENOMEM;
 
+	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+	mq->mqrq_cur = mqrq_cur;
+	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
-	mq->req = NULL;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
-	if (mmc_can_erase(card)) {
-		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
-		mq->queue->limits.max_discard_sectors = UINT_MAX;
-		if (card->erased_byte == 0)
-			mq->queue->limits.discard_zeroes_data = 1;
-		mq->queue->limits.discard_granularity = card->pref_erase << 9;
-		if (mmc_can_secure_erase_trim(card))
-			queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD,
-						mq->queue);
-	}
+	if (mmc_can_erase(card))
+		mmc_queue_setup_discard(mq->queue, card);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_segs == 1) {
@@ -187,53 +201,64 @@
 			bouncesz = host->max_blk_count * 512;
 
 		if (bouncesz > 512) {
-			mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
-			if (!mq->bounce_buf) {
+			mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+			if (!mqrq_cur->bounce_buf) {
 				printk(KERN_WARNING "%s: unable to "
-					"allocate bounce buffer\n",
+					"allocate bounce cur buffer\n",
 					mmc_card_name(card));
 			}
+			mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+			if (!mqrq_prev->bounce_buf) {
+				printk(KERN_WARNING "%s: unable to "
+					"allocate bounce prev buffer\n",
+					mmc_card_name(card));
+				kfree(mqrq_cur->bounce_buf);
+				mqrq_cur->bounce_buf = NULL;
+			}
 		}
 
-		if (mq->bounce_buf) {
+		if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
 			blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
 			blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
 			blk_queue_max_segments(mq->queue, bouncesz / 512);
 			blk_queue_max_segment_size(mq->queue, bouncesz);
 
-			mq->sg = kmalloc(sizeof(struct scatterlist),
-				GFP_KERNEL);
-			if (!mq->sg) {
-				ret = -ENOMEM;
+			mqrq_cur->sg = mmc_alloc_sg(1, &ret);
+			if (ret)
 				goto cleanup_queue;
-			}
-			sg_init_table(mq->sg, 1);
 
-			mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
-				bouncesz / 512, GFP_KERNEL);
-			if (!mq->bounce_sg) {
-				ret = -ENOMEM;
+			mqrq_cur->bounce_sg =
+				mmc_alloc_sg(bouncesz / 512, &ret);
+			if (ret)
 				goto cleanup_queue;
-			}
-			sg_init_table(mq->bounce_sg, bouncesz / 512);
+
+			mqrq_prev->sg = mmc_alloc_sg(1, &ret);
+			if (ret)
+				goto cleanup_queue;
+
+			mqrq_prev->bounce_sg =
+				mmc_alloc_sg(bouncesz / 512, &ret);
+			if (ret)
+				goto cleanup_queue;
 		}
 	}
 #endif
 
-	if (!mq->bounce_buf) {
+	if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
 		blk_queue_bounce_limit(mq->queue, limit);
 		blk_queue_max_hw_sectors(mq->queue,
 			min(host->max_blk_count, host->max_req_size / 512));
 		blk_queue_max_segments(mq->queue, host->max_segs);
 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
-		mq->sg = kmalloc(sizeof(struct scatterlist) *
-			host->max_segs, GFP_KERNEL);
-		if (!mq->sg) {
-			ret = -ENOMEM;
+		mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
+		if (ret)
 			goto cleanup_queue;
-		}
-		sg_init_table(mq->sg, host->max_segs);
+
+
+		mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
+		if (ret)
+			goto cleanup_queue;
 	}
 
 	sema_init(&mq->thread_sem, 1);
@@ -248,16 +273,22 @@
 
 	return 0;
  free_bounce_sg:
- 	if (mq->bounce_sg)
- 		kfree(mq->bounce_sg);
- 	mq->bounce_sg = NULL;
+	kfree(mqrq_cur->bounce_sg);
+	mqrq_cur->bounce_sg = NULL;
+	kfree(mqrq_prev->bounce_sg);
+	mqrq_prev->bounce_sg = NULL;
+
  cleanup_queue:
- 	if (mq->sg)
-		kfree(mq->sg);
-	mq->sg = NULL;
-	if (mq->bounce_buf)
-		kfree(mq->bounce_buf);
-	mq->bounce_buf = NULL;
+	kfree(mqrq_cur->sg);
+	mqrq_cur->sg = NULL;
+	kfree(mqrq_cur->bounce_buf);
+	mqrq_cur->bounce_buf = NULL;
+
+	kfree(mqrq_prev->sg);
+	mqrq_prev->sg = NULL;
+	kfree(mqrq_prev->bounce_buf);
+	mqrq_prev->bounce_buf = NULL;
+
 	blk_cleanup_queue(mq->queue);
 	return ret;
 }
@@ -266,6 +297,8 @@
 {
 	struct request_queue *q = mq->queue;
 	unsigned long flags;
+	struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+	struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
 
 	/* Make sure the queue isn't suspended, as that will deadlock */
 	mmc_queue_resume(mq);
@@ -279,16 +312,23 @@
 	blk_start_queue(q);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 
- 	if (mq->bounce_sg)
- 		kfree(mq->bounce_sg);
- 	mq->bounce_sg = NULL;
+	kfree(mqrq_cur->bounce_sg);
+	mqrq_cur->bounce_sg = NULL;
 
-	kfree(mq->sg);
-	mq->sg = NULL;
+	kfree(mqrq_cur->sg);
+	mqrq_cur->sg = NULL;
 
-	if (mq->bounce_buf)
-		kfree(mq->bounce_buf);
-	mq->bounce_buf = NULL;
+	kfree(mqrq_cur->bounce_buf);
+	mqrq_cur->bounce_buf = NULL;
+
+	kfree(mqrq_prev->bounce_sg);
+	mqrq_prev->bounce_sg = NULL;
+
+	kfree(mqrq_prev->sg);
+	mqrq_prev->sg = NULL;
+
+	kfree(mqrq_prev->bounce_buf);
+	mqrq_prev->bounce_buf = NULL;
 
 	mq->card = NULL;
 }
@@ -341,27 +381,27 @@
 /*
  * Prepare the sg list(s) to be handed of to the host driver
  */
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
+unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
 {
 	unsigned int sg_len;
 	size_t buflen;
 	struct scatterlist *sg;
 	int i;
 
-	if (!mq->bounce_buf)
-		return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
+	if (!mqrq->bounce_buf)
+		return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
 
-	BUG_ON(!mq->bounce_sg);
+	BUG_ON(!mqrq->bounce_sg);
 
-	sg_len = blk_rq_map_sg(mq->queue, mq->req, mq->bounce_sg);
+	sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
 
-	mq->bounce_sg_len = sg_len;
+	mqrq->bounce_sg_len = sg_len;
 
 	buflen = 0;
-	for_each_sg(mq->bounce_sg, sg, sg_len, i)
+	for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
 		buflen += sg->length;
 
-	sg_init_one(mq->sg, mq->bounce_buf, buflen);
+	sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
 
 	return 1;
 }
@@ -370,31 +410,30 @@
  * If writing, bounce the data to the buffer before the request
  * is sent to the host driver
  */
-void mmc_queue_bounce_pre(struct mmc_queue *mq)
+void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
 {
-	if (!mq->bounce_buf)
+	if (!mqrq->bounce_buf)
 		return;
 
-	if (rq_data_dir(mq->req) != WRITE)
+	if (rq_data_dir(mqrq->req) != WRITE)
 		return;
 
-	sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
-		mq->bounce_buf, mq->sg[0].length);
+	sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+		mqrq->bounce_buf, mqrq->sg[0].length);
 }
 
 /*
  * If reading, bounce the data from the buffer after the request
  * has been handled by the host driver
  */
-void mmc_queue_bounce_post(struct mmc_queue *mq)
+void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
 {
-	if (!mq->bounce_buf)
+	if (!mqrq->bounce_buf)
 		return;
 
-	if (rq_data_dir(mq->req) != READ)
+	if (rq_data_dir(mqrq->req) != READ)
 		return;
 
-	sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
-		mq->bounce_buf, mq->sg[0].length);
+	sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+		mqrq->bounce_buf, mqrq->sg[0].length);
 }
-
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 6223ef8..d2a1eb4 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -4,19 +4,35 @@
 struct request;
 struct task_struct;
 
+struct mmc_blk_request {
+	struct mmc_request	mrq;
+	struct mmc_command	sbc;
+	struct mmc_command	cmd;
+	struct mmc_command	stop;
+	struct mmc_data		data;
+};
+
+struct mmc_queue_req {
+	struct request		*req;
+	struct mmc_blk_request	brq;
+	struct scatterlist	*sg;
+	char			*bounce_buf;
+	struct scatterlist	*bounce_sg;
+	unsigned int		bounce_sg_len;
+	struct mmc_async_req	mmc_active;
+};
+
 struct mmc_queue {
 	struct mmc_card		*card;
 	struct task_struct	*thread;
 	struct semaphore	thread_sem;
 	unsigned int		flags;
-	struct request		*req;
 	int			(*issue_fn)(struct mmc_queue *, struct request *);
 	void			*data;
 	struct request_queue	*queue;
-	struct scatterlist	*sg;
-	char			*bounce_buf;
-	struct scatterlist	*bounce_sg;
-	unsigned int		bounce_sg_len;
+	struct mmc_queue_req	mqrq[2];
+	struct mmc_queue_req	*mqrq_cur;
+	struct mmc_queue_req	*mqrq_prev;
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -25,8 +41,9 @@
 extern void mmc_queue_suspend(struct mmc_queue *);
 extern void mmc_queue_resume(struct mmc_queue *);
 
-extern unsigned int mmc_queue_map_sg(struct mmc_queue *);
-extern void mmc_queue_bounce_pre(struct mmc_queue *);
-extern void mmc_queue_bounce_post(struct mmc_queue *);
+extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
+				     struct mmc_queue_req *);
+extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
+extern void mmc_queue_bounce_post(struct mmc_queue_req *);
 
 #endif
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 03be6d0..84983e0 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -120,7 +120,8 @@
 	return 0;
 }
 
-static int mmc_bus_suspend(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int mmc_bus_pm_suspend(struct device *dev)
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_card *card = mmc_dev_to_card(dev);
@@ -131,7 +132,7 @@
 	return ret;
 }
 
-static int mmc_bus_resume(struct device *dev)
+static int mmc_bus_pm_resume(struct device *dev)
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_card *card = mmc_dev_to_card(dev);
@@ -141,9 +142,9 @@
 		ret = drv->resume(card);
 	return ret;
 }
+#endif
 
 #ifdef CONFIG_PM_RUNTIME
-
 static int mmc_runtime_suspend(struct device *dev)
 {
 	struct mmc_card *card = mmc_dev_to_card(dev);
@@ -162,19 +163,11 @@
 {
 	return pm_runtime_suspend(dev);
 }
-
-#else /* !CONFIG_PM_RUNTIME */
-#define mmc_runtime_suspend	NULL
-#define mmc_runtime_resume	NULL
-#define mmc_runtime_idle	NULL
-#endif /* !CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM_RUNTIME */
 
 static const struct dev_pm_ops mmc_bus_pm_ops = {
-	.runtime_suspend	= mmc_runtime_suspend,
-	.runtime_resume		= mmc_runtime_resume,
-	.runtime_idle		= mmc_runtime_idle,
-	.suspend		= mmc_bus_suspend,
-	.resume			= mmc_bus_resume,
+	SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_pm_suspend, mmc_bus_pm_resume)
+	SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, mmc_runtime_idle)
 };
 
 static struct bus_type mmc_bus_type = {
@@ -263,6 +256,7 @@
 {
 	int ret;
 	const char *type;
+	const char *uhs_bus_speed_mode = "";
 
 	dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
 
@@ -292,6 +286,28 @@
 		break;
 	}
 
+	if (mmc_sd_card_uhs(card)) {
+		switch (card->sd_bus_speed) {
+		case UHS_SDR104_BUS_SPEED:
+			uhs_bus_speed_mode = "SDR104 ";
+			break;
+		case UHS_SDR50_BUS_SPEED:
+			uhs_bus_speed_mode = "SDR50 ";
+			break;
+		case UHS_DDR50_BUS_SPEED:
+			uhs_bus_speed_mode = "DDR50 ";
+			break;
+		case UHS_SDR25_BUS_SPEED:
+			uhs_bus_speed_mode = "SDR25 ";
+			break;
+		case UHS_SDR12_BUS_SPEED:
+			uhs_bus_speed_mode = "SDR12 ";
+			break;
+		default:
+			uhs_bus_speed_mode = "";
+			break;
+		}
+	}
 	if (mmc_host_is_spi(card->host)) {
 		printk(KERN_INFO "%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
@@ -299,11 +315,13 @@
 			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%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 " : "",
+			uhs_bus_speed_mode,
 			type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 51434b6..ef4ae57 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -106,12 +106,12 @@
 	}
 
 	if (err && cmd->retries && !mmc_card_removed(host->card)) {
-		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
-			mmc_hostname(host), cmd->opcode, err);
-
-		cmd->retries--;
-		cmd->error = 0;
-		host->ops->request(host, mrq);
+		/*
+		 * Request starter must handle retries - see
+		 * mmc_wait_for_req_done().
+		 */
+		if (mrq->done)
+			mrq->done(mrq);
 	} else {
 		led_trigger_event(host->led, LED_OFF);
 
@@ -122,17 +122,21 @@
 
 		if (mrq->data) {
 #ifdef CONFIG_MMC_PERF_PROFILING
-			diff = ktime_sub(ktime_get(), host->perf.start);
-			if (mrq->data->flags == MMC_DATA_READ) {
-				host->perf.rbytes_drv +=
+			if (host->perf_enable) {
+				diff = ktime_sub(ktime_get(), host->perf.start);
+				if (mrq->data->flags == MMC_DATA_READ) {
+					host->perf.rbytes_drv +=
+							mrq->data->bytes_xfered;
+					host->perf.rtime_drv =
+						ktime_add(host->perf.rtime_drv,
+							diff);
+				} else {
+					host->perf.wbytes_drv +=
 						mrq->data->bytes_xfered;
-				host->perf.rtime_drv =
-					ktime_add(host->perf.rtime_drv, diff);
-			} else {
-				host->perf.wbytes_drv +=
-						 mrq->data->bytes_xfered;
-				host->perf.wtime_drv =
-					ktime_add(host->perf.wtime_drv, diff);
+					host->perf.wtime_drv =
+						ktime_add(host->perf.wtime_drv,
+							diff);
+				}
 			}
 #endif
 			pr_debug("%s:     %d bytes transferred: %d\n",
@@ -210,7 +214,8 @@
 			mrq->stop->mrq = mrq;
 		}
 #ifdef CONFIG_MMC_PERF_PROFILING
-		host->perf.start = ktime_get();
+		if (host->perf_enable)
+			host->perf.start = ktime_get();
 #endif
 	}
 	mmc_host_clk_hold(host);
@@ -220,9 +225,123 @@
 
 static void mmc_wait_done(struct mmc_request *mrq)
 {
-	complete(mrq->done_data);
+	complete(&mrq->completion);
 }
 
+static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+	init_completion(&mrq->completion);
+	mrq->done = mmc_wait_done;
+	mmc_start_request(host, mrq);
+}
+
+static void mmc_wait_for_req_done(struct mmc_host *host,
+				  struct mmc_request *mrq)
+{
+	struct mmc_command *cmd;
+
+	while (1) {
+		wait_for_completion(&mrq->completion);
+
+		cmd = mrq->cmd;
+		if (!cmd->error || !cmd->retries)
+			break;
+
+		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+			 mmc_hostname(host), cmd->opcode, cmd->error);
+		cmd->retries--;
+		cmd->error = 0;
+		host->ops->request(host, mrq);
+	}
+}
+
+/**
+ *	mmc_pre_req - Prepare for a new request
+ *	@host: MMC host to prepare command
+ *	@mrq: MMC request to prepare for
+ *	@is_first_req: true if there is no previous started request
+ *                     that may run in parellel to this call, otherwise false
+ *
+ *	mmc_pre_req() is called in prior to mmc_start_req() to let
+ *	host prepare for the new request. Preparation of a request may be
+ *	performed while another request is running on the host.
+ */
+static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+		 bool is_first_req)
+{
+	if (host->ops->pre_req)
+		host->ops->pre_req(host, mrq, is_first_req);
+}
+
+/**
+ *	mmc_post_req - Post process a completed request
+ *	@host: MMC host to post process command
+ *	@mrq: MMC request to post process for
+ *	@err: Error, if non zero, clean up any resources made in pre_req
+ *
+ *	Let the host post process a completed request. Post processing of
+ *	a request may be performed while another reuqest is running.
+ */
+static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+			 int err)
+{
+	if (host->ops->post_req)
+		host->ops->post_req(host, mrq, err);
+}
+
+/**
+ *	mmc_start_req - start a non-blocking request
+ *	@host: MMC host to start command
+ *	@areq: async request to start
+ *	@error: out parameter returns 0 for success, otherwise non zero
+ *
+ *	Start a new MMC custom command request for a host.
+ *	If there is on ongoing async request wait for completion
+ *	of that request and start the new one and return.
+ *	Does not wait for the new request to complete.
+ *
+ *      Returns the completed request, NULL in case of none completed.
+ *	Wait for the an ongoing request (previoulsy started) to complete and
+ *	return the completed request. If there is no ongoing request, NULL
+ *	is returned without waiting. NULL is not an error condition.
+ */
+struct mmc_async_req *mmc_start_req(struct mmc_host *host,
+				    struct mmc_async_req *areq, int *error)
+{
+	int err = 0;
+	struct mmc_async_req *data = host->areq;
+
+	/* Prepare a new request */
+	if (areq)
+		mmc_pre_req(host, areq->mrq, !host->areq);
+
+	if (host->areq) {
+		mmc_wait_for_req_done(host, host->areq->mrq);
+		err = host->areq->err_check(host->card, host->areq);
+		if (err) {
+			mmc_post_req(host, host->areq->mrq, 0);
+			if (areq)
+				mmc_post_req(host, areq->mrq, -EINVAL);
+
+			host->areq = NULL;
+			goto out;
+		}
+	}
+
+	if (areq)
+		__mmc_start_req(host, areq->mrq);
+
+	if (host->areq)
+		mmc_post_req(host, host->areq->mrq, 0);
+
+	host->areq = areq;
+ out:
+	if (error)
+		*error = err;
+	return data;
+}
+EXPORT_SYMBOL(mmc_start_req);
+
 /**
  *	mmc_wait_for_req - start a request and wait for completion
  *	@host: MMC host to start command
@@ -234,21 +353,67 @@
  */
 void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 {
-	DECLARE_COMPLETION_ONSTACK(complete);
+	__mmc_start_req(host, mrq);
+	mmc_wait_for_req_done(host, mrq);
+}
+EXPORT_SYMBOL(mmc_wait_for_req);
 
-	mrq->done_data = &complete;
-	mrq->done = mmc_wait_done;
-	if (mmc_card_removed(host->card)) {
-		mrq->cmd->error = -ENOMEDIUM;
-		return;
+/**
+ *	mmc_interrupt_hpi - Issue for High priority Interrupt
+ *	@card: the MMC card associated with the HPI transfer
+ *
+ *	Issued High Priority Interrupt, and check for card status
+ *	util out-of prg-state.
+ */
+int mmc_interrupt_hpi(struct mmc_card *card)
+{
+	int err;
+	u32 status;
+
+	BUG_ON(!card);
+
+	if (!card->ext_csd.hpi_en) {
+		pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
+		return 1;
 	}
 
-	mmc_start_request(host, mrq);
+	mmc_claim_host(card->host);
+	err = mmc_send_status(card, &status);
+	if (err) {
+		pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
+		goto out;
+	}
 
-	wait_for_completion_io(&complete);
+	/*
+	 * If the card status is in PRG-state, we can send the HPI command.
+	 */
+	if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
+		do {
+			/*
+			 * We don't know when the HPI command will finish
+			 * processing, so we need to resend HPI until out
+			 * of prg-state, and keep checking the card status
+			 * with SEND_STATUS.  If a timeout error occurs when
+			 * sending the HPI command, we are already out of
+			 * prg-state.
+			 */
+			err = mmc_send_hpi_cmd(card, &status);
+			if (err)
+				pr_debug("%s: abort HPI (%d error)\n",
+					 mmc_hostname(card->host), err);
+
+			err = mmc_send_status(card, &status);
+			if (err)
+				break;
+		} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+	} else
+		pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+
+out:
+	mmc_release_host(card->host);
+	return err;
 }
-
-EXPORT_SYMBOL(mmc_wait_for_req);
+EXPORT_SYMBOL(mmc_interrupt_hpi);
 
 /**
  *	mmc_wait_for_cmd - start a command and wait for completion
@@ -262,7 +427,7 @@
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 
 	WARN_ON(!host->claimed);
 
@@ -645,7 +810,7 @@
  * Internal function that does the actual ios call to the host driver,
  * optionally printing some debug output.
  */
-static inline void mmc_set_ios(struct mmc_host *host)
+void mmc_set_ios(struct mmc_host *host)
 {
 	struct mmc_ios *ios = &host->ios;
 
@@ -659,6 +824,7 @@
 		mmc_set_ungated(host);
 	host->ops->set_ios(host, ios);
 }
+EXPORT_SYMBOL(mmc_set_ios);
 
 /*
  * Control chip select pin on a host.
@@ -701,6 +867,8 @@
 {
 	unsigned long flags;
 
+	WARN_ON(!host->ios.clock);
+
 	spin_lock_irqsave(&host->clk_lock, flags);
 	host->clk_old = host->ios.clock;
 	host->ios.clock = 0;
@@ -723,7 +891,7 @@
 	 * we just ignore the call.
 	 */
 	if (host->clk_old) {
-		BUG_ON(host->ios.clock);
+		WARN_ON(host->ios.clock);
 		/* This call will also set host->clk_gated to false */
 		__mmc_set_clock(host, host->clk_old);
 	}
@@ -1035,6 +1203,46 @@
 	mmc_host_clk_release(host);
 }
 
+static void mmc_poweroff_notify(struct mmc_host *host)
+{
+	struct mmc_card *card;
+	unsigned int timeout;
+	unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
+	int err = 0;
+
+	card = host->card;
+
+	/*
+	 * Send power notify command only if card
+	 * is mmc and notify state is powered ON
+	 */
+	if (card && mmc_card_mmc(card) &&
+	    (card->poweroff_notify_state == MMC_POWERED_ON)) {
+
+		if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
+			notify_type = EXT_CSD_POWER_OFF_SHORT;
+			timeout = card->ext_csd.generic_cmd6_time;
+			card->poweroff_notify_state = MMC_POWEROFF_SHORT;
+		} else {
+			notify_type = EXT_CSD_POWER_OFF_LONG;
+			timeout = card->ext_csd.power_off_longtime;
+			card->poweroff_notify_state = MMC_POWEROFF_LONG;
+		}
+
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_OFF_NOTIFICATION,
+				 notify_type, timeout);
+
+		if (err && err != -EBADMSG)
+			pr_err("Device failed to respond within %d poweroff "
+			       "time. Forcefully powering down the device\n",
+			       timeout);
+
+		/* Set the card state to no notification after the poweroff */
+		card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
+	}
+}
+
 /*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
@@ -1046,7 +1254,7 @@
  * If a host does all the power sequencing itself, ignore the
  * initial MMC_POWER_UP stage.
  */
-static void mmc_power_up(struct mmc_host *host)
+void mmc_power_up(struct mmc_host *host)
 {
 	int bit;
 
@@ -1091,13 +1299,15 @@
 	mmc_host_clk_release(host);
 }
 
-static void mmc_power_off(struct mmc_host *host)
+void mmc_power_off(struct mmc_host *host)
 {
 	mmc_host_clk_hold(host);
 
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
 
+	mmc_poweroff_notify(host);
+
 	/*
 	 * Reset ocr mask to be the highest possible voltage supported for
 	 * this mmc host. This value will be used at next power up.
@@ -1211,8 +1421,7 @@
 }
 
 /*
- * Remove the current bus handler from a host. Assumes that there are
- * no interesting cards left, so the bus is powered down.
+ * Remove the current bus handler from a host.
  */
 void mmc_detach_bus(struct mmc_host *host)
 {
@@ -1229,8 +1438,6 @@
 
 	spin_unlock_irqrestore(&host->lock, flags);
 
-	mmc_power_off(host);
-
 	mmc_bus_put(host);
 }
 
@@ -1452,7 +1659,7 @@
 	if (err) {
 		printk(KERN_ERR "mmc_erase: group start error %d, "
 		       "status %#x\n", err, cmd.resp[0]);
-		err = -EINVAL;
+		err = -EIO;
 		goto out;
 	}
 
@@ -1467,7 +1674,7 @@
 	if (err) {
 		printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n",
 		       err, cmd.resp[0]);
-		err = -EINVAL;
+		err = -EIO;
 		goto out;
 	}
 
@@ -1501,7 +1708,7 @@
 			goto out;
 		}
 	} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
-		 R1_CURRENT_STATE(cmd.resp[0]) == 7);
+		 R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
 out:
 	return err;
 }
@@ -1586,10 +1793,32 @@
 {
 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
 		return 1;
+	if (mmc_can_discard(card))
+		return 1;
 	return 0;
 }
 EXPORT_SYMBOL(mmc_can_trim);
 
+int mmc_can_discard(struct mmc_card *card)
+{
+	/*
+	 * As there's no way to detect the discard support bit at v4.5
+	 * use the s/w feature support filed.
+	 */
+	if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_discard);
+
+int mmc_can_sanitize(struct mmc_card *card)
+{
+	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_sanitize);
+
 int mmc_can_secure_erase_trim(struct mmc_card *card)
 {
 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
@@ -1609,6 +1838,82 @@
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
+static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
+					    unsigned int arg)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
+	unsigned int last_timeout = 0;
+
+	if (card->erase_shift)
+		max_qty = UINT_MAX >> card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_qty = UINT_MAX;
+	else
+		max_qty = UINT_MAX / card->erase_size;
+
+	/* Find the largest qty with an OK timeout */
+	do {
+		y = 0;
+		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
+			timeout = mmc_erase_timeout(card, arg, qty + x);
+			if (timeout > host->max_discard_to)
+				break;
+			if (timeout < last_timeout)
+				break;
+			last_timeout = timeout;
+			y = x;
+		}
+		qty += y;
+	} while (y);
+
+	if (!qty)
+		return 0;
+
+	if (qty == 1)
+		return 1;
+
+	/* Convert qty to sectors */
+	if (card->erase_shift)
+		max_discard = --qty << card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_discard = qty;
+	else
+		max_discard = --qty * card->erase_size;
+
+	return max_discard;
+}
+
+unsigned int mmc_calc_max_discard(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, max_trim;
+
+	if (!host->max_discard_to)
+		return UINT_MAX;
+
+	/*
+	 * Without erase_group_def set, MMC erase timeout depends on clock
+	 * frequence which can change.  In that case, the best choice is
+	 * just the preferred erase size.
+	 */
+	if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
+		return card->pref_erase;
+
+	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
+	if (mmc_can_trim(card)) {
+		max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
+		if (max_trim < max_discard)
+			max_discard = max_trim;
+	} else if (max_discard < card->erase_size) {
+		max_discard = 0;
+	}
+	pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
+		 mmc_hostname(host), max_discard, host->max_discard_to);
+	return max_discard;
+}
+EXPORT_SYMBOL(mmc_calc_max_discard);
+
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
@@ -1623,6 +1928,94 @@
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
+static void mmc_hw_reset_for_init(struct mmc_host *host)
+{
+	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+		return;
+	mmc_host_clk_hold(host);
+	host->ops->hw_reset(host);
+	mmc_host_clk_release(host);
+}
+
+int mmc_can_reset(struct mmc_card *card)
+{
+	u8 rst_n_function;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+	rst_n_function = card->ext_csd.rst_n_function;
+	if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
+		return 0;
+	return 1;
+}
+EXPORT_SYMBOL(mmc_can_reset);
+
+static int mmc_do_hw_reset(struct mmc_host *host, int check)
+{
+	struct mmc_card *card = host->card;
+
+	if (!host->bus_ops->power_restore)
+		return -EOPNOTSUPP;
+
+	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+		return -EOPNOTSUPP;
+
+	if (!card)
+		return -EINVAL;
+
+	if (!mmc_can_reset(card))
+		return -EOPNOTSUPP;
+
+	mmc_host_clk_hold(host);
+	mmc_set_clock(host, host->f_init);
+
+	host->ops->hw_reset(host);
+
+	/* If the reset has happened, then a status command will fail */
+	if (check) {
+		struct mmc_command cmd = {0};
+		int err;
+
+		cmd.opcode = MMC_SEND_STATUS;
+		if (!mmc_host_is_spi(card->host))
+			cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+		err = mmc_wait_for_cmd(card->host, &cmd, 0);
+		if (!err) {
+			mmc_host_clk_release(host);
+			return -ENOSYS;
+		}
+	}
+
+	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
+	if (mmc_host_is_spi(host)) {
+		host->ios.chip_select = MMC_CS_HIGH;
+		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+	} else {
+		host->ios.chip_select = MMC_CS_DONTCARE;
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	}
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
+	host->ios.timing = MMC_TIMING_LEGACY;
+	mmc_set_ios(host);
+
+	mmc_host_clk_release(host);
+
+	return host->bus_ops->power_restore(host);
+}
+
+int mmc_hw_reset(struct mmc_host *host)
+{
+	return mmc_do_hw_reset(host, 0);
+}
+EXPORT_SYMBOL(mmc_hw_reset);
+
+int mmc_hw_reset_check(struct mmc_host *host)
+{
+	return mmc_do_hw_reset(host, 1);
+}
+EXPORT_SYMBOL(mmc_hw_reset_check);
+
 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 {
 	host->f_init = freq;
@@ -1634,6 +2027,12 @@
 	mmc_power_up(host);
 
 	/*
+	 * Some eMMCs (with VCCQ always on) may not be reset after power up, so
+	 * do a hardware reset if possible.
+	 */
+	mmc_hw_reset_for_init(host);
+
+	/*
 	 * sdio_reset sends CMD52 to reset card.  Since we do not know
 	 * if the card is being re-initialized, just send it.  CMD52
 	 * should be ignored by SD/eMMC cards.
@@ -1796,6 +2195,7 @@
 
 		mmc_claim_host(host);
 		mmc_detach_bus(host);
+		mmc_power_off(host);
 		mmc_release_host(host);
 		mmc_bus_put(host);
 		return;
@@ -1870,7 +2270,7 @@
 
 	mmc_bus_get(host);
 
-	if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+	if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
 		err = host->bus_ops->sleep(host);
 
 	mmc_bus_put(host);
@@ -1889,6 +2289,65 @@
 }
 EXPORT_SYMBOL(mmc_card_can_sleep);
 
+/*
+ * Flush the cache to the non-volatile storage.
+ */
+int mmc_flush_cache(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
+		return err;
+
+	if (mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0) &&
+			(card->ext_csd.cache_ctrl & 1)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_FLUSH_CACHE, 1, 0);
+		if (err)
+			pr_err("%s: cache flush error %d\n",
+					mmc_hostname(card->host), err);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_flush_cache);
+
+/*
+ * Turn the cache ON/OFF.
+ * Turning the cache OFF shall trigger flushing of the data
+ * to the non-volatile storage.
+ */
+int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
+{
+	struct mmc_card *card = host->card;
+	int err = 0;
+
+	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
+			mmc_card_is_removable(host))
+		return err;
+
+	if (card && mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0)) {
+		enable = !!enable;
+
+		if (card->ext_csd.cache_ctrl ^ enable)
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_CACHE_CTRL, enable, 0);
+		if (err)
+			pr_err("%s: cache %s error %d\n",
+					mmc_hostname(card->host),
+					enable ? "on" : "off",
+					err);
+		else
+			card->ext_csd.cache_ctrl = enable;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_cache_ctrl);
+
 #ifdef CONFIG_PM
 
 /**
@@ -1907,10 +2366,12 @@
 	if (cancel_delayed_work(&host->detect))
 		wake_unlock(&host->detect_wake_lock);
 	mmc_flush_scheduled_work();
+	err = mmc_cache_ctrl(host, 0);
+	if (err)
+		goto out;
 
 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
-
 		/*
 		 * A long response time is not acceptable for device drivers
 		 * when doing suspend. Prevent mmc_claim_host in the suspend
@@ -1954,6 +2415,7 @@
 	if (!err && !mmc_card_keep_power(host))
 		mmc_power_off(host);
 
+out:
 	return err;
 }
 
@@ -2029,6 +2491,7 @@
 			break;
 		}
 		host->rescan_disable = 1;
+		host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
 		spin_unlock_irqrestore(&host->lock, flags);
 		if (cancel_delayed_work_sync(&host->detect))
 			wake_unlock(&host->detect_wake_lock);
@@ -2042,6 +2505,7 @@
 			host->bus_ops->remove(host);
 
 		mmc_detach_bus(host);
+		mmc_power_off(host);
 		mmc_release_host(host);
 		host->pm_flags = 0;
 		break;
@@ -2056,6 +2520,7 @@
 			break;
 		}
 		host->rescan_disable = 0;
+		host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
 		spin_unlock_irqrestore(&host->lock, flags);
 		mmc_detect_change(host, 0);
 
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 49684f6..e4b098a 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -32,6 +32,8 @@
 
 void mmc_init_erase(struct mmc_card *card);
 
+void mmc_power_up(struct mmc_host *host);
+void mmc_power_off(struct mmc_host *host);
 void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_gate_clock(struct mmc_host *host);
@@ -44,6 +46,7 @@
 			   bool cmd11);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+void mmc_power_off(struct mmc_host *host);
 
 static inline void mmc_delay(unsigned int ms)
 {
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/host.c b/drivers/mmc/core/host.c
index 1985745..a162586 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -399,18 +399,23 @@
 {
 	int64_t value;
 	struct mmc_host *host = dev_get_drvdata(dev);
+
 	sscanf(buf, "%lld", &value);
+	spin_lock(&host->lock);
 	if (!value) {
-		spin_lock(&host->lock);
 		memset(&host->perf, 0, sizeof(host->perf));
-		spin_unlock(&host->lock);
+		host->perf_enable = false;
+	} else {
+		host->perf_enable = true;
 	}
+	spin_unlock(&host->lock);
 
 	return count;
 }
 
 static DEVICE_ATTR(perf, S_IRUGO | S_IWUSR,
 		show_perf, set_perf);
+
 #endif
 
 static struct attribute *dev_attrs[] = {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 79d6e97..9385087 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -259,7 +259,7 @@
 	}
 
 	card->ext_csd.rev = ext_csd[EXT_CSD_REV];
-	if (card->ext_csd.rev > 5) {
+	if (card->ext_csd.rev > 6) {
 		printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
 			mmc_hostname(card->host), card->ext_csd.rev);
 		err = -EINVAL;
@@ -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;
@@ -359,6 +380,7 @@
 		 * card has the Enhanced area enabled.  If so, export enhanced
 		 * area offset and size to user by adding sysfs interface.
 		 */
+		card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
 		if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
 		    (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
 			u8 hc_erase_grp_sz =
@@ -402,14 +424,48 @@
 			ext_csd[EXT_CSD_TRIM_MULT];
 	}
 
-	if (card->ext_csd.rev >= 5)
-		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+	if (card->ext_csd.rev >= 5) {
+		/* check whether the eMMC card supports HPI */
+		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+			card->ext_csd.hpi = 1;
+			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
+				card->ext_csd.hpi_cmd =	MMC_STOP_TRANSMISSION;
+			else
+				card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
+			/*
+			 * Indicate the maximum timeout to close
+			 * a command interrupted by HPI
+			 */
+			card->ext_csd.out_of_int_time =
+				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
+		}
 
+		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+	}
+
+	card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
 	if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
 		card->erased_byte = 0xFF;
 	else
 		card->erased_byte = 0x0;
 
+	/* eMMC v4.5 or later */
+	if (card->ext_csd.rev >= 6) {
+		card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
+
+		card->ext_csd.generic_cmd6_time = 10 *
+			ext_csd[EXT_CSD_GENERIC_CMD6_TIME];
+		card->ext_csd.power_off_longtime = 10 *
+			ext_csd[EXT_CSD_POWER_OFF_LONG_TIME];
+
+		card->ext_csd.cache_size =
+			ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+	}
+
 out:
 	return err;
 }
@@ -530,6 +586,164 @@
 };
 
 /*
+ * Select the PowerClass for the current bus width
+ * If power class is defined for 4/8 bit bus in the
+ * extended CSD register, select it by executing the
+ * mmc_switch command.
+ */
+static int mmc_select_powerclass(struct mmc_card *card,
+		unsigned int bus_width, u8 *ext_csd)
+{
+	int err = 0;
+	unsigned int pwrclass_val;
+	unsigned int index = 0;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+	BUG_ON(!host);
+
+	if (ext_csd == NULL)
+		return 0;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == EXT_CSD_BUS_WIDTH_1)
+		return 0;
+
+	switch (1 << host->ios.vdd) {
+	case MMC_VDD_165_195:
+		if (host->ios.clock <= 26000000)
+			index = EXT_CSD_PWR_CL_26_195;
+		else if	(host->ios.clock <= 52000000)
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_52_195 :
+				EXT_CSD_PWR_CL_DDR_52_195;
+		else if (host->ios.clock <= 200000000)
+			index = EXT_CSD_PWR_CL_200_195;
+		break;
+	case MMC_VDD_27_28:
+	case MMC_VDD_28_29:
+	case MMC_VDD_29_30:
+	case MMC_VDD_30_31:
+	case MMC_VDD_31_32:
+	case MMC_VDD_32_33:
+	case MMC_VDD_33_34:
+	case MMC_VDD_34_35:
+	case MMC_VDD_35_36:
+		if (host->ios.clock <= 26000000)
+			index = EXT_CSD_PWR_CL_26_360;
+		else if	(host->ios.clock <= 52000000)
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_52_360 :
+				EXT_CSD_PWR_CL_DDR_52_360;
+		else if (host->ios.clock <= 200000000)
+			index = EXT_CSD_PWR_CL_200_360;
+		break;
+	default:
+		pr_warning("%s: Voltage range not supported "
+			   "for power class.\n", mmc_hostname(host));
+		return -EINVAL;
+	}
+
+	pwrclass_val = ext_csd[index];
+
+	if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
+		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
+				EXT_CSD_PWR_CL_8BIT_SHIFT;
+	else
+		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
+				EXT_CSD_PWR_CL_4BIT_SHIFT;
+
+	/* If the power class is different from the default value */
+	if (pwrclass_val > 0) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_CLASS,
+				 pwrclass_val,
+				 card->ext_csd.generic_cmd6_time);
+	}
+
+	return err;
+}
+
+/*
+ * 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
@@ -671,7 +885,8 @@
 	 */
 	if (card->ext_csd.enhanced_area_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_ERASE_GROUP_DEF, 1, 0);
+				 EXT_CSD_ERASE_GROUP_DEF, 1,
+				 card->ext_csd.generic_cmd6_time);
 
 		if (err && err != -EBADMSG)
 			goto free_card;
@@ -709,12 +924,39 @@
 	}
 
 	/*
+	 * If the host supports the power_off_notify capability then
+	 * set the notification byte in the ext_csd register of device
+	 */
+	if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
+	    (card->ext_csd.rev >= 6)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_OFF_NOTIFICATION,
+				 EXT_CSD_POWER_ON,
+				 card->ext_csd.generic_cmd6_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
+
+		/*
+		 * The err can be -EBADMSG or 0,
+		 * so check for success and update the flag
+		 */
+		if (!err)
+			card->poweroff_notify_state = MMC_POWERED_ON;
+	}
+
+	/*
 	 * 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, 0);
+	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;
 
@@ -723,8 +965,15 @@
 			       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);
+			}
 		}
 	}
 
@@ -733,7 +982,7 @@
 	 */
 	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) {
@@ -759,9 +1008,50 @@
 	}
 
 	/*
+	 * 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_warning("%s: power class selection to bus width %d"
+				   " failed\n", mmc_hostname(card->host),
+				   1 << bus_width);
+	}
+
+	/*
 	 * 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 },
@@ -783,10 +1073,18 @@
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
+			err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
+						    ext_csd);
+			if (err)
+				pr_warning("%s: power class selection to "
+					   "bus width %d failed\n",
+					   mmc_hostname(card->host),
+					   1 << bus_width);
+
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][0],
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 			if (!err) {
 				mmc_set_bus_width(card->host, bus_width);
 
@@ -806,10 +1104,18 @@
 		}
 
 		if (!err && ddr) {
+			err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
+						    ext_csd);
+			if (err)
+				pr_warning("%s: power class selection to "
+					   "bus width %d ddr %d failed\n",
+					   mmc_hostname(card->host),
+					   1 << bus_width, ddr);
+
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 		}
 		if (err) {
 			printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
@@ -843,6 +1149,40 @@
 		}
 	}
 
+	/*
+	 * 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.
+	 */
+	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
+			card->ext_csd.cache_size > 0) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_CACHE_CTRL, 1, 0);
+		if (err && err != -EBADMSG)
+			goto free_card;
+
+		/*
+		 * Only if no error, cache is turned on successfully.
+		 */
+		card->ext_csd.cache_ctrl = err ? 0 : 1;
+	}
+
 	if (!oldcard)
 		host->card = card;
 
@@ -905,6 +1245,7 @@
 
 		mmc_claim_host(host);
 		mmc_detach_bus(host);
+		mmc_power_off(host);
 		mmc_release_host(host);
 	}
 }
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 2e39d2c..2438176 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -233,7 +233,7 @@
 mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
 		u32 opcode, void *buf, unsigned len)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -408,7 +408,7 @@
 			break;
 		if (mmc_host_is_spi(card->host))
 			break;
-	} while (R1_CURRENT_STATE(status) == 7);
+	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
 	if (mmc_host_is_spi(card->host)) {
 		if (status & R1_SPI_ILLEGAL_COMMAND)
@@ -455,7 +455,7 @@
 mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
 		  u8 len)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -551,3 +551,34 @@
 	err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
 	return err;
 }
+
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
+{
+	struct mmc_command cmd = {0};
+	unsigned int opcode;
+	unsigned int flags;
+	int err;
+
+	opcode = card->ext_csd.hpi_cmd;
+	if (opcode == MMC_STOP_TRANSMISSION)
+		flags = MMC_RSP_R1 | MMC_CMD_AC;
+	else if (opcode == MMC_SEND_STATUS)
+		flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	cmd.opcode = opcode;
+	cmd.arg = card->rca << 16 | 1;
+	cmd.flags = flags;
+	cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err) {
+		pr_warn("%s: error %d interrupting operation. "
+			"HPI command response %#x\n", mmc_hostname(card->host),
+			err, cmd.resp[0]);
+		return err;
+	}
+	if (status)
+		*status = cmd.resp[0];
+
+	return 0;
+}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 9276946..3dd8941 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -26,6 +26,7 @@
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 int mmc_card_sleepawake(struct mmc_host *host, int sleep);
 int mmc_bus_test(struct mmc_card *card, u8 bus_width);
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
 
 #endif
 
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 3a59621..92990b9 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -21,6 +21,14 @@
 #define SDIO_DEVICE_ID_TI_WL1271	0x4076
 #endif
 
+#ifndef SDIO_VENDOR_ID_MSM
+#define SDIO_VENDOR_ID_MSM		0x0070
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_WCN1314
+#define SDIO_DEVICE_ID_MSM_WCN1314	0x2881
+#endif
+
 /*
  * This hook just adds a quirk for all sdio devices
  */
@@ -40,6 +48,9 @@
 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
 		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
 
+	SDIO_FIXUP(SDIO_VENDOR_ID_MSM, SDIO_DEVICE_ID_MSM_WCN1314,
+		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
 		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6522efb..597f2b5 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);
 	}
 
@@ -1093,6 +1094,7 @@
 
 		mmc_claim_host(host);
 		mmc_detach_bus(host);
+		mmc_power_off(host);
 		mmc_release_host(host);
 	}
 }
@@ -1139,8 +1141,11 @@
 		if (err) {
 			printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n",
 			       mmc_hostname(host), err, retries);
-			mdelay(5);
 			retries--;
+			mmc_power_off(host);
+			usleep_range(5000, 5500);
+			mmc_power_up(host);
+			mmc_select_voltage(host, host->ocr);
 			continue;
 		}
 		break;
@@ -1277,6 +1282,10 @@
 		err = mmc_sd_init_card(host, host->ocr, NULL);
 		if (err) {
 			retries--;
+			mmc_power_off(host);
+			usleep_range(5000, 5500);
+			mmc_power_up(host);
+			mmc_select_voltage(host, host->ocr);
 			continue;
 		}
 		break;
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed1..46a7854 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -67,7 +67,7 @@
 int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
 	struct mmc_command *cmd, int retries)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 
 	int i, err;
 
@@ -244,7 +244,7 @@
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 {
 	int err;
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -303,7 +303,7 @@
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 	u8 value, u8 *resp)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -348,7 +348,7 @@
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
 {
 	int err;
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 8ac2e59..39e6ce3 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>
@@ -635,6 +636,7 @@
 
 		mmc_claim_host(host);
 		mmc_detach_bus(host);
+		mmc_power_off(host);
 		mmc_release_host(host);
 	}
 }
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 8b250c12..28505636 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -31,17 +31,6 @@
 {
 	int i, ret, count;
 	unsigned char pending;
-	struct sdio_func *func;
-
-	/*
-	 * Optimization, if there is only 1 function interrupt registered
-	 * call irq handler directly
-	 */
-	func = card->sdio_single_irq;
-	if (func) {
-		func->irq_handler(func);
-		return 1;
-	}
 
 	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
 	if (ret) {
@@ -53,7 +42,7 @@
 	count = 0;
 	for (i = 1; i <= 7; i++) {
 		if (pending & (1 << i)) {
-			func = card->sdio_func[i - 1];
+			struct sdio_func *func = card->sdio_func[i - 1];
 			if (!func) {
 				printk(KERN_WARNING "%s: pending IRQ for "
 					"non-existent function\n",
@@ -203,24 +192,6 @@
 	return 0;
 }
 
-/* If there is only 1 function registered set sdio_single_irq */
-static void sdio_single_irq_set(struct mmc_card *card)
-{
-	struct sdio_func *func;
-	int i;
-
-	card->sdio_single_irq = NULL;
-	if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
-	    card->host->sdio_irqs == 1)
-		for (i = 0; i < card->sdio_funcs; i++) {
-		       func = card->sdio_func[i];
-		       if (func && func->irq_handler) {
-			       card->sdio_single_irq = func;
-			       break;
-		       }
-	       }
-}
-
 /**
  *	sdio_claim_irq - claim the IRQ for a SDIO function
  *	@func: SDIO function
@@ -262,7 +233,6 @@
 	ret = sdio_card_irq_get(func->card);
 	if (ret)
 		func->irq_handler = NULL;
-	sdio_single_irq_set(func->card);
 
 	return ret;
 }
@@ -287,7 +257,6 @@
 	if (func->irq_handler) {
 		func->irq_handler = NULL;
 		sdio_card_irq_put(func->card);
-		sdio_single_irq_set(func->card);
 	}
 
 	ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index f087d87..4addbe9 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -121,7 +121,7 @@
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7c1e16a..92946b8 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/bio.h>
 #include <linux/dma-mapping.h>
 #include <linux/crc7.h>
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index fe14072..9394d0b 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -557,7 +557,8 @@
 	      unsigned int status)
 {
 	/* First check for errors */
-	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
+		      MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
 		u32 remain, success;
 
 		/* Terminate the DMA transfer */
@@ -636,8 +637,12 @@
 	}
 
 	if (!cmd->data || cmd->error) {
-		if (host->data)
+		if (host->data) {
+			/* Terminate the DMA transfer */
+			if (dma_inprogress(host))
+				mmci_dma_data_error(host);
 			mmci_stop_data(host);
+		}
 		mmci_request_end(host, cmd->mrq);
 	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
 		mmci_start_data(host, cmd->data);
@@ -837,8 +842,9 @@
 		dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 
 		data = host->data;
-		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
-			      MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
+		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
+			      MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
+			      MCI_DATABLOCKEND) && data)
 			mmci_data_irq(host, data, status);
 
 		cmd = host->cmd;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e364eac..f03aeac 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -53,7 +53,6 @@
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
 #include <mach/dma.h>
-#include <mach/htc_pwrsink.h>
 #include <mach/sdio_al.h>
 
 #include "msm_sdcc.h"
@@ -96,13 +95,24 @@
  * An array holding the Tuning pattern to compare with when
  * executing a tuning cycle.
  */
-static const u32 cmd19_tuning_block[16] = {
+static const u32 tuning_block_64[] = {
 	0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
 	0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
 	0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
 	0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
 };
 
+static const u32 tuning_block_128[] = {
+	0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
+	0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
+	0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
+	0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
+	0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
+	0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
+	0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
+	0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
+};
+
 #if IRQ_DEBUG == 1
 static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
 				   "dattimeout", "txunderrun", "rxoverrun",
@@ -132,8 +142,11 @@
 static void
 msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
 		      u32 c);
+static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
 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 int msmsdcc_vreg_reset(struct msmsdcc_host *host);
 
 static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
 {
@@ -248,9 +261,9 @@
 	 * and CPSM (command path state machine).
 	 */
 	writel_relaxed(0, host->base + MMCICOMMAND);
-	msmsdcc_delay(host);
+	msmsdcc_sync_reg_wr(host);
 	writel_relaxed(0, host->base + MMCIDATACTRL);
-	msmsdcc_delay(host);
+	msmsdcc_sync_reg_wr(host);
 }
 
 static void msmsdcc_hard_reset(struct msmsdcc_host *host)
@@ -270,6 +283,7 @@
 			" with err %d\n", mmc_hostname(host->mmc),
 			host->clk_rate, ret);
 
+	mb();
 	/* Give some delay for clock reset to propogate to controller */
 	msmsdcc_delay(host);
 }
@@ -303,6 +317,7 @@
 		/* Save the controller state */
 		mci_clk = readl_relaxed(host->base + MMCICLOCK);
 		mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
+		host->pwr = readl_relaxed(host->base + MMCIPOWER);
 		mb();
 
 		msmsdcc_hard_reset(host);
@@ -311,9 +326,9 @@
 
 		/* Restore the contoller state */
 		writel_relaxed(host->pwr, host->base + MMCIPOWER);
-		msmsdcc_delay(host);
+		msmsdcc_sync_reg_wr(host);
 		writel_relaxed(mci_clk, host->base + MMCICLOCK);
-		msmsdcc_delay(host);
+		msmsdcc_sync_reg_wr(host);
 		writel_relaxed(mci_mask0, host->base + MMCIMASK0);
 		mb(); /* no delay required after writing to MASK0 register */
 	}
@@ -329,9 +344,6 @@
 
 	BUG_ON(host->curr.data);
 
-	host->curr.mrq = NULL;
-	host->curr.cmd = NULL;
-
 	del_timer(&host->req_tout_timer);
 
 	if (mrq->data)
@@ -339,6 +351,9 @@
 	if (mrq->cmd->error == -ETIMEDOUT)
 		mdelay(5);
 
+	/* Clear current request information as current request has ended */
+	memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
+
 	/*
 	 * Need to drop the host lock here; mmc_request_done may call
 	 * back into the driver...
@@ -359,7 +374,7 @@
 	host->curr.got_auto_prog_done = 0;
 	writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
 			(~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
-	msmsdcc_delay(host);	/* Allow the DPSM to be reset */
+	msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
 }
 
 static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
@@ -370,16 +385,15 @@
 static inline unsigned int msmsdcc_get_min_sup_clk_rate(
 					struct msmsdcc_host *host);
 
-static inline void msmsdcc_delay(struct msmsdcc_host *host)
+static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
 {
-	ktime_t start, diff;
-
 	mb();
-	udelay(host->reg_write_delay);
+	if (!host->sdcc_version)
+		udelay(host->reg_write_delay);
+	else if (readl_relaxed(host->base + MCI_STATUS2) &
+			MCI_MCLK_REG_WR_ACTIVE) {
+		ktime_t start, diff;
 
-	if (host->sdcc_version &&
-		(readl_relaxed(host->base + MCI_STATUS2) &
-			MCI_MCLK_REG_WR_ACTIVE)) {
 		start = ktime_get();
 		while (readl_relaxed(host->base + MCI_STATUS2) &
 			MCI_MCLK_REG_WR_ACTIVE) {
@@ -395,6 +409,12 @@
 	}
 }
 
+static inline void msmsdcc_delay(struct msmsdcc_host *host)
+{
+	udelay(host->reg_write_delay);
+
+}
+
 static inline void
 msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
 {
@@ -418,7 +438,7 @@
 	writel_relaxed((unsigned int)host->curr.xfer_size,
 			host->base + MMCIDATALENGTH);
 	writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
-	msmsdcc_delay(host);	/* Force delay prior to ADM or command */
+	msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
 
 	if (host->cmd_cmd) {
 		msmsdcc_start_command_exec(host,
@@ -498,10 +518,13 @@
 		msmsdcc_stop_data(host);
 		if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
-			host->curr.mrq = NULL;
-			host->curr.cmd = NULL;
 			mrq->data->bytes_xfered = host->curr.data_xfered;
 			del_timer(&host->req_tout_timer);
+			/*
+			 * Clear current request information as current
+			 * request has ended
+			 */
+			memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
 			spin_unlock_irqrestore(&host->lock, flags);
 
 			mmc_request_done(host->mmc, mrq);
@@ -655,10 +678,13 @@
 		msmsdcc_stop_data(host);
 		if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
-			host->curr.mrq = NULL;
-			host->curr.cmd = NULL;
 			mrq->data->bytes_xfered = host->curr.data_xfered;
 			del_timer(&host->req_tout_timer);
+			/*
+			 * Clear current request information as current
+			 * request has ended
+			 */
+			memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
 			spin_unlock_irqrestore(&host->lock, flags);
 
 			mmc_request_done(host->mmc, mrq);
@@ -984,7 +1010,9 @@
 		*c |= MCI_CSPM_DATCMD;
 
 	/* Check if AUTO CMD19 is required or not? */
-	if (host->tuning_needed) {
+	if (host->tuning_needed &&
+		!(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
+
 		/*
 		 * For open ended block read operation (without CMD23),
 		 * AUTO_CMD19 bit should be set while sending the READ command.
@@ -1076,21 +1104,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)
@@ -1131,18 +1153,20 @@
 				(~(MCI_IRQ_PIO))) | pio_irqmask,
 				host->base + MMCIMASK0);
 		writel_relaxed(datactrl, base + MMCIDATACTRL);
-		/*
-		 * We don't need delay after writing to DATA_CTRL register
-		 * if we are not writing to CMD register immediately after
-		 * this. As we already have delay before sending the
-		 * command, we just need mb() here.
-		 */
-		mb();
 
 		if (cmd) {
-			msmsdcc_delay(host); /* Delay between data/command */
+			/* Delay between data/command */
+			msmsdcc_sync_reg_wr(host);
 			/* Daisy-chain the command if requested */
 			msmsdcc_start_command(host, cmd, c);
+		} else {
+			/*
+			 * We don't need delay after writing to DATA_CTRL
+			 * register if we are not writing to CMD register
+			 * immediately after this. As we already have delay
+			 * before sending the command, we just need mb() here.
+			 */
+			mb();
 		}
 	}
 }
@@ -1160,7 +1184,9 @@
 {
 	if (status & MCI_DATACRCFAIL) {
 		if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
-			|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
+			|| data->mrq->cmd->opcode == MMC_BUS_TEST_R
+			|| data->mrq->cmd->opcode ==
+				MMC_SEND_TUNING_BLOCK_HS200)) {
 			pr_err("%s: Data CRC error\n",
 			       mmc_hostname(host->mmc));
 			pr_err("%s: opcode 0x%.8x\n", __func__,
@@ -1250,6 +1276,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 +1421,8 @@
 	void __iomem		*base = host->base;
 	uint32_t		status;
 	unsigned long flags;
+	unsigned int remain;
+	char *buffer;
 
 	spin_lock(&host->lock);
 
@@ -1267,45 +1433,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) {
@@ -1384,7 +1548,7 @@
 				mmc_hostname(host->mmc), cmd->opcode);
 		cmd->error = -ETIMEDOUT;
 	} else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
-			!host->cmd19_tuning_in_progress) {
+			!host->tuning_in_progress) {
 		pr_err("%s: CMD%d: Command CRC error\n",
 			mmc_hostname(host->mmc), cmd->opcode);
 		msmsdcc_dump_sdcc_state(host);
@@ -1414,6 +1578,7 @@
 					host->curr.cmd = cmd;
 			} else {
 				host->prog_enable = 0;
+				host->curr.wait_for_auto_prog_done = 0;
 				if (host->dummy_52_needed)
 					host->dummy_52_needed = 0;
 				if (cmd->data && cmd->error)
@@ -1454,18 +1619,32 @@
 		if (!host->clks_on) {
 			pr_debug("%s: %s: SDIO async irq received\n",
 					mmc_hostname(host->mmc), __func__);
-			host->mmc->ios.clock = host->clk_rate;
-			spin_unlock(&host->lock);
-			host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
-			spin_lock(&host->lock);
-			if (host->plat->cfg_mpm_sdiowakeup &&
-				(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
+
+			/*
+			 * Only async interrupt can come when clocks are off,
+			 * disable further interrupts and enable them when
+			 * clocks are on.
+			 */
+			if (!host->sdcc_irq_disabled) {
+				disable_irq_nosync(irq);
+				host->sdcc_irq_disabled = 1;
+			}
+
+			/*
+			 * If mmc_card_wake_sdio_irq() is set, mmc core layer
+			 * will take care of signaling sdio irq during
+			 * mmc_sdio_resume().
+			 */
+			if (host->sdcc_suspended)
+				/*
+				 * This is a wakeup interrupt so hold wakelock
+				 * until SDCC resume is handled.
+				 */
 				wake_lock(&host->sdio_wlock);
-			/* only ansyc interrupt can come when clocks are off */
-			writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
-			if (host->clk_rate <=
-					msmsdcc_get_min_sup_clk_rate(host))
-				msmsdcc_delay(host);
+			else
+				mmc_signal_sdio_irq(host->mmc);
+			ret = 1;
+			break;
 		}
 
 		status = readl_relaxed(host->base + MMCISTATUS);
@@ -1482,7 +1661,7 @@
 		/* Allow clear to take effect*/
 		if (host->clk_rate <=
 				msmsdcc_get_min_sup_clk_rate(host))
-			msmsdcc_delay(host);
+			msmsdcc_sync_reg_wr(host);
 #if IRQ_DEBUG
 		msmsdcc_print_status(host, "irq0-p", status);
 #endif
@@ -1835,6 +2014,10 @@
 			if (rc)
 				goto vccq_reg_deinit;
 		}
+		rc = msmsdcc_vreg_reset(host);
+		if (rc)
+			pr_err("msmsdcc.%d vreg reset failed (%d)\n",
+			       host->pdev_id, rc);
 		goto out;
 	} else {
 		/* Deregister all regulators from regulator framework */
@@ -1943,6 +2126,21 @@
 	return rc;
 }
 
+/*
+ * Reset vreg by ensuring it is off during probe. A call
+ * to enable vreg is needed to balance disable vreg
+ */
+static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
+{
+	int rc;
+
+	rc = msmsdcc_setup_vreg(host, 1);
+	if (rc)
+		return rc;
+	rc = msmsdcc_setup_vreg(host, 0);
+	return rc;
+}
+
 static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
 {
 	int rc = 0;
@@ -1994,6 +2192,22 @@
 	return rc;
 }
 
+static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
+{
+	struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
+	int rc = 0;
+
+	if (curr_slot && curr_slot->vccq_data) {
+		rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
+				level, level);
+		if (rc)
+			pr_err("%s: %s: failed to change vccq level to %d",
+				mmc_hostname(host->mmc), __func__, level);
+	}
+
+	return rc;
+}
+
 static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
 {
 	if (host->clk_rate > 400000 && msmsdcc_pwrsave)
@@ -2009,8 +2223,10 @@
 		if (!IS_ERR(host->pclk))
 			clk_enable(host->pclk);
 		clk_enable(host->clk);
+		mb();
 		msmsdcc_delay(host);
 	} else {
+		mb();
 		msmsdcc_delay(host);
 		clk_disable(host->clk);
 		if (!IS_ERR(host->pclk))
@@ -2025,6 +2241,11 @@
 {
 	unsigned int sel_clk = -1;
 
+	if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
+		sel_clk = msmsdcc_get_min_sup_clk_rate(host);
+		goto out;
+	}
+
 	if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
 		unsigned char cnt;
 
@@ -2045,6 +2266,7 @@
 			sel_clk = req_clk;
 	}
 
+out:
 	return sel_clk;
 }
 
@@ -2150,6 +2372,56 @@
 	return rc;
 }
 
+static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
+{
+	u32 pwr = 0;
+	int ret = 0;
+	struct mmc_host *mmc = host->mmc;
+
+	if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
+		ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
+	else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
+		ret = msmsdcc_setup_vreg(host, !!ios->vdd);
+
+	if (ret) {
+		pr_err("%s: Failed to setup voltage regulators\n",
+				mmc_hostname(host->mmc));
+		goto out;
+	}
+
+	switch (ios->power_mode) {
+	case MMC_POWER_OFF:
+		pwr = MCI_PWR_OFF;
+		if (host->plat->cfg_mpm_sdiowakeup)
+			host->plat->cfg_mpm_sdiowakeup(
+				mmc_dev(mmc), SDC_DAT1_DISABLE);
+		/*
+		 * As VDD pad rail is always on, set low voltage for VDD
+		 * pad rail when slot is unused (when card is not present
+		 * or during system suspend).
+		 */
+		msmsdcc_set_vddp_low_vol(host);
+		msmsdcc_setup_pins(host, false);
+		break;
+	case MMC_POWER_UP:
+		/* writing PWR_UP bit is redundant */
+		pwr = MCI_PWR_UP;
+		if (host->plat->cfg_mpm_sdiowakeup)
+			host->plat->cfg_mpm_sdiowakeup(
+				mmc_dev(mmc), SDC_DAT1_ENABLE);
+
+		msmsdcc_set_vddp_high_vol(host);
+		msmsdcc_setup_pins(host, true);
+		break;
+	case MMC_POWER_ON:
+		pwr = MCI_PWR_ON;
+		break;
+	}
+
+out:
+	return pwr;
+}
+
 static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
 {
 	unsigned int wakeup_irq;
@@ -2179,6 +2451,90 @@
 }
 
 static void
+msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
+{
+	struct mmc_host *mmc = host->mmc;
+
+	/*
+	 * SDIO_AL clients has different mechanism of handling LPM through
+	 * sdio_al driver itself. The sdio wakeup interrupt is configured as
+	 * part of that. Here, we are interested only in clients like WLAN.
+	 */
+	if (!(mmc->card && mmc_card_sdio(mmc->card))
+			|| host->plat->is_sdio_al_client)
+		goto out;
+
+	if (!host->sdcc_suspended) {
+		/*
+		 * When MSM is not in power collapse and we
+		 * are disabling clocks, enable bit 22 in MASK0
+		 * to handle asynchronous SDIO interrupts.
+		 */
+		if (enable_wakeup_irq) {
+			writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
+			mb();
+		} else {
+			writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
+			msmsdcc_sync_reg_wr(host);
+		}
+		goto out;
+	} else if (!mmc_card_wake_sdio_irq(mmc)) {
+		/*
+		 * Wakeup MSM only if SDIO function drivers set
+		 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
+		 */
+		goto out;
+	}
+
+	if (enable_wakeup_irq) {
+		if (!host->plat->sdiowakeup_irq) {
+			/*
+			 * When there is no gpio line that can be configured
+			 * as wakeup interrupt handle it by configuring
+			 * asynchronous sdio interrupts and DAT1 line.
+			 */
+			writel_relaxed(MCI_SDIOINTMASK,
+					host->base + MMCIMASK0);
+			mb();
+			if (host->plat->cfg_mpm_sdiowakeup)
+				host->plat->cfg_mpm_sdiowakeup(
+					mmc_dev(mmc), SDC_DAT1_ENWAKE);
+			/* configure sdcc core interrupt as wakeup interrupt */
+			msmsdcc_enable_irq_wake(host);
+		} else {
+			/* Let gpio line handle wakeup interrupt */
+			writel_relaxed(0, host->base + MMCIMASK0);
+			mb();
+			if (host->sdio_wakeupirq_disabled) {
+				host->sdio_wakeupirq_disabled = 0;
+				/* configure gpio line as wakeup interrupt */
+				msmsdcc_enable_irq_wake(host);
+				enable_irq(host->plat->sdiowakeup_irq);
+			}
+		}
+	} else {
+		if (!host->plat->sdiowakeup_irq) {
+			/*
+			 * We may not have cleared bit 22 in the interrupt
+			 * handler as the clocks might be off at that time.
+			 */
+			writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
+			msmsdcc_sync_reg_wr(host);
+			if (host->plat->cfg_mpm_sdiowakeup)
+				host->plat->cfg_mpm_sdiowakeup(
+					mmc_dev(mmc), SDC_DAT1_DISWAKE);
+			msmsdcc_disable_irq_wake(host);
+		} else if (!host->sdio_wakeupirq_disabled) {
+			disable_irq_nosync(host->plat->sdiowakeup_irq);
+			msmsdcc_disable_irq_wake(host);
+			host->sdio_wakeupirq_disabled = 1;
+		}
+	}
+out:
+	return;
+}
+
+static void
 msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct msmsdcc_host *host = mmc_priv(mmc);
@@ -2189,33 +2545,35 @@
 
 	DBG(host, "ios->clock = %u\n", ios->clock);
 
-	if (ios->clock) {
+	/*
+	 * Disable SDCC core interrupt until set_ios is completed.
+	 * This avoids any race conditions with interrupt raised
+	 * when turning on/off the clocks. One possible
+	 * scenario is SDIO operational interrupt while the clock
+	 * is turned off.
+	 */
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (!host->sdcc_irq_disabled) {
+		spin_unlock_irqrestore(&host->lock, flags);
+		disable_irq(host->core_irqres->start);
 		spin_lock_irqsave(&host->lock, flags);
+		host->sdcc_irq_disabled = 1;
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	pwr = msmsdcc_setup_pwr(host, ios);
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (ios->clock) {
 		if (!host->clks_on) {
 			msmsdcc_setup_clocks(host, true);
 			host->clks_on = 1;
-			if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
-				if (!host->plat->sdiowakeup_irq) {
-					writel_relaxed(host->mci_irqenable,
-							host->base + MMCIMASK0);
-					mb();
-					if (host->plat->cfg_mpm_sdiowakeup &&
-					(mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
-						host->plat->cfg_mpm_sdiowakeup(
-						mmc_dev(mmc), SDC_DAT1_DISWAKE);
-					msmsdcc_disable_irq_wake(host);
-				} else if (!(mmc->pm_flags &
-							MMC_PM_WAKE_SDIO_IRQ)) {
-					writel_relaxed(host->mci_irqenable,
-							host->base + MMCIMASK0);
-				}
-			} else {
-				writel_relaxed(host->mci_irqenable,
-						host->base + MMCIMASK0);
-				mb();
-			}
+			writel_relaxed(host->mci_irqenable,
+					host->base + MMCIMASK0);
+			mb();
+			msmsdcc_cfg_sdio_wakeup(host, false);
 		}
-		spin_unlock_irqrestore(&host->lock, flags);
 
 		clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
 		/*
@@ -2254,6 +2612,7 @@
 		 * give atleast 2 MCLK cycles delay for clocks
 		 * and SDCC core to stabilize
 		 */
+		mb();
 		msmsdcc_delay(host);
 		clk |= MCI_CLK_ENABLE;
 	}
@@ -2275,7 +2634,8 @@
 	 * Select the controller timing mode according
 	 * to current bus speed mode
 	 */
-	if (ios->timing == MMC_TIMING_UHS_SDR104) {
+	if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
+		(ios->timing == MMC_TIMING_MMC_HS200)) {
 		clk |= (4 << 14);
 		host->tuning_needed = 1;
 	} else if (ios->timing == MMC_TIMING_UHS_DDR50) {
@@ -2294,97 +2654,34 @@
 	if (host->io_pad_pwr_switch)
 		clk |= IO_PAD_PWR_SWITCH;
 
-	if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
-		pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
-	else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
-		pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
-
-	switch (ios->power_mode) {
-	case MMC_POWER_OFF:
-		htc_pwrsink_set(PWRSINK_SDCARD, 0);
-		if (!host->sdcc_irq_disabled) {
-			if (host->plat->cfg_mpm_sdiowakeup)
-				host->plat->cfg_mpm_sdiowakeup(
-					mmc_dev(mmc), SDC_DAT1_DISABLE);
-			disable_irq(host->core_irqres->start);
-			host->sdcc_irq_disabled = 1;
+	/* Don't write into registers if clocks are disabled */
+	if (host->clks_on) {
+		if (readl_relaxed(host->base + MMCICLOCK) != clk) {
+			writel_relaxed(clk, host->base + MMCICLOCK);
+			msmsdcc_sync_reg_wr(host);
 		}
-		/*
-		 * As VDD pad rail is always on, set low voltage for VDD
-		 * pad rail when slot is unused (when card is not present
-		 * or during system suspend).
-		 */
-		msmsdcc_set_vddp_low_vol(host);
-		msmsdcc_setup_pins(host, false);
-		break;
-	case MMC_POWER_UP:
-		/* writing PWR_UP bit is redundant */
-		pwr |= MCI_PWR_UP;
-		if (host->sdcc_irq_disabled) {
-			if (host->plat->cfg_mpm_sdiowakeup)
-				host->plat->cfg_mpm_sdiowakeup(
-					mmc_dev(mmc), SDC_DAT1_ENABLE);
-			enable_irq(host->core_irqres->start);
-			host->sdcc_irq_disabled = 0;
+		if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
+			host->pwr = pwr;
+			writel_relaxed(pwr, host->base + MMCIPOWER);
+			msmsdcc_sync_reg_wr(host);
 		}
-		msmsdcc_set_vddp_high_vol(host);
-		msmsdcc_setup_pins(host, true);
-		break;
-	case MMC_POWER_ON:
-		htc_pwrsink_set(PWRSINK_SDCARD, 100);
-		pwr |= MCI_PWR_ON;
-		break;
-	}
-
-	spin_lock_irqsave(&host->lock, flags);
-	if (!host->clks_on) {
-		/* force the clocks to be on */
-		msmsdcc_setup_clocks(host, true);
-		/*
-		 * give atleast 2 MCLK cycles delay for clocks
-		 * and SDCC core to stabilize
-		 */
-		msmsdcc_delay(host);
-	}
-	writel_relaxed(clk, host->base + MMCICLOCK);
-	msmsdcc_delay(host);
-
-	if (host->pwr != pwr) {
-		host->pwr = pwr;
-		writel_relaxed(pwr, host->base + MMCIPOWER);
-		msmsdcc_delay(host);
-	}
-	if (!host->clks_on) {
-		/* force the clocks to be off */
-		msmsdcc_setup_clocks(host, false);
 	}
 
 	if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
-		if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
-			if (!host->plat->sdiowakeup_irq) {
-				writel_relaxed(MCI_SDIOINTMASK,
-						host->base + MMCIMASK0);
-				mb();
-				if (host->plat->cfg_mpm_sdiowakeup &&
-					(mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
-					host->plat->cfg_mpm_sdiowakeup(
-						mmc_dev(mmc), SDC_DAT1_ENWAKE);
-				msmsdcc_enable_irq_wake(host);
-			} else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
-				writel_relaxed(0, host->base + MMCIMASK0);
-			} else {
-				writel_relaxed(MCI_SDIOINTMASK,
-						host->base + MMCIMASK0);
-			}
-			mb();
-		}
+		msmsdcc_cfg_sdio_wakeup(host, true);
 		msmsdcc_setup_clocks(host, false);
 		host->clks_on = 0;
 	}
 
-	if (host->cmd19_tuning_in_progress)
+	if (host->tuning_in_progress)
 		WARN(!host->clks_on,
-			"cmd19_tuning_in_progress but SDCC clocks are OFF\n");
+			"tuning_in_progress but SDCC clocks are OFF\n");
+
+	/* Let interrupts be disabled if the host is powered off */
+	if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
+		enable_irq(host->core_irqres->start);
+		host->sdcc_irq_disabled = 0;
+	}
 
 	spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -2401,7 +2698,7 @@
 	else
 		clk &= ~MCI_CLK_PWRSAVE;
 	writel_relaxed(clk, host->base + MMCICLOCK);
-	msmsdcc_delay(host);
+	msmsdcc_sync_reg_wr(host);
 
 	return 0;
 }
@@ -2450,18 +2747,29 @@
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	unsigned long flags;
 
+	/*
+	 * We may come here with clocks turned off in that case don't
+	 * attempt to write into MASK0 register. While turning on the
+	 * clocks mci_irqenable will be written to MASK0 register.
+	 */
+
 	if (enable) {
 		spin_lock_irqsave(&host->lock, flags);
 		host->mci_irqenable |= MCI_SDIOINTOPERMASK;
-		writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
+		if (host->clks_on) {
+			writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
 				MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
+			mb();
+		}
 		spin_unlock_irqrestore(&host->lock, flags);
 	} else {
 		host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
-		writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
+		if (host->clks_on) {
+			writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
 				~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
+			mb();
+		}
 	}
-	mb();
 }
 #endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
 
@@ -2570,6 +2878,16 @@
 	host->io_pad_pwr_switch = 0;
 	spin_unlock_irqrestore(&host->lock, flags);
 
+	/*
+	 * For eMMC cards, VccQ voltage range must be changed
+	 * only if it operates in HS200 SDR 1.2V mode or in
+	 * DDR 1.2V mode.
+	 */
+	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
+		rc = msmsdcc_set_vccq_vol(host, 1200000);
+		goto out;
+	 }
+
 	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
 		/* Change voltage level of VDDPX to high voltage */
 		rc = msmsdcc_set_vddp_high_vol(host);
@@ -2600,7 +2918,7 @@
 	/* Stop SD CLK output. */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
 			MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
-	msmsdcc_delay(host);
+	msmsdcc_sync_reg_wr(host);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	/*
@@ -2614,7 +2932,7 @@
 	spin_lock_irqsave(&host->lock, flags);
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
 			IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
-	msmsdcc_delay(host);
+	msmsdcc_sync_reg_wr(host);
 	host->io_pad_pwr_switch = 1;
 	spin_unlock_irqrestore(&host->lock, flags);
 
@@ -2625,7 +2943,7 @@
 	/* Disable PWRSAVE would make sure that SD CLK is always running */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
 			& ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
-	msmsdcc_delay(host);
+	msmsdcc_sync_reg_wr(host);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	/*
@@ -2649,6 +2967,7 @@
 	/* Enable PWRSAVE */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
 			MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	msmsdcc_sync_reg_wr(host);
 	spin_unlock_irqrestore(&host->lock, flags);
 out:
 	return rc;
@@ -2697,6 +3016,7 @@
 	 */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
 			& ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	msmsdcc_sync_reg_wr(host);
 
 	/* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
 	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
@@ -2742,6 +3062,7 @@
 	/* re-enable PWRSAVE */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
 			MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	msmsdcc_sync_reg_wr(host);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	return rc;
@@ -2877,15 +3198,23 @@
  * 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} };
-	u8 phases_per_row[16] = {0};
+	#define MAX_PHASES 16
+	int ret;
+	u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
+	u8 phases_per_row[MAX_PHASES] = {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 || (total_phases > MAX_PHASES)) {
+		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;
@@ -2900,6 +3229,9 @@
 		}
 	}
 
+	if (row_index >= MAX_PHASES)
+		return -EINVAL;
+
 	/* Check if phase-0 is present in first valid window? */
 	if (!ranges[0][0]) {
 		phase_0_found = true;
@@ -2907,7 +3239,7 @@
 		/* Check if cycle exist between 2 valid windows */
 		for (cnt = 1; cnt <= row_index; cnt++) {
 			if (phases_per_row[cnt]) {
-				for (i = 0; i <= phases_per_row[cnt]; i++) {
+				for (i = 0; i < phases_per_row[cnt]; i++) {
 					if (ranges[cnt][i] == 15) {
 						phase_15_found = true;
 						phase_15_raw_index = cnt;
@@ -2925,12 +3257,23 @@
 		/* number of phases in raw where phase 15 is present */
 		u8 phases_15 = phases_per_row[phase_15_raw_index];
 
-		cnt = 0;
-		for (i = phases_15; i < (phases_15 + phases_0); i++) {
+		if (phases_0 + phases_15 >= MAX_PHASES)
+			/*
+			 * If there are more than 1 phase windows then total
+			 * number of phases in both the windows should not be
+			 * more than or equal to MAX_PHASES.
+			 */
+			return -EINVAL;
+
+		/* Merge 2 cyclic windows */
+		i = phases_15;
+		for (cnt = 0; cnt < phases_0; cnt++) {
 			ranges[phase_15_raw_index][i] =
 				ranges[phase_0_raw_index][cnt];
-			cnt++;
+			if (++i >= MAX_PHASES)
+				break;
 		}
+
 		phases_per_row[phase_0_raw_index] = 0;
 		phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
 	}
@@ -2942,18 +3285,29 @@
 		}
 	}
 
-	i = ((curr_max * 3) / 4) - 1;
-	ret = ranges[selected_row_index][i];
+	i = ((curr_max * 3) / 4);
+	if (i)
+		i--;
+
+	ret = (int)ranges[selected_row_index][i];
+
+	if (ret >= MAX_PHASES) {
+		ret = -EINVAL;
+		pr_err("%s: %s: invalid phase selected=%d\n",
+			mmc_hostname(host->mmc), __func__, ret);
+	}
 
 	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);
 	unsigned long	flags;
 	u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+	const u32 *tuning_block_pattern = tuning_block_64;
+	int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
 
 	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
 
@@ -2968,8 +3322,12 @@
 	WARN(!host->clks_on, "SDCC clocks are turned off\n");
 	WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
 
-	host->cmd19_tuning_in_progress = 1;
-	msmsdcc_delay(host);
+	host->tuning_in_progress = 1;
+	if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+		(mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
+		tuning_block_pattern = tuning_block_128;
+		size = sizeof(tuning_block_128);
+	}
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	/* first of all reset the tuning block */
@@ -2977,7 +3335,7 @@
 	if (rc)
 		goto out;
 
-	data_buf = kmalloc(64, GFP_KERNEL);
+	data_buf = kmalloc(size, GFP_KERNEL);
 	if (!data_buf) {
 		rc = -ENOMEM;
 		goto out;
@@ -2998,23 +3356,23 @@
 		if (rc)
 			goto kfree;
 
-		cmd.opcode = MMC_SEND_TUNING_BLOCK;
+		cmd.opcode = opcode;
 		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
 
-		data.blksz = 64;
+		data.blksz = size;
 		data.blocks = 1;
 		data.flags = MMC_DATA_READ;
 		data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
 
 		data.sg = &sg;
 		data.sg_len = 1;
-		sg_init_one(&sg, data_buf, 64);
-		memset(data_buf, 0, 64);
+		sg_init_one(&sg, data_buf, size);
+		memset(data_buf, 0, size);
 		mmc_wait_for_req(mmc, &mrq);
 
 		if (!cmd.error && !data.error &&
-			!memcmp(data_buf, cmd19_tuning_block, 64)) {
-			/* tuning is successful with this tuning point */
+			!memcmp(data_buf, tuning_block_pattern, size)) {
+			/* tuning is successful at this tuning point */
 			tuned_phases[tuned_phase_cnt++] = phase;
 			pr_debug("%s: %s: found good phase = %d\n",
 				mmc_hostname(mmc), __func__, phase);
@@ -3022,8 +3380,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.
@@ -3045,8 +3408,7 @@
 	kfree(data_buf);
 out:
 	spin_lock_irqsave(&host->lock, flags);
-	msmsdcc_delay(host);
-	host->cmd19_tuning_in_progress = 0;
+	host->tuning_in_progress = 0;
 	spin_unlock_irqrestore(&host->lock, flags);
 exit:
 	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
@@ -3145,13 +3507,13 @@
 
 	pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
 	spin_lock(&host->lock);
-	if (!host->sdio_irq_disabled) {
+	if (!host->sdio_wakeupirq_disabled) {
 		disable_irq_nosync(irq);
-		if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
+		if (host->sdcc_suspended) {
 			wake_lock(&host->sdio_wlock);
 			msmsdcc_disable_irq_wake(host);
 		}
-		host->sdio_irq_disabled = 1;
+		host->sdio_wakeupirq_disabled = 1;
 	}
 	if (host->plat->is_sdio_al_client) {
 		if (!host->clks_on) {
@@ -3768,6 +4130,7 @@
 			}
 		} else {
 			host->prog_enable = 0;
+			host->curr.wait_for_auto_prog_done = 0;
 			msmsdcc_reset_and_restore(host);
 			msmsdcc_request_end(host, mrq);
 		}
@@ -4156,7 +4519,7 @@
 	mmc->caps |= plat->mmc_bus_width;
 
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
-	mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
+	mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
 
 	/*
 	 * If we send the CMD23 before multi block write/read command
@@ -4178,6 +4541,13 @@
 		mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
 				MMC_CAP_SET_XPC_180);
 
+	mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
+	if (pdev->dev.of_node) {
+		if (of_get_property((&pdev->dev)->of_node,
+					"qcom,sdcc-hs200", NULL))
+			mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+	}
+
 	if (plat->nonremovable)
 		mmc->caps |= MMC_CAP_NONREMOVABLE;
 #ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
@@ -4196,6 +4566,7 @@
 
 	writel_relaxed(0, host->base + MMCIMASK0);
 	writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
+	msmsdcc_sync_reg_wr(host);
 
 	writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
 	mb();
@@ -4235,9 +4606,9 @@
 			goto pio_irq_free;
 		} else {
 			spin_lock_irqsave(&host->lock, flags);
-			if (!host->sdio_irq_disabled) {
+			if (!host->sdio_wakeupirq_disabled) {
 				disable_irq_nosync(plat->sdiowakeup_irq);
-				host->sdio_irq_disabled = 1;
+				host->sdio_wakeupirq_disabled = 1;
 			}
 			spin_unlock_irqrestore(&host->lock, flags);
 		}
@@ -4505,6 +4876,14 @@
 	return 0;
 }
 
+static void msmsdcc_shutdown(struct platform_device *pdev)
+{
+	struct mmc_host *mmc = mmc_get_drvdata(pdev);
+
+	mmc_remove_host(mmc);
+	mmc_free_host(mmc);
+}
+
 #ifdef CONFIG_MSM_SDIO_AL
 int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
 {
@@ -4535,15 +4914,15 @@
 			host->sdio_gpio_lpm = 1;
 		}
 
-		if (host->sdio_irq_disabled) {
+		if (host->sdio_wakeupirq_disabled) {
 			msmsdcc_enable_irq_wake(host);
 			enable_irq(host->plat->sdiowakeup_irq);
-			host->sdio_irq_disabled = 0;
+			host->sdio_wakeupirq_disabled = 0;
 		}
 	} else {
-		if (!host->sdio_irq_disabled) {
+		if (!host->sdio_wakeupirq_disabled) {
 			disable_irq_nosync(host->plat->sdiowakeup_irq);
-			host->sdio_irq_disabled = 1;
+			host->sdio_wakeupirq_disabled = 1;
 			msmsdcc_disable_irq_wake(host);
 		}
 
@@ -4585,6 +4964,8 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	int rc = 0;
+	unsigned long flags;
+
 
 	if (host->plat->is_sdio_al_client)
 		return 0;
@@ -4594,20 +4975,6 @@
 		mmc->suspend_task = current;
 
 		/*
-		 * If the clocks are already turned off by SDIO clients (as
-		 * part of LPM), then clocks should be turned on before
-		 * calling mmc_suspend_host() because mmc_suspend_host might
-		 * send some commands to the card. The clocks will be turned
-		 * off again after mmc_suspend_host. Thus for SDIO
-		 * cards, clocks will be turned on before mmc_suspend_host
-		 * and turned off after mmc_suspend_host.
-		 */
-		if (mmc->card && mmc_card_sdio(mmc->card)) {
-			mmc->ios.clock = host->clk_rate;
-			mmc->ops->set_ios(host->mmc, &host->mmc->ios);
-		}
-
-		/*
 		 * MMC core thinks that host is disabled by now since
 		 * runtime suspend is scheduled after msmsdcc_disable()
 		 * is called. Thus, MMC core will try to enable the host
@@ -4630,26 +4997,24 @@
 		pm_runtime_put_noidle(dev);
 
 		if (!rc) {
-			if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
-				(mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
-				disable_irq(host->core_irqres->start);
-				host->sdcc_irq_disabled = 1;
-
+			spin_lock_irqsave(&host->lock, flags);
+			host->sdcc_suspended = true;
+			spin_unlock_irqrestore(&host->lock, flags);
+			if (mmc->card && mmc_card_sdio(mmc->card) &&
+				mmc->ios.clock) {
 				/*
-				 * If MMC core level suspend is not supported,
-				 * turn off clocks to allow deep sleep (TCXO
-				 * shutdown).
+				 * If SDIO function driver doesn't want
+				 * to power off the card, atleast turn off
+				 * clocks to allow deep sleep (TCXO shutdown).
 				 */
+				mmc_host_clk_hold(mmc);
+				spin_lock_irqsave(&mmc->clk_lock, flags);
+				mmc->clk_old = mmc->ios.clock;
 				mmc->ios.clock = 0;
-				mmc->ops->set_ios(host->mmc, &host->mmc->ios);
-				enable_irq(host->core_irqres->start);
-				host->sdcc_irq_disabled = 0;
-
-				if (host->plat->sdiowakeup_irq) {
-					host->sdio_irq_disabled = 0;
-					msmsdcc_enable_irq_wake(host);
-					enable_irq(host->plat->sdiowakeup_irq);
-				}
+				mmc->clk_gated = true;
+				spin_unlock_irqrestore(&mmc->clk_lock, flags);
+				mmc_set_ios(mmc);
+				mmc_host_clk_release(mmc);
 			}
 		}
 		host->sdcc_suspending = 0;
@@ -4673,30 +5038,12 @@
 
 	pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
 	if (mmc) {
-		if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
-			if (host->sdcc_irq_disabled) {
-				enable_irq(host->core_irqres->start);
-				host->sdcc_irq_disabled = 0;
-			}
+		if (mmc->card && mmc_card_sdio(mmc->card) &&
+				mmc_card_keep_power(mmc)) {
+			mmc_host_clk_hold(mmc);
 			mmc->ios.clock = host->clk_rate;
-			mmc->ops->set_ios(host->mmc, &host->mmc->ios);
-
-			spin_lock_irqsave(&host->lock, flags);
-			writel_relaxed(host->mci_irqenable,
-					host->base + MMCIMASK0);
-			mb();
-
-			if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
-					!host->sdio_irq_disabled) {
-				if (host->plat->sdiowakeup_irq) {
-					disable_irq_nosync(
-						host->plat->sdiowakeup_irq);
-					msmsdcc_disable_irq_wake(host);
-					host->sdio_irq_disabled = 1;
-				}
-			}
-
-			spin_unlock_irqrestore(&host->lock, flags);
+			mmc_set_ios(mmc);
+			mmc_host_clk_release(mmc);
 		}
 
 		mmc_resume_host(mmc);
@@ -4707,13 +5054,14 @@
 		 */
 		spin_lock_irqsave(&host->lock, flags);
 		mmc->pm_flags = 0;
+		host->sdcc_suspended = false;
 		spin_unlock_irqrestore(&host->lock, flags);
 
 		/*
 		 * After resuming the host wait for sometime so that
 		 * the SDIO work will be processed.
 		 */
-		if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
+		if (mmc->card && mmc_card_sdio(mmc->card)) {
 			if ((host->plat->cfg_mpm_sdiowakeup ||
 					host->plat->sdiowakeup_irq) &&
 					wake_lock_active(&host->sdio_wlock))
@@ -4753,8 +5101,47 @@
 	if (host->plat->status_irq)
 		disable_irq(host->plat->status_irq);
 
-	if (!pm_runtime_suspended(dev))
-		rc = msmsdcc_runtime_suspend(dev);
+	if (!pm_runtime_suspended(dev)) {
+		if (!(mmc->card && mmc_card_sdio(mmc->card))) {
+			/*
+			 * decrement power.usage_counter if it's
+			 * not zero earlier
+			 */
+			pm_runtime_put_noidle(dev);
+			rc = pm_runtime_suspend(dev);
+		}
+
+		/*
+		 * if device runtime PM status is still not suspended
+		 * then perform suspend here.
+		 */
+		if (!pm_runtime_suspended(dev))
+			rc = msmsdcc_runtime_suspend(dev);
+	}
+
+	return rc;
+}
+
+static int msmsdcc_suspend_noirq(struct device *dev)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	int rc = 0;
+
+	/*
+	 * After platform suspend there may be active request
+	 * which might have enabled clocks. For example, in SDIO
+	 * case, ksdioirq thread might have scheduled after sdcc
+	 * suspend but before system freeze. In that case abort
+	 * suspend and retry instead of keeping the clocks on
+	 * during suspend and not allowing TCXO.
+	 */
+
+	if (host->clks_on) {
+		pr_warn("%s: clocks are on after suspend, aborting system "
+				"suspend\n", mmc_hostname(mmc));
+		rc = -EAGAIN;
+	}
 
 	return rc;
 }
@@ -4784,6 +5171,7 @@
 #define msmsdcc_runtime_idle NULL
 #define msmsdcc_pm_suspend NULL
 #define msmsdcc_pm_resume NULL
+#define msmsdcc_suspend_noirq NULL
 #endif
 
 static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
@@ -4792,6 +5180,7 @@
 	.runtime_idle    = msmsdcc_runtime_idle,
 	.suspend 	 = msmsdcc_pm_suspend,
 	.resume		 = msmsdcc_pm_resume,
+	.suspend_noirq	 = msmsdcc_suspend_noirq,
 };
 
 static const struct of_device_id msmsdcc_dt_match[] = {
@@ -4803,6 +5192,7 @@
 static struct platform_driver msmsdcc_driver = {
 	.probe		= msmsdcc_probe,
 	.remove		= msmsdcc_remove,
+	.shutdown	= msmsdcc_shutdown,
 	.driver		= {
 		.name	= "msm_sdcc",
 		.pm	= &msmsdcc_dev_pm_ops,
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 319d721..832e437 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -2,7 +2,7 @@
  *  linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller
  *
  *  Copyright (C) 2008 Google, All Rights Reserved.
- *  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 as
@@ -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;
@@ -383,21 +384,21 @@
 	unsigned int	dummy_52_needed;
 	unsigned int	dummy_52_sent;
 
-	unsigned int	sdio_irq_disabled;
 	bool		is_resumed;
 	struct wake_lock	sdio_wlock;
 	struct wake_lock	sdio_suspend_wlock;
-	unsigned int    sdcc_suspending;
-
-	unsigned int sdcc_irq_disabled;
 	struct timer_list req_tout_timer;
 	unsigned long reg_write_delay;
 	bool io_pad_pwr_switch;
-	bool cmd19_tuning_in_progress;
+	bool tuning_in_progress;
 	bool tuning_needed;
 	bool sdio_gpio_lpm;
 	bool irq_wake_enabled;
 	struct pm_qos_request_list pm_qos_req_dma;
+	bool sdcc_suspending;
+	bool sdcc_irq_disabled;
+	bool sdcc_suspended;
+	bool sdio_wakeupirq_disabled;
 };
 
 int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index cc20e02..e12fbc5 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -731,6 +731,7 @@
 				"failed to config DMA channel. Falling back to PIO\n");
 			dma_release_channel(host->dma);
 			host->do_dma = 0;
+			host->dma = NULL;
 		}
 	}
 
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index d513d47..99b449d 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -37,6 +37,7 @@
 #include <linux/mmc/sdio.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/module.h>
 
 #include <mach/mxs.h>
 #include <mach/common.h>
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index ba40d6d..6be0a24 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -15,6 +15,7 @@
 
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 68ddb75..aaea044 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -20,6 +20,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 936bbca..0f008b3 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -14,6 +14,7 @@
 
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
@@ -239,6 +240,8 @@
 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
 	}
 
+	slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
+
 	return 0;
 }
 
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 60a4c97..a152b5c 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 343c97e..bb1ae46 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
+#include <linux/module.h>
 
 #include <mach/gpio.h>
 #include <mach/sdhci.h>
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aad27c8..6ebbdc0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/highmem.h>
 #include <linux/io.h>
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
@@ -1340,8 +1341,7 @@
 		if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
-		    (ios->timing == MMC_TIMING_UHS_SDR25) ||
-		    (ios->timing == MMC_TIMING_UHS_SDR12))
+		    (ios->timing == MMC_TIMING_UHS_SDR25))
 			ctrl |= SDHCI_CTRL_HISPD;
 
 		ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@@ -2227,9 +2227,8 @@
 	/* Disable tuning since we are suspending */
 	if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
 	    host->tuning_mode == SDHCI_TUNING_MODE_1) {
+		del_timer_sync(&host->tuning_timer);
 		host->flags &= ~SDHCI_NEEDS_RETUNING;
-		mod_timer(&host->tuning_timer, jiffies +
-			host->tuning_count * HZ);
 	}
 
 	ret = mmc_suspend_host(host->mmc);
@@ -2558,6 +2557,15 @@
 	if (caps[1] & SDHCI_DRIVER_TYPE_D)
 		mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
 
+	/*
+	 * If Power Off Notify capability is enabled by the host,
+	 * set notify to short power off notify timeout value.
+	 */
+	if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
+	else
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
+
 	/* Initial value for re-tuning timer count */
 	host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
 			      SDHCI_RETUNING_TIMER_COUNT_SHIFT;
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index 496b7ef..7009f17 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -26,6 +26,7 @@
 */
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/scatterlist.h>
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 14f8edb..51b68cc 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -31,6 +31,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/spinlock.h>
+#include <linux/module.h>
 
 #define DRIVER_NAME	"sh_mmcif"
 #define DRIVER_VERSION	"2010-04-28"
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index ce500f0..f5ce77b 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 457c26e..90c6b1b 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -16,6 +16,7 @@
 #include <linux/mmc/host.h>
 #include <linux/highmem.h>
 #include <linux/scatterlist.h>
+#include <linux/module.h>
 #include <asm/io.h>
 
 #define DRIVER_NAME "tifm_sd"
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 4dfe2c0..faf3594 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/highmem.h>
 #include <linux/delay.h>
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index d4455ff..52f4b64 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -259,7 +259,7 @@
 static int firmware_rom_wait_states = 0x1C;
 #endif
 
-module_param(firmware_rom_wait_states, bool, 0644);
+module_param(firmware_rom_wait_states, int, 0644);
 MODULE_PARM_DESC(firmware_rom_wait_states,
 		 "ROM wait states byte=RRRIIEEE (Reserved Internal External)");
 
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/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 25f66e4..ce2b09b 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -215,7 +215,7 @@
 
 	mutex_lock(&dev->lock);
 
-	if (dev->open++)
+	if (dev->open)
 		goto unlock;
 
 	kref_get(&dev->ref);
@@ -235,6 +235,7 @@
 		goto error_release;
 
 unlock:
+	dev->open++;
 	mutex_unlock(&dev->lock);
 	blktrans_dev_put(dev);
 	return ret;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index ed9468c..0811d00 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -321,6 +321,7 @@
 			ops.mode = MTD_OOB_RAW;
 			ops.datbuf = kbuf;
 			ops.oobbuf = NULL;
+			ops.ooboffs = 0;
 			ops.len = len;
 
 			ret = mtd->write_oob(mtd, *ppos, &ops);
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index e3e40f4..43130e8 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -253,6 +253,9 @@
 	size_t retlen;
 
 	for (page = 0; page < cxt->oops_pages; page++) {
+		if (mtd->block_isbad &&
+		    mtd->block_isbad(mtd, page * record_size))
+			continue;
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
 		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
@@ -369,7 +372,7 @@
 
 	/* oops_page_used is a bit field */
 	cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages,
-			BITS_PER_LONG));
+			BITS_PER_LONG) * sizeof(unsigned long));
 	if (!cxt->oops_page_used) {
 		printk(KERN_ERR "mtdoops: could not allocate page array\n");
 		return;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 6516b08..15d7165 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2097,14 +2097,22 @@
 
 /**
  * nand_fill_oob - [Internal] Transfer client buffer to oob
- * @chip:	nand chip structure
+ * @mtd:	MTD device structure
  * @oob:	oob data buffer
  * @len:	oob data write length
  * @ops:	oob ops structure
  */
-static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
-						struct mtd_oob_ops *ops)
+static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
+			      struct mtd_oob_ops *ops)
 {
+	struct nand_chip *chip = mtd->priv;
+
+	/*
+	 * Initialise to all 0xFF, to avoid the possibility of left over OOB
+	 * data from a previous OOB read.
+	 */
+	memset(chip->oob_poi, 0xff, mtd->oobsize);
+
 	switch (ops->mode) {
 
 	case MTD_OOB_PLACE:
@@ -2201,10 +2209,6 @@
 	    (chip->pagebuf << chip->page_shift) < (to + ops->len))
 		chip->pagebuf = -1;
 
-	/* If we're not given explicit OOB data, let it be 0xFF */
-	if (likely(!oob))
-		memset(chip->oob_poi, 0xff, mtd->oobsize);
-
 	/* Don't allow multipage oob writes with offset */
 	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
 		return -EINVAL;
@@ -2226,8 +2230,11 @@
 
 		if (unlikely(oob)) {
 			size_t len = min(oobwritelen, oobmaxlen);
-			oob = nand_fill_oob(chip, oob, len, ops);
+			oob = nand_fill_oob(mtd, oob, len, ops);
 			oobwritelen -= len;
+		} else {
+			/* We still need to erase leftover OOB data */
+			memset(chip->oob_poi, 0xff, mtd->oobsize);
 		}
 
 		ret = chip->write_page(mtd, chip, wbuf, page, cached,
@@ -2401,10 +2408,8 @@
 	if (page == chip->pagebuf)
 		chip->pagebuf = -1;
 
-	memset(chip->oob_poi, 0xff, mtd->oobsize);
-	nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
+	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
 	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
-	memset(chip->oob_poi, 0xff, mtd->oobsize);
 
 	if (status)
 		return status;
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 1fb3b3a..30689cc 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -685,6 +685,8 @@
 		 * OOB, ignore such double bit errors
 		 */
 		if (is_buf_blank(buf, mtd->writesize))
+			info->retcode = ERR_NONE;
+		else
 			mtd->ecc_stats.failed++;
 	}
 
@@ -813,7 +815,7 @@
 	info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
 	/* set info fields needed to read id */
 	info->read_id_bytes = (info->page_size == 2048) ? 4 : 2;
-	info->reg_ndcr = ndcr;
+	info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
 	info->cmdset = &default_cmdset;
 
 	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
@@ -882,7 +884,7 @@
 	struct pxa3xx_nand_info *info = mtd->priv;
 	struct platform_device *pdev = info->pdev;
 	struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
-	struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} };
+	struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
 	const struct pxa3xx_nand_flash *f = NULL;
 	struct nand_chip *chip = mtd->priv;
 	uint32_t id = -1;
@@ -942,8 +944,10 @@
 	pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block;
 	if (f->flash_width == 16)
 		pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16;
+	pxa3xx_flash_ids[1].name = NULL;
+	def = pxa3xx_flash_ids;
 KEEP_CONFIG:
-	if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids))
+	if (nand_scan_ident(mtd, 1, def))
 		return -ENODEV;
 	/* calculate addressing information */
 	info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1;
@@ -954,9 +958,9 @@
 		info->row_addr_cycles = 2;
 	mtd->name = mtd_names[0];
 	chip->ecc.mode = NAND_ECC_HW;
-	chip->ecc.size = f->page_size;
+	chip->ecc.size = info->page_size;
 
-	chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0;
+	chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0;
 	chip->options |= NAND_NO_AUTOINCR;
 	chip->options |= NAND_NO_READRDY;
 
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index 7a87d07..4938bd0 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -297,6 +297,9 @@
 	.name = "RedBoot",
 };
 
+/* mtd parsers will request the module by parser name */
+MODULE_ALIAS("RedBoot");
+
 static int __init redboot_parser_init(void)
 {
 	return register_mtd_parser(&redboot_parser);
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
index 531625f..129bad2 100644
--- a/drivers/mtd/tests/mtd_stresstest.c
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -277,6 +277,12 @@
 	       (unsigned long long)mtd->size, mtd->erasesize,
 	       pgsize, ebcnt, pgcnt, mtd->oobsize);
 
+	if (ebcnt < 2) {
+		printk(PRINT_PREF "error: need at least 2 eraseblocks\n");
+		err = -ENOSPC;
+		goto out_put_mtd;
+	}
+
 	/* Read or write up 2 eraseblocks at a time */
 	bufsize = mtd->erasesize * 2;
 
@@ -315,6 +321,7 @@
 	kfree(bbt);
 	vfree(writebuf);
 	vfree(readbuf);
+out_put_mtd:
 	put_mtd_device(mtd);
 	if (err)
 		printk(PRINT_PREF "error %d occurred\n", err);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 191f3bb..cdea669 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -628,6 +628,9 @@
 	if (req->alignment != 1 && n)
 		goto bad;
 
+	if (!req->name[0] || !req->name_len)
+		goto bad;
+
 	if (req->name_len > UBI_VOL_NAME_MAX) {
 		err = -ENAMETOOLONG;
 		goto bad;
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 3f1a09c..5f0e4c2 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -51,7 +51,10 @@
 	pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__)
 
 /* Just a debugging messages not related to any specific UBI subsystem */
-#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                    \
+	printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
+	       current->pid, __func__, ##__VA_ARGS__)
+
 /* General debugging messages */
 #define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Messages from the eraseblock association sub-system */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 4be6718..c696c94 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -1028,12 +1028,14 @@
 	 * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
 	 * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
 	 * LEB is already locked, we just do not move it and return
-	 * %MOVE_CANCEL_RACE, which means that UBI will re-try, but later.
+	 * %MOVE_RETRY. Note, we do not return %MOVE_CANCEL_RACE here because
+	 * we do not know the reasons of the contention - it may be just a
+	 * normal I/O on this LEB, so we want to re-try.
 	 */
 	err = leb_write_trylock(ubi, vol_id, lnum);
 	if (err) {
 		dbg_wl("contention on LEB %d:%d, cancel", vol_id, lnum);
-		return MOVE_CANCEL_RACE;
+		return MOVE_RETRY;
 	}
 
 	/*
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index c6c2229..bbfa88d 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -121,6 +121,7 @@
  *                     PEB
  * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the
  *                       target PEB
+ * MOVE_RETRY: retry scrubbing the PEB
  */
 enum {
 	MOVE_CANCEL_RACE = 1,
@@ -128,6 +129,7 @@
 	MOVE_TARGET_RD_ERR,
 	MOVE_TARGET_WR_ERR,
 	MOVE_CANCEL_BITFLIPS,
+	MOVE_RETRY,
 };
 
 /**
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index ff2c495..12e44c9 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -792,7 +792,10 @@
 			protect = 1;
 			goto out_not_moved;
 		}
-
+		if (err == MOVE_RETRY) {
+			scrubbing = 1;
+			goto out_not_moved;
+		}
 		if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
 		    err == MOVE_TARGET_RD_ERR) {
 			/*
@@ -1046,7 +1049,6 @@
 
 	ubi_err("failed to erase PEB %d, error %d", pnum, err);
 	kfree(wl_wrk);
-	kmem_cache_free(ubi_wl_entry_slab, e);
 
 	if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
 	    err == -EBUSY) {
@@ -1059,14 +1061,16 @@
 			goto out_ro;
 		}
 		return err;
-	} else if (err != -EIO) {
+	}
+
+	kmem_cache_free(ubi_wl_entry_slab, e);
+	if (err != -EIO)
 		/*
 		 * If this is not %-EIO, we have no idea what to do. Scheduling
 		 * this physical eraseblock for erasure again would cause
 		 * errors again and again. Well, lets switch to R/O mode.
 		 */
 		goto out_ro;
-	}
 
 	/* It is %-EIO, the PEB went bad */
 
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 2df9276..5e725e0 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -871,16 +871,12 @@
 	}
 }
 
-/* hw is a boolean parameter that determines whether we should try and
- * set the hw address of the device as well as the hw address of the
- * net_device
- */
-static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw)
+static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
 {
 	struct net_device *dev = slave->dev;
 	struct sockaddr s_addr;
 
-	if (!hw) {
+	if (slave->bond->params.mode == BOND_MODE_TLB) {
 		memcpy(dev->dev_addr, addr, dev->addr_len);
 		return 0;
 	}
@@ -910,8 +906,8 @@
 	u8 tmp_mac_addr[ETH_ALEN];
 
 	memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);
-	alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled);
-	alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled);
+	alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr);
+	alb_set_slave_mac_addr(slave2, tmp_mac_addr);
 
 }
 
@@ -1058,8 +1054,7 @@
 
 		/* Try setting slave mac to bond address and fall-through
 		   to code handling that situation below... */
-		alb_set_slave_mac_addr(slave, bond->dev->dev_addr,
-				       bond->alb_info.rlb_enabled);
+		alb_set_slave_mac_addr(slave, bond->dev->dev_addr);
 	}
 
 	/* The slave's address is equal to the address of the bond.
@@ -1095,8 +1090,7 @@
 	}
 
 	if (free_mac_slave) {
-		alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr,
-				       bond->alb_info.rlb_enabled);
+		alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr);
 
 		pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n",
 			   bond->dev->name, slave->dev->name,
@@ -1452,8 +1446,7 @@
 {
 	int res;
 
-	res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr,
-				     bond->alb_info.rlb_enabled);
+	res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr);
 	if (res) {
 		return res;
 	}
@@ -1604,8 +1597,7 @@
 		alb_swap_mac_addr(bond, swap_slave, new_slave);
 	} else {
 		/* set the new_slave to the bond mac address */
-		alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr,
-				       bond->alb_info.rlb_enabled);
+		alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr);
 	}
 
 	if (swap_slave) {
@@ -1665,8 +1657,7 @@
 		alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);
 		alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave);
 	} else {
-		alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr,
-				       bond->alb_info.rlb_enabled);
+		alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr);
 
 		read_lock(&bond->lock);
 		alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 9ea2f21..0b65c5f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1500,6 +1500,8 @@
 	struct sk_buff *skb = *pskb;
 	struct slave *slave;
 	struct bonding *bond;
+	void (*recv_probe)(struct sk_buff *, struct bonding *,
+				struct slave *);
 
 	skb = skb_share_check(skb, GFP_ATOMIC);
 	if (unlikely(!skb))
@@ -1513,11 +1515,12 @@
 	if (bond->params.arp_interval)
 		slave->dev->last_rx = jiffies;
 
-	if (bond->recv_probe) {
+	recv_probe = ACCESS_ONCE(bond->recv_probe);
+	if (recv_probe) {
 		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
 
 		if (likely(nskb)) {
-			bond->recv_probe(nskb, bond, slave);
+			recv_probe(nskb, bond, slave);
 			dev_kfree_skb(nskb);
 		}
 	}
@@ -1902,7 +1905,7 @@
 				 "but new slave device does not support netpoll.\n",
 				 bond_dev->name);
 			res = -EBUSY;
-			goto err_close;
+			goto err_detach;
 		}
 	}
 #endif
@@ -1911,7 +1914,7 @@
 
 	res = bond_create_slave_symlinks(bond_dev, slave_dev);
 	if (res)
-		goto err_close;
+		goto err_detach;
 
 	res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
 					 new_slave);
@@ -1932,6 +1935,11 @@
 err_dest_symlinks:
 	bond_destroy_slave_symlinks(bond_dev, slave_dev);
 
+err_detach:
+	write_lock_bh(&bond->lock);
+	bond_detach_slave(bond, new_slave);
+	write_unlock_bh(&bond->lock);
+
 err_close:
 	dev_close(slave_dev);
 
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 3f2e12c..015b515 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -971,7 +971,7 @@
 	case (NETEVENT_REDIRECT):{
 		struct netevent_redirect *nr = ctx;
 		cxgb_redirect(nr->old, nr->new);
-		cxgb_neigh_update(nr->new->neighbour);
+		cxgb_neigh_update(dst_get_neighbour(nr->new));
 		break;
 	}
 	default:
@@ -1116,8 +1116,8 @@
 	struct l2t_entry *e;
 	struct t3c_tid_entry *te;
 
-	olddev = old->neighbour->dev;
-	newdev = new->neighbour->dev;
+	olddev = dst_get_neighbour(old)->dev;
+	newdev = dst_get_neighbour(new)->dev;
 	if (!is_offloading(olddev))
 		return;
 	if (!is_offloading(newdev)) {
@@ -1134,7 +1134,7 @@
 	}
 
 	/* Add new L2T entry */
-	e = t3_l2t_get(tdev, new->neighbour, newdev);
+	e = t3_l2t_get(tdev, dst_get_neighbour(new), newdev);
 	if (!e) {
 		printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
 		       __func__);
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 2f433fb..51fba5f 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1718,8 +1718,12 @@
 			enic_isr_msix_rq(enic->msix_entry[intr].vector,
 				&enic->napi[i]);
 		}
-		intr = enic_msix_wq_intr(enic, i);
-		enic_isr_msix_wq(enic->msix_entry[intr].vector, enic);
+
+		for (i = 0; i < enic->wq_count; i++) {
+			intr = enic_msix_wq_intr(enic, i);
+			enic_isr_msix_wq(enic->msix_entry[intr].vector, enic);
+		}
+
 		break;
 	case VNIC_DEV_INTR_MODE_MSI:
 		enic_isr_msi(enic->pdev->irq, enic);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 2f3c48d..ab4723d 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -239,7 +239,7 @@
 		dest = macvlan_hash_lookup(port, eth->h_dest);
 		if (dest && dest->mode == MACVLAN_MODE_BRIDGE) {
 			/* send to lowerdev first for its network taps */
-			vlan->forward(vlan->lowerdev, skb);
+			dev_forward_skb(vlan->lowerdev, skb);
 
 			return NET_XMIT_SUCCESS;
 		}
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index dfc8272..4840ab7 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -307,6 +307,11 @@
 		return err;
 	if (enabled < 0 || enabled > 1)
 		return -EINVAL;
+	if (enabled == nt->enabled) {
+		printk(KERN_INFO "netconsole: network logging has already %s\n",
+				nt->enabled ? "started" : "stopped");
+		return -EINVAL;
+	}
 
 	if (enabled) {	/* 1 */
 
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index cb6e0b4..364cd67 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -875,6 +875,7 @@
 	struct dp83640_clock *clock;
 	struct list_head *this, *next;
 	struct dp83640_private *tmp, *dp83640 = phydev->priv;
+	struct sk_buff *skb;
 
 	if (phydev->addr == BROADCAST_ADDR)
 		return;
@@ -882,6 +883,12 @@
 	enable_status_frames(phydev, false);
 	cancel_work_sync(&dp83640->ts_work);
 
+	while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL)
+		kfree_skb(skb);
+
+	while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL)
+		skb_complete_tx_timestamp(skb, NULL);
+
 	clock = dp83640_clock_get(dp83640->clock);
 
 	if (dp83640 == clock->chosen) {
@@ -1060,7 +1067,7 @@
 	struct dp83640_private *dp83640 = phydev->priv;
 
 	if (!dp83640->hwts_tx_en) {
-		kfree_skb(skb);
+		skb_complete_tx_timestamp(skb, NULL);
 		return;
 	}
 	skb_queue_tail(&dp83640->tx_queue, skb);
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 47c8339a..2843c90 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -241,7 +241,7 @@
 
 static struct platform_driver mdio_ofgpio_driver = {
 	.driver = {
-		.name = "mdio-gpio",
+		.name = "mdio-ofgpio",
 		.owner = THIS_MODULE,
 		.of_match_table = mdio_ofgpio_match,
 	},
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
index 1286fe2..4b3a68b 100644
--- a/drivers/net/pptp.c
+++ b/drivers/net/pptp.c
@@ -418,10 +418,8 @@
 	lock_sock(sk);
 
 	opt->src_addr = sp->sa_addr.pptp;
-	if (add_chan(po)) {
-		release_sock(sk);
+	if (add_chan(po))
 		error = -EBUSY;
-	}
 
 	release_sock(sk);
 	return error;
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index ca4694e..1f421d7 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -88,8 +88,8 @@
 #define dev_rionet_capable(dev) \
 	is_rionet_capable(dev->src_ops, dev->dst_ops)
 
-#define RIONET_MAC_MATCH(x)	(*(u32 *)x == 0x00010001)
-#define RIONET_GET_DESTID(x)	(*(u16 *)(x + 4))
+#define RIONET_MAC_MATCH(x)	(!memcmp((x), "\00\01\00\01", 4))
+#define RIONET_GET_DESTID(x)	((*((u8 *)x + 4) << 8) | *((u8 *)x + 5))
 
 static int rionet_rx_clean(struct net_device *ndev)
 {
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 38f6859..bc8c183 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -15278,7 +15278,7 @@
 
 		cancel_work_sync(&tp->reset_task);
 
-		if (!tg3_flag(tp, USE_PHYLIB)) {
+		if (tg3_flag(tp, USE_PHYLIB)) {
 			tg3_phy_fini(tp);
 			tg3_mdio_fini(tp);
 		}
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 5250288..7105577 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -314,12 +314,11 @@
 	skb_pull(skb, 4);
 
 	while (skb->len > 0) {
-		if ((short)(header & 0x0000ffff) !=
-		    ~((short)((header & 0xffff0000) >> 16))) {
+		if ((header & 0x07ff) != ((~header >> 16) & 0x07ff))
 			netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
-		}
+
 		/* get the packet length */
-		size = (u16) (header & 0x0000ffff);
+		size = (u16) (header & 0x000007ff);
 
 		if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
 			u8 alignment = (unsigned long)skb->data & 0x3;
@@ -372,7 +371,7 @@
 
 		skb_pull(skb, (size + 1) & 0xfffe);
 
-		if (skb->len == 0)
+		if (skb->len < sizeof(header))
 			break;
 
 		head = (u8 *) skb->data;
@@ -1561,6 +1560,10 @@
 	// ASIX 88772a
 	USB_DEVICE(0x0db0, 0xa877),
 	.driver_info = (unsigned long) &ax88772_info,
+}, {
+	// Asus USB Ethernet Adapter
+	USB_DEVICE (0x0b95, 0x7e2b),
+	.driver_info = (unsigned long) &ax88772_info,
 },
 	{ },		// END
 };
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index d3b9e95..6a53161 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -229,23 +229,40 @@
 	if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
 
 		if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
-			struct usb_cdc_ncm_ndp_input_size ndp_in_sz;
-			err = usb_control_msg(ctx->udev,
-					usb_sndctrlpipe(ctx->udev, 0),
-					USB_CDC_SET_NTB_INPUT_SIZE,
-					USB_TYPE_CLASS | USB_DIR_OUT
-					 | USB_RECIP_INTERFACE,
-					0, iface_no, &ndp_in_sz, 8, 1000);
-		} else {
-			__le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
-			err = usb_control_msg(ctx->udev,
-					usb_sndctrlpipe(ctx->udev, 0),
-					USB_CDC_SET_NTB_INPUT_SIZE,
-					USB_TYPE_CLASS | USB_DIR_OUT
-					 | USB_RECIP_INTERFACE,
-					0, iface_no, &dwNtbInMaxSize, 4, 1000);
-		}
+			struct usb_cdc_ncm_ndp_input_size *ndp_in_sz;
 
+			ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL);
+			if (!ndp_in_sz) {
+				err = -ENOMEM;
+				goto size_err;
+			}
+
+			err = usb_control_msg(ctx->udev,
+					usb_sndctrlpipe(ctx->udev, 0),
+					USB_CDC_SET_NTB_INPUT_SIZE,
+					USB_TYPE_CLASS | USB_DIR_OUT
+					 | USB_RECIP_INTERFACE,
+					0, iface_no, ndp_in_sz, 8, 1000);
+			kfree(ndp_in_sz);
+		} else {
+			__le32 *dwNtbInMaxSize;
+			dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize),
+					GFP_KERNEL);
+			if (!dwNtbInMaxSize) {
+				err = -ENOMEM;
+				goto size_err;
+			}
+			*dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+
+			err = usb_control_msg(ctx->udev,
+					usb_sndctrlpipe(ctx->udev, 0),
+					USB_CDC_SET_NTB_INPUT_SIZE,
+					USB_TYPE_CLASS | USB_DIR_OUT
+					 | USB_RECIP_INTERFACE,
+					0, iface_no, dwNtbInMaxSize, 4, 1000);
+			kfree(dwNtbInMaxSize);
+		}
+size_err:
 		if (err < 0)
 			pr_debug("Setting NTB Input Size failed\n");
 	}
@@ -326,19 +343,29 @@
 
 	/* set Max Datagram Size (MTU) */
 	if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
-		__le16 max_datagram_size;
+		__le16 *max_datagram_size;
 		u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+		max_datagram_size = kzalloc(sizeof(*max_datagram_size),
+				GFP_KERNEL);
+		if (!max_datagram_size) {
+			err = -ENOMEM;
+			goto max_dgram_err;
+		}
+
 		err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0),
 				USB_CDC_GET_MAX_DATAGRAM_SIZE,
 				USB_TYPE_CLASS | USB_DIR_IN
 				 | USB_RECIP_INTERFACE,
-				0, iface_no, &max_datagram_size,
+				0, iface_no, max_datagram_size,
 				2, 1000);
 		if (err < 0) {
 			pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
 						CDC_NCM_MIN_DATAGRAM_SIZE);
+			kfree(max_datagram_size);
 		} else {
-			ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+			ctx->max_datagram_size =
+				le16_to_cpu(*max_datagram_size);
 			/* Check Eth descriptor value */
 			if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) {
 				if (ctx->max_datagram_size > eth_max_sz)
@@ -361,8 +388,10 @@
 						USB_TYPE_CLASS | USB_DIR_OUT
 						 | USB_RECIP_INTERFACE,
 						0,
-						iface_no, &max_datagram_size,
+						iface_no, max_datagram_size,
 						2, 1000);
+			kfree(max_datagram_size);
+max_dgram_err:
 			if (err < 0)
 				pr_debug("SET_MAX_DATAGRAM_SIZE failed\n");
 		}
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index 81126ff..8f9b7f7 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -59,6 +59,7 @@
 #define USB_PRODUCT_IPHONE_3G   0x1292
 #define USB_PRODUCT_IPHONE_3GS  0x1294
 #define USB_PRODUCT_IPHONE_4	0x1297
+#define USB_PRODUCT_IPHONE_4_VZW 0x129c
 
 #define IPHETH_USBINTF_CLASS    255
 #define IPHETH_USBINTF_SUBCLASS 253
@@ -98,6 +99,10 @@
 		USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4,
 		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
 		IPHETH_USBINTF_PROTO) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(
+		USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
+		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+		IPHETH_USBINTF_PROTO) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, ipheth_table);
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index b693b18..ebd58ab 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.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
@@ -66,7 +66,7 @@
 	return snprintf(buf, PAGE_SIZE, "%u\n", dev->mdm_wait_timeout);
 }
 
-static DEVICE_ATTR(modem_wait, 0666, modem_wait_show, modem_wait_store);
+static DEVICE_ATTR(modem_wait, 0664, modem_wait_show, modem_wait_store);
 
 static int	ctl_msg_dbg_mask;
 module_param_named(dump_ctrl_msg, ctl_msg_dbg_mask, int,
@@ -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 ffdfce1..ae3f934 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)
@@ -461,6 +466,11 @@
 
 	status = rmnet_usb_ctrl_probe(iface, unet->status,
 		(struct rmnet_ctrl_dev *)unet->data[1]);
+	if (status)
+		goto out;
+
+	/* allow modem to wake up suspended system */
+	device_set_wakeup_enable(&udev->dev, 1);
 out:
 	return status;
 }
@@ -472,6 +482,7 @@
 	struct rmnet_ctrl_dev	*dev;
 
 	udev = interface_to_usbdev(intf);
+	device_set_wakeup_enable(&udev->dev, 0);
 
 	unet = usb_get_intfdata(intf);
 	if (!unet) {
@@ -494,12 +505,14 @@
 /*bit position represents interface number*/
 #define PID9034_IFACE_MASK	0xF0
 #define PID9048_IFACE_MASK	0x1E0
+#define PID904C_IFACE_MASK	0x1C0
 
 static const struct driver_info rmnet_info_pid9034 = {
 	.description   = "RmNET net device",
 	.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,
 };
 
@@ -508,9 +521,19 @@
 	.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,
 };
 
+static const struct driver_info rmnet_info_pid904c = {
+	.description   = "RmNET net device",
+	.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,
+};
+
 static const struct usb_device_id vidpids[] = {
 	{
 		USB_DEVICE(0x05c6, 0x9034), /* MDM9x15*/
@@ -520,6 +543,10 @@
 		USB_DEVICE(0x05c6, 0x9048), /* MDM9x15*/
 		.driver_info = (unsigned long)&rmnet_info_pid9048,
 	},
+	{
+		USB_DEVICE(0x05c6, 0x904c), /* MDM9x15*/
+		.driver_info = (unsigned long)&rmnet_info_pid904c,
+	},
 
 	{ }, /* Terminating entry */
 };
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 041fb7d..ef3b236 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -977,7 +977,6 @@
 	usb_set_intfdata(intf, NULL);
 	if (dev) {
 		set_bit(RTL8150_UNPLUG, &dev->flags);
-		tasklet_disable(&dev->tl);
 		tasklet_kill(&dev->tl);
 		unregister_netdev(dev->netdev);
 		unlink_all_urbs(dev);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index c3a756d..d07487b 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;
@@ -369,6 +372,7 @@
 			tasklet_schedule (&dev->bh);
 			break;
 		case 0:
+			usb_mark_last_busy(dev->udev);
 			__skb_queue_tail (&dev->rxq, skb);
 		}
 	} else {
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index bfb6481..4e4e7c3 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -502,9 +502,6 @@
 		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
 				     ATH9K_ANI_CCK_WEAK_SIG_THR);
 
-		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
-				     ATH9K_RX_FILTER_PHYERR);
-
 		ath9k_ani_restart(ah);
 		return;
 	}
@@ -525,8 +522,6 @@
 		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 				     aniState->firstepLevel);
 
-	ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
-			     ~ATH9K_RX_FILTER_PHYERR);
 	ath9k_ani_restart(ah);
 
 	ENABLE_REGWRITE_BUFFER(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index f48051c..7c2aaad 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -643,8 +643,9 @@
 			outlier_idx = max_idx;
 		else
 			outlier_idx = min_idx;
+
+		mp_coeff[outlier_idx] = mp_avg;
 	}
-	mp_coeff[outlier_idx] = mp_avg;
 }
 
 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 1f99249..7880dca 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -255,8 +255,6 @@
 		return -EIO;
 	}
 
-	if (status & AR_TxOpExceeded)
-		ts->ts_status |= ATH9K_TXERR_XTXOP;
 	ts->ts_rateindex = MS(status, AR_FinalTxIdx);
 	ts->ts_seqnum = MS(status, AR_SeqNum);
 	ts->tid = MS(status, AR_TxTid);
@@ -267,6 +265,8 @@
 	ts->ts_status = 0;
 	ts->ts_flags  = 0;
 
+	if (status & AR_TxOpExceeded)
+		ts->ts_status |= ATH9K_TXERR_XTXOP;
 	status = ACCESS_ONCE(ads->status2);
 	ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00);
 	ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index efdbe98..2364b5f 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -570,12 +570,12 @@
 
 #define AR_PHY_TXGAIN_TABLE      (AR_SM_BASE + 0x300)
 
-#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + AR_SREV_9485(ah) ? \
-						 0x3c8 : 0x448)
-#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + AR_SREV_9485(ah) ? \
-						 0x3c4 : 0x440)
-#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + AR_SREV_9485(ah) ? \
-						 0x3f0 : 0x48c)
+#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + (AR_SREV_9485(ah) ? \
+						 0x3c8 : 0x448))
+#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + (AR_SREV_9485(ah) ? \
+						 0x3c4 : 0x440))
+#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + (AR_SREV_9485(ah) ? \
+						 0x3f0 : 0x48c))
 #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i)    (AR_SM_BASE + \
 					     (AR_SREV_9485(ah) ? \
 					      0x3d0 : 0x450) + ((_i) << 2))
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index 611ea6c..d16d029 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -521,7 +521,7 @@
 	{0x000160ac, 0x24611800},
 	{0x000160b0, 0x03284f3e},
 	{0x0001610c, 0x00170000},
-	{0x00016140, 0x10804008},
+	{0x00016140, 0x50804008},
 };
 
 static const u32 ar9485_1_1_mac_postamble[][5] = {
@@ -603,7 +603,7 @@
 
 static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
 	/* Addr        allmodes */
-	{0x00018c00, 0x10052e5e},
+	{0x00018c00, 0x18052e5e},
 	{0x00018c04, 0x000801d8},
 	{0x00018c08, 0x0000080c},
 };
@@ -776,7 +776,7 @@
 
 static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = {
 	/* Addr        allmodes */
-	{0x00018c00, 0x10013e5e},
+	{0x00018c00, 0x18013e5e},
 	{0x00018c04, 0x000801d8},
 	{0x00018c08, 0x0000080c},
 };
@@ -882,7 +882,7 @@
 
 static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
 	/* Addr        allmodes  */
-	{0x00018c00, 0x10012e5e},
+	{0x00018c00, 0x18012e5e},
 	{0x00018c04, 0x000801d8},
 	{0x00018c08, 0x0000080c},
 };
@@ -1021,7 +1021,7 @@
 
 static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = {
 	/* Addr        allmodes */
-	{0x00018c00, 0x10053e5e},
+	{0x00018c00, 0x18053e5e},
 	{0x00018c04, 0x000801d8},
 	{0x00018c08, 0x0000080c},
 };
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 260f1f3..5513c0a 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -37,6 +37,7 @@
 	{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
 	{ USB_DEVICE(0x040D, 0x3801) }, /* VIA */
 	{ USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
+	{ USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
 
 	{ USB_DEVICE(0x0cf3, 0x7015),
 	  .driver_info = AR9287_USB },  /* Atheros */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 87b6109..c42036f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1942,6 +1942,10 @@
 		pCap->num_gpio_pins = AR9271_NUM_GPIO;
 	else if (AR_DEVID_7010(ah))
 		pCap->num_gpio_pins = AR7010_NUM_GPIO;
+	else if (AR_SREV_9300_20_OR_LATER(ah))
+		pCap->num_gpio_pins = AR9300_NUM_GPIO;
+	else if (AR_SREV_9287_11_OR_LATER(ah))
+		pCap->num_gpio_pins = AR9287_NUM_GPIO;
 	else if (AR_SREV_9285_12_OR_LATER(ah))
 		pCap->num_gpio_pins = AR9285_NUM_GPIO;
 	else if (AR_SREV_9280_20_OR_LATER(ah))
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5362306..a126a3e 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1828,6 +1828,9 @@
 	struct ath_softc *sc = hw->priv;
 	struct ath_node *an = (struct ath_node *) sta->drv_priv;
 
+	if (!(sc->sc_flags & SC_OP_TXAGGR))
+		return;
+
 	switch (cmd) {
 	case STA_NOTIFY_SLEEP:
 		an->sleeping = true;
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index ba7f36a..ea35843 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1252,7 +1252,9 @@
 
 	ath_rc_priv->max_valid_rate = k;
 	ath_rc_sort_validrates(rate_table, ath_rc_priv);
-	ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
+	ath_rc_priv->rate_max_phy = (k > 4) ?
+					ath_rc_priv->valid_rate_index[k-4] :
+					ath_rc_priv->valid_rate_index[k-1];
 	ath_rc_priv->rate_table = rate_table;
 
 	ath_dbg(common, ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 07e35e5..3b5f9d6 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -423,12 +423,9 @@
 
 u32 ath_calcrxfilter(struct ath_softc *sc)
 {
-#define	RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
-
 	u32 rfilt;
 
-	rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE)
-		| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
+	rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
 		| ATH9K_RX_FILTER_MCAST;
 
 	if (sc->rx.rxfilter & FIF_PROBE_REQ)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index b1fe4fe..7c2e09a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2401,6 +2401,13 @@
 		b43_print_fw_helptext(dev->wl, 1);
 		err = -EOPNOTSUPP;
 		goto error;
+	} else if (fwrev >= 598) {
+		b43err(dev->wl, "YOUR FIRMWARE IS TOO NEW. Support for "
+		       "firmware 598 and up requires kernel 3.2 or newer. You "
+		       "have to install older firmware or upgrade kernel.\n");
+		b43_print_fw_helptext(dev->wl, 1);
+		err = -EOPNOTSUPP;
+		goto error;
 	}
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
diff --git a/drivers/net/wireless/bcm4329/dhd_common.c b/drivers/net/wireless/bcm4329/dhd_common.c
index f7cd372..8b89e39 100644
--- a/drivers/net/wireless/bcm4329/dhd_common.c
+++ b/drivers/net/wireless/bcm4329/dhd_common.c
@@ -1896,6 +1896,41 @@
 
 #endif
 
+/*
+ * returns = TRUE if associated, FALSE if not associated
+ */
+bool is_associated(dhd_pub_t *dhd, void *bss_buf)
+{
+	char bssid[ETHER_ADDR_LEN], zbuf[ETHER_ADDR_LEN];
+	int ret = -1;
+
+	bzero(bssid, ETHER_ADDR_LEN);
+	bzero(zbuf, ETHER_ADDR_LEN);
+
+	ret = dhdcdc_set_ioctl(dhd, 0, WLC_GET_BSSID, (char *)bssid, ETHER_ADDR_LEN);
+	DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
+
+	if (ret == BCME_NOTASSOCIATED) {
+		DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
+	}
+
+	if (ret < 0)
+		return FALSE;
+
+	if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
+		/*  STA is assocoated BSSID is non zero */
+
+		if (bss_buf) {
+			/* return bss if caller provided buf */
+			memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
+		}
+		return TRUE;
+	} else {
+		DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
+		return FALSE;
+	}
+}
+
 /* Function to estimate possible DTIM_SKIP value */
 int dhd_get_dtim_skip(dhd_pub_t *dhd)
 {
@@ -1979,7 +2014,6 @@
 int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
 {
 	char iovbuf[128];
-	uint8 bssid[6];
 	int ret = -1;
 
 	if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
@@ -1990,12 +2024,7 @@
 	memset(iovbuf, 0, sizeof(iovbuf));
 
 	/* Check if disassoc to enable pno */
-	if ((pfn_enabled) && \
-		((ret = dhdcdc_set_ioctl(dhd, 0, WLC_GET_BSSID, \
-				 (char *)&bssid, ETHER_ADDR_LEN)) == BCME_NOTASSOCIATED)) {
-		DHD_TRACE(("%s pno enable called in disassoc mode\n", __FUNCTION__));
-	}
-	else if (pfn_enabled) {
+	if (pfn_enabled && (is_associated(dhd, NULL) == TRUE)) {
 		DHD_ERROR(("%s pno enable called in assoc mode ret=%d\n", \
 			__FUNCTION__, ret));
 		return ret;
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig
index db434ab..205c813 100644
--- a/drivers/net/wireless/bcmdhd/Kconfig
+++ b/drivers/net/wireless/bcmdhd/Kconfig
@@ -31,3 +31,10 @@
 	select WEXT_PRIV
 	help
 	  Enables WEXT support
+
+config DHD_USE_STATIC_BUF
+	bool "Enable memory preallocation"
+	depends on BCMDHD
+	default n
+	---help---
+	  Use memory preallocated in platform
\ No newline at end of file
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
index e82c985..17f07ca 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -13,7 +13,7 @@
 DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o   \
 	dhd_linux_sched.o bcmwifi.o dhd_sdio.o bcmevent.o dhd_bta.o hndpmu.o  \
 	bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o            \
-	bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o
+	bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o dhd_cfg80211.o
 
 obj-$(CONFIG_BCMDHD) += bcmdhd.o
 bcmdhd-objs += $(DHDOFILES)
@@ -22,7 +22,7 @@
 DHDCFLAGS += -DSOFTAP
 endif
 ifneq ($(CONFIG_CFG80211),)
-bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o dhd_linux_mon.o
+bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o
 DHDCFLAGS += -DWL_CFG80211
 endif
 EXTRA_CFLAGS = $(DHDCFLAGS)
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index 24581dd..6a25d9a 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -20,7 +20,7 @@
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
- * $Id: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 Exp $
+ * $Id: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 $
  */
 
 #include <typedefs.h>
@@ -29,7 +29,7 @@
 #include <proto/bcmeth.h>
 #include <proto/bcmevent.h>
 
-#if WLC_E_LAST != 85
+#if WLC_E_LAST != 87
 #error "You need to add an entry to bcmevent_names[] for the new event"
 #endif
 
@@ -117,8 +117,10 @@
 	{ WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" },
 	{ WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" },
 #ifdef SOFTAP
-	{ WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }
+	{ WLC_E_GTK_PLUMBED, "GTK_PLUMBED" },
 #endif
+	{ WLC_E_ASSOC_REQ_IE, "ASSOC_REQ_IE" },
+	{ WLC_E_ASSOC_RESP_IE, "ASSOC_RESP_IE" }
 };
 
 
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
index 04c43a3..e01b6f8 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_linux.c,v 1.72.6.5 2010-12-23 01:13:15 Exp $
+ * $Id: bcmsdh_linux.c 308641 2012-01-17 02:18:02Z $
  */
 
 /**
@@ -147,17 +147,6 @@
 #endif /* BCMLXSDMMC */
 
 #ifndef BCMLXSDMMC
-static struct device_driver bcmsdh_driver = {
-	.name		= "pxa2xx-mci",
-	.bus		= &platform_bus_type,
-	.probe		= bcmsdh_probe,
-	.remove		= bcmsdh_remove,
-	.suspend	= NULL,
-	.resume		= NULL,
-	};
-#endif /* BCMLXSDMMC */
-
-#ifndef BCMLXSDMMC
 static
 #endif /* BCMLXSDMMC */
 int bcmsdh_probe(struct device *dev)
@@ -238,9 +227,9 @@
 	/* chain SDIO Host Controller info together */
 	sdhc->next = sdhcinfo;
 	sdhcinfo = sdhc;
+
 	/* Read the vendor/device ID from the CIS */
 	vendevid = bcmsdh_query_device(sdh);
-
 	/* try to attach to the target device */
 	if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
 	                                 (vendevid & 0xFFFF), 0, 0, 0, 0,
@@ -274,6 +263,7 @@
 	sdhc = sdhcinfo;
 	drvinfo.detach(sdhc->ch);
 	bcmsdh_detach(sdhc->osh, sdhc->sdh);
+
 	/* find the SDIO Host Controller state for this pdev and take it out from the list */
 	for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
 		if (sdhc->dev == (void *)dev) {
@@ -290,7 +280,6 @@
 		return 0;
 	}
 
-
 	/* release SDIO Host Controller info */
 	osh = sdhc->osh;
 	MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
@@ -531,13 +520,8 @@
 	drvinfo = *driver;
 
 #if defined(BCMPLATFORM_BUS)
-#if defined(BCMLXSDMMC)
 	SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
 	error = sdio_function_init();
-#else
-	SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
-	error = driver_register(&bcmsdh_driver);
-#endif /* defined(BCMLXSDMMC) */
 	return error;
 #endif /* defined(BCMPLATFORM_BUS) */
 
@@ -565,14 +549,12 @@
 	if (bcmsdh_pci_driver.node.next)
 #endif
 
-#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
-		driver_unregister(&bcmsdh_driver);
-#endif
 #if defined(BCMLXSDMMC)
 	sdio_function_cleanup();
 #endif /* BCMLXSDMMC */
+
 #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
-		pci_unregister_driver(&bcmsdh_pci_driver);
+	pci_unregister_driver(&bcmsdh_pci_driver);
 #endif /* BCMPLATFORM_BUS */
 }
 
@@ -611,13 +593,6 @@
 	return IRQ_HANDLED;
 }
 
-void *bcmsdh_get_drvdata(void)
-{
-	if (!sdhcinfo)
-		return NULL;
-	return dev_get_drvdata(sdhcinfo->dev);
-}
-
 int bcmsdh_register_oob_intr(void * dhdp)
 {
 	int error = 0;
@@ -645,6 +620,13 @@
 	return 0;
 }
 
+void *bcmsdh_get_drvdata(void)
+{
+	if (!sdhcinfo)
+		return NULL;
+	return dev_get_drvdata(sdhcinfo->dev);
+}
+
 void bcmsdh_set_irq(int flag)
 {
 	if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) {
@@ -671,6 +653,7 @@
 	}
 }
 #endif /* defined(OOB_INTR_ONLY) */
+
 /* Module parameters specific to each host-controller driver */
 
 extern uint sd_msglevel;	/* Debug message level */
@@ -694,6 +677,10 @@
 extern uint sd_f2_blocksize;
 module_param(sd_f2_blocksize, int, 0);
 
+#ifdef BCMSDIOH_STD
+extern int sd_uhsimode;
+module_param(sd_uhsimode, int, 0);
+#endif
 
 #ifdef BCMSDH_MODULE
 EXPORT_SYMBOL(bcmsdh_attach);
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index 70bacbd3..6a8ff94 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_sdmmc.c 282820 2011-09-09 15:40:35Z $
+ * $Id: bcmsdh_sdmmc.c 301794 2011-12-08 20:41:35Z $
  */
 #include <typedefs.h>
 
@@ -448,6 +448,7 @@
 		bcopy(params, &int_val, sizeof(int_val));
 
 	bool_val = (int_val != 0) ? TRUE : FALSE;
+	BCM_REFERENCE(bool_val);
 
 	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
 	switch (actionid) {
@@ -1002,11 +1003,11 @@
 	if (pkt == NULL) {
 		sd_data(("%s: Creating new %s Packet, len=%d\n",
 		         __FUNCTION__, write ? "TX" : "RX", buflen_u));
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 		if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
 #else
 		if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
 			sd_err(("%s: PKTGET failed: len %d\n",
 			           __FUNCTION__, buflen_u));
 			return SDIOH_API_RC_FAIL;
@@ -1023,11 +1024,11 @@
 		if (!write) {
 			bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
 		}
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 		PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
 #else
 		PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
 	} else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
 		/* Case 2: We have a packet, but it is unaligned. */
 
@@ -1036,11 +1037,11 @@
 
 		sd_data(("%s: Creating aligned %s Packet, len=%d\n",
 		         __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 		if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
 #else
 		if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
 			sd_err(("%s: PKTGET failed: len %d\n",
 			           __FUNCTION__, PKTLEN(sd->osh, pkt)));
 			return SDIOH_API_RC_FAIL;
@@ -1061,11 +1062,11 @@
 			      PKTDATA(sd->osh, pkt),
 			      PKTLEN(sd->osh, mypkt));
 		}
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 		PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
 #else
 		PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
-#endif /* DHD_USE_STATIC_BUF */
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
 	} else { /* case 3: We have a packet and it is aligned. */
 		sd_data(("%s: Aligned %s Packet, direct DMA\n",
 		         __FUNCTION__, write ? "Tx" : "Rx"));
@@ -1179,6 +1180,7 @@
 	sd = gInstance->sd;
 
 	ASSERT(sd != NULL);
+	BCM_REFERENCE(sd);
 }
 #endif /* !defined(OOB_INTR_ONLY) */
 
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
index 726b639..83f4d3d 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_sdmmc_linux.c,v 1.8.6.2 2011-02-01 18:38:36 Exp $
+ * $Id: bcmsdh_sdmmc_linux.c 308645 2012-01-17 02:33:26Z $
  */
 
 #include <typedefs.h>
@@ -55,13 +55,22 @@
 #if !defined(SDIO_DEVICE_ID_BROADCOM_4319)
 #define SDIO_DEVICE_ID_BROADCOM_4319	0x4319
 #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4330)
+#define SDIO_DEVICE_ID_BROADCOM_4330	0x4330
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4334)
+#define SDIO_DEVICE_ID_BROADCOM_4334    0x4334
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_43239)
+#define SDIO_DEVICE_ID_BROADCOM_43239    43239
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */
 
 #include <bcmsdh_sdmmc.h>
 
 #include <dhd_dbg.h>
 
 #ifdef WL_CFG80211
-extern void wl_cfg80211_set_sdio_func(void *func);
+extern void wl_cfg80211_set_parent_dev(void *dev);
 #endif
 
 extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
@@ -118,7 +127,7 @@
 
 	if (func->num == 2) {
 #ifdef WL_CFG80211
-		wl_cfg80211_set_sdio_func(func);
+		wl_cfg80211_set_parent_dev(&func->dev);
 #endif
 		sd_trace(("F2 found, calling bcmsdh_probe...\n"));
 		ret = bcmsdh_probe(&func->dev);
@@ -153,6 +162,9 @@
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) },
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) },
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) },
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) },
 	{ SDIO_DEVICE_CLASS(SDIO_CLASS_NONE)		},
 	{ /* end: all zeroes */				},
 };
@@ -166,11 +178,14 @@
 
 	if (func->num != 2)
 		return 0;
+
+	sd_trace(("%s Enter\n", __FUNCTION__));
+
 	if (dhd_os_check_wakelock(bcmsdh_get_drvdata()))
 		return -EBUSY;
 #if defined(OOB_INTR_ONLY)
 	bcmsdh_oob_intr_set(0);
-#endif
+#endif	/* defined(OOB_INTR_ONLY) */
 	dhd_mmc_suspend = TRUE;
 	smp_mb();
 
@@ -181,13 +196,13 @@
 {
 	struct sdio_func *func = dev_to_sdio_func(pdev);
 
-	if (func->num != 2)
-		return 0;
+	sd_trace(("%s Enter\n", __FUNCTION__));
 	dhd_mmc_suspend = FALSE;
 #if defined(OOB_INTR_ONLY)
-	if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
+	if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata()))
 		bcmsdh_oob_intr_set(1);
-#endif
+#endif /* (OOB_INTR_ONLY) */
+
 	smp_mb();
 	return 0;
 }
@@ -196,7 +211,7 @@
 	.suspend	= bcmsdh_sdmmc_suspend,
 	.resume		= bcmsdh_sdmmc_resume,
 };
-#endif
+#endif  /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
 
 static struct sdio_driver bcmsdh_sdmmc_driver = {
 	.probe		= bcmsdh_sdmmc_probe,
@@ -207,7 +222,7 @@
 	.drv = {
 		.pm	= &bcmsdh_sdmmc_pm_ops,
 	},
-#endif
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
 };
 
 struct sdos_info {
diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c
index fbdd7cd..6b578e6 100644
--- a/drivers/net/wireless/bcmdhd/bcmutils.c
+++ b/drivers/net/wireless/bcmdhd/bcmutils.c
@@ -20,7 +20,7 @@
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
- * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 Exp $
+ * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 $
  */
 
 #include <typedefs.h>
@@ -987,7 +987,6 @@
 	return (rc | priority);
 }
 
-#ifndef BCM_BOOTLOADER
 
 static char bcm_undeferrstr[32];
 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
@@ -1009,7 +1008,6 @@
 	return bcmerrorstrtable[-bcmerror];
 }
 
-#endif /* !BCM_BOOTLOADER */
 
 
 
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index c87f6cf..25e74f4 100644
--- a/drivers/net/wireless/bcmdhd/dhd.h
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd.h 290844 2011-10-20 08:54:39Z $
+ * $Id: dhd.h 306879 2012-01-09 21:33:03Z $
  */
 
 /****************
@@ -83,6 +83,9 @@
 /* max sequential rxcntl timeouts to set HANG event */
 #define MAX_CNTL_TIMEOUT  2
 
+#define DHD_SCAN_ACTIVE_TIME	 40 /* ms : Embedded default Active setting from DHD Driver */
+#define DHD_SCAN_PASSIVE_TIME	130 /* ms: Embedded default Passive setting from DHD Driver */
+
 enum dhd_bus_wake_state {
 	WAKE_LOCK_OFF,
 	WAKE_LOCK_PRIV,
@@ -116,7 +119,7 @@
 } dhd_if_state_t;
 
 
-#if defined(DHD_USE_STATIC_BUF)
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
 
 uint8* dhd_os_prealloc(void *osh, int section, uint size);
 void dhd_os_prefree(void *osh, void *addr, uint size);
@@ -128,7 +131,7 @@
 #define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size)
 #define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size)
 
-#endif /* defined(DHD_USE_STATIC_BUF) */
+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
 
 /* Packet alignment for most efficient SDIO (can change based on platform) */
 #ifndef DHD_SDALIGN
@@ -314,8 +317,8 @@
 #define DHD_OS_WAKE_LOCK_TIMEOUT(pub)		dhd_os_wake_lock_timeout(pub)
 #define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val)	dhd_os_wake_lock_timeout_enable(pub, val)
 
-#define DHD_PACKET_TIMEOUT	1
-#define DHD_EVENT_TIMEOUT	2
+#define DHD_PACKET_TIMEOUT_MS	1000
+#define DHD_EVENT_TIMEOUT_MS	1500
 
 /* interface operations (register, remove) should be atomic, use this lock to prevent race
  * condition among wifi on/off and interface operation functions
@@ -365,6 +368,11 @@
  * bus_hdrlen specifies required headroom for bus module header.
  */
 extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen);
+#if defined(WLP2P) && defined(WL_CFG80211)
+/* To allow attach/detach calls corresponding to p2p0 interface  */
+extern int dhd_attach_p2p(dhd_pub_t *);
+extern int dhd_detach_p2p(dhd_pub_t *);
+#endif /* WLP2P && WL_CFG80211 */
 extern int dhd_net_attach(dhd_pub_t *dhdp, int idx);
 
 /* Indication from bus module regarding removal/absence of dongle */
@@ -411,6 +419,9 @@
 extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
 extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
 extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
+extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
+
+#ifdef PNO_SUPPORT
 extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
 extern int dhd_pno_clean(dhd_pub_t *dhd);
 extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid,
@@ -421,9 +432,7 @@
                            int nssid, ushort  scan_fr, int pno_repeat, int pno_freq_expo_max);
 extern int dhd_dev_pno_enable(struct net_device *dev,  int pfn_enabled);
 extern int dhd_dev_get_pno_status(struct net_device *dev);
-extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
-extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
-extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
+#endif /* PNO_SUPPORT */
 
 #define DHD_UNICAST_FILTER_NUM		0
 #define DHD_BROADCAST_FILTER_NUM	1
@@ -432,6 +441,9 @@
 extern int net_os_set_packet_filter(struct net_device *dev, int val);
 extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num);
 
+extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
+extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
+
 #ifdef DHD_DEBUG
 extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
 #endif /* DHD_DEBUG */
@@ -453,7 +465,7 @@
 
 extern int dhd_ifname2idx(struct dhd_info *dhd, char *name);
 extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net);
-extern struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx);
+extern struct net_device * dhd_idx2net(void *pub, int ifidx);
 extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata,
                          wl_event_msg_t *, void **data_ptr);
 extern void wl_event_to_host_order(wl_event_msg_t * evt);
@@ -465,6 +477,7 @@
 extern struct dhd_cmn *dhd_common_init(osl_t *osh);
 extern void dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn);
 
+extern int dhd_do_driver_init(struct net_device *net);
 extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle,
 	char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx);
 extern void dhd_del_if(struct dhd_info *dhd, int ifidx);
@@ -701,12 +714,6 @@
 #define DHD_PKTTAG_DSTN(tag)	((dhd_pkttag_t*)(tag))->dstn_ether
 
 typedef int (*f_commitpkt_t)(void* ctx, void* p);
-int dhd_wlfc_enable(dhd_pub_t *dhd);
-int dhd_wlfc_interface_event(struct dhd_info *, uint8 action, uint8 ifid, uint8 iftype, uint8* ea);
-int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data);
-int dhd_wlfc_event(struct dhd_info *dhd);
-int dhd_os_wlfc_block(dhd_pub_t *pub);
-int dhd_os_wlfc_unblock(dhd_pub_t *pub);
 
 #ifdef PROP_TXSTATUS_DEBUG
 #define DHD_WLFC_CTRINC_MAC_CLOSE(entry)	do { (entry)->closed_ct++; } while (0)
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c
index 3a4de96..d01853c 100644
--- a/drivers/net/wireless/bcmdhd/dhd_cdc.c
+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_cdc.c,v 1.51.6.31 2011-02-09 14:31:43 Exp $
+ * $Id: dhd_cdc.c 303389 2011-12-16 09:30:48Z $
  *
  * BDC is like CDC, except it includes a header for data packets to convey
  * packet priority over the bus, and flags (e.g. to indicate checksum status
@@ -78,6 +78,8 @@
 	unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
 } dhd_prot_t;
 
+extern int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf);
+
 static int
 dhdcdc_msg(dhd_pub_t *dhd)
 {
@@ -2174,6 +2176,7 @@
 		WLFC_FLAGS_CREDIT_STATUS_SIGNALS |
 		WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE : 0;
 
+	dhd->wlfc_state  = NULL;
 
 	/*
 	try to enable/disable signaling by sending "tlv" iovar. if that fails,
@@ -2460,10 +2463,10 @@
 	return 0;
 
 fail:
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
 	if (cdc != NULL)
 		MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
-#endif
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
 	return BCME_NOMEM;
 }
 
@@ -2474,9 +2477,9 @@
 #ifdef PROP_TXSTATUS
 	dhd_wlfc_deinit(dhd);
 #endif
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
 	MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
-#endif
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
 	dhd->prot = NULL;
 }
 
@@ -2512,9 +2515,10 @@
 	ret = dhd_wlfc_init(dhd);
 #endif
 
-#if !defined(WL_CFG80211)
+#if defined(WL_CFG80211)
+	if (dhd_download_fw_on_driverload)
+#endif /* defined(WL_CFG80211) */
 	ret = dhd_preinit_ioctls(dhd);
-#endif /* WL_CFG80211 */
 
 	/* Always assumes wl for now */
 	dhd->iswl = TRUE;
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
new file mode 100644
index 0000000..800590c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
@@ -0,0 +1,593 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ * 
+ *         Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+#include <net/rtnetlink.h>
+
+#include <bcmutils.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <dhd_cfg80211.h>
+extern struct wl_priv *wlcfg_drv_priv;
+static int dhd_dongle_up = FALSE;
+
+static s32 wl_dongle_up(struct net_device *ndev, u32 up);
+
+/**
+ * Function implementations
+ */
+
+s32 dhd_cfg80211_init(struct wl_priv *wl)
+{
+	dhd_dongle_up = FALSE;
+	return 0;
+}
+
+s32 dhd_cfg80211_deinit(struct wl_priv *wl)
+{
+	dhd_dongle_up = FALSE;
+	return 0;
+}
+
+s32 dhd_cfg80211_down(struct wl_priv *wl)
+{
+	dhd_dongle_up = FALSE;
+	return 0;
+}
+
+static s32 wl_dongle_up(struct net_device *ndev, u32 up)
+{
+	s32 err = 0;
+
+	err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
+	if (unlikely(err)) {
+		WL_ERR(("WLC_UP error (%d)\n", err));
+	}
+	return err;
+}
+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock)
+{
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN	32
+#endif
+	struct net_device *ndev;
+	s32 err = 0;
+
+	WL_TRACE(("In\n"));
+	if (dhd_dongle_up) {
+		WL_ERR(("Dongle is already up\n"));
+		return err;
+	}
+
+	ndev = wl_to_prmry_ndev(wl);
+
+	if (need_lock)
+		rtnl_lock();
+
+	err = wl_dongle_up(ndev, 0);
+	if (unlikely(err)) {
+		WL_ERR(("wl_dongle_up failed\n"));
+		goto default_conf_out;
+	}
+	dhd_dongle_up = true;
+
+default_conf_out:
+	if (need_lock)
+		rtnl_unlock();
+	return err;
+
+}
+
+
+/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
+#define COEX_DHCP
+
+#if defined(COEX_DHCP)
+
+/* use New SCO/eSCO smart YG suppression */
+#define BT_DHCP_eSCO_FIX
+/* this flag boost wifi pkt priority to max, caution: -not fair to sco */
+#define BT_DHCP_USE_FLAGS
+/* T1 start SCO/ESCo priority suppression */
+#define BT_DHCP_OPPR_WIN_TIME	2500
+/* T2 turn off SCO/SCO supperesion is (timeout) */
+#define BT_DHCP_FLAG_FORCE_TIME 5500
+
+enum wl_cfg80211_btcoex_status {
+	BT_DHCP_IDLE,
+	BT_DHCP_START,
+	BT_DHCP_OPPR_WIN,
+	BT_DHCP_FLAG_FORCE_TIMEOUT
+};
+
+/*
+ * get named driver variable to uint register value and return error indication
+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
+ */
+static int
+dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
+	uint reg, int *retval)
+{
+	union {
+		char buf[WLC_IOCTL_SMLEN];
+		int val;
+	} var;
+	int error;
+
+	bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
+		(char *)(&var), sizeof(var.buf));
+	error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
+
+	*retval = dtoh32(var.val);
+	return (error);
+}
+
+static int
+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+	char ioctlbuf_local[1024];
+#else
+	static char ioctlbuf_local[1024];
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
+
+	bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
+
+	return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true));
+}
+/*
+get named driver variable to uint register value and return error indication
+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
+*/
+static int
+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
+{
+	char reg_addr[8];
+
+	memset(reg_addr, 0, sizeof(reg_addr));
+	memcpy((char *)&reg_addr[0], (char *)addr, 4);
+	memcpy((char *)&reg_addr[4], (char *)val, 4);
+
+	return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+}
+
+static bool btcoex_is_sco_active(struct net_device *dev)
+{
+	int ioc_res = 0;
+	bool res = FALSE;
+	int sco_id_cnt = 0;
+	int param27;
+	int i;
+
+	for (i = 0; i < 12; i++) {
+
+		ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
+
+		WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
+			__FUNCTION__, i, param27));
+
+		if (ioc_res < 0) {
+			WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
+			break;
+		}
+
+		if ((param27 & 0x6) == 2) { /* count both sco & esco  */
+			sco_id_cnt++;
+		}
+
+		if (sco_id_cnt > 2) {
+			WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d  samples:%d\n",
+				__FUNCTION__, sco_id_cnt, i));
+			res = TRUE;
+			break;
+		}
+
+		msleep(5);
+	}
+
+	return res;
+}
+
+#if defined(BT_DHCP_eSCO_FIX)
+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+	static bool saved_status = FALSE;
+
+	char buf_reg50va_dhcp_on[8] =
+		{ 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+	char buf_reg51va_dhcp_on[8] =
+		{ 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+	char buf_reg64va_dhcp_on[8] =
+		{ 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+	char buf_reg65va_dhcp_on[8] =
+		{ 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+	char buf_reg71va_dhcp_on[8] =
+		{ 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+	uint32 regaddr;
+	static uint32 saved_reg50;
+	static uint32 saved_reg51;
+	static uint32 saved_reg64;
+	static uint32 saved_reg65;
+	static uint32 saved_reg71;
+
+	if (trump_sco) {
+		/* this should reduce eSCO agressive retransmit
+		 * w/o breaking it
+		 */
+
+		/* 1st save current */
+		WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+			  "override}\n"));
+		if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+			(!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+			(!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+			(!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+			(!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+			saved_status = TRUE;
+			WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
+				  "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+				  __FUNCTION__, saved_reg50, saved_reg51,
+				  saved_reg64, saved_reg65, saved_reg71));
+		} else {
+			WL_ERR((":%s: save btc_params failed\n",
+				__FUNCTION__));
+			saved_status = FALSE;
+			return -1;
+		}
+
+		WL_TRACE(("override with [50,51,64,65,71]:"
+			  "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+			  *(u32 *)(buf_reg50va_dhcp_on+4),
+			  *(u32 *)(buf_reg51va_dhcp_on+4),
+			  *(u32 *)(buf_reg64va_dhcp_on+4),
+			  *(u32 *)(buf_reg65va_dhcp_on+4),
+			  *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+		dev_wlc_bufvar_set(dev, "btc_params",
+			(char *)&buf_reg50va_dhcp_on[0], 8);
+		dev_wlc_bufvar_set(dev, "btc_params",
+			(char *)&buf_reg51va_dhcp_on[0], 8);
+		dev_wlc_bufvar_set(dev, "btc_params",
+			(char *)&buf_reg64va_dhcp_on[0], 8);
+		dev_wlc_bufvar_set(dev, "btc_params",
+			(char *)&buf_reg65va_dhcp_on[0], 8);
+		dev_wlc_bufvar_set(dev, "btc_params",
+			(char *)&buf_reg71va_dhcp_on[0], 8);
+
+		saved_status = TRUE;
+	} else if (saved_status) {
+		/* restore previously saved bt params */
+		WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+			  "override}\n"));
+
+		regaddr = 50;
+		dev_wlc_intvar_set_reg(dev, "btc_params",
+			(char *)&regaddr, (char *)&saved_reg50);
+		regaddr = 51;
+		dev_wlc_intvar_set_reg(dev, "btc_params",
+			(char *)&regaddr, (char *)&saved_reg51);
+		regaddr = 64;
+		dev_wlc_intvar_set_reg(dev, "btc_params",
+			(char *)&regaddr, (char *)&saved_reg64);
+		regaddr = 65;
+		dev_wlc_intvar_set_reg(dev, "btc_params",
+			(char *)&regaddr, (char *)&saved_reg65);
+		regaddr = 71;
+		dev_wlc_intvar_set_reg(dev, "btc_params",
+			(char *)&regaddr, (char *)&saved_reg71);
+
+		WL_TRACE(("restore bt_params[50,51,64,65,71]:"
+			"0x%x 0x%x 0x%x 0x%x 0x%x\n",
+			saved_reg50, saved_reg51, saved_reg64,
+			saved_reg65, saved_reg71));
+
+		saved_status = FALSE;
+	} else {
+		WL_ERR((":%s att to restore not saved BTCOEX params\n",
+			__FUNCTION__));
+		return -1;
+	}
+	return 0;
+}
+#endif /* BT_DHCP_eSCO_FIX */
+
+static void
+wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+{
+#if defined(BT_DHCP_USE_FLAGS)
+	char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
+	char buf_flag7_default[8]   = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
+
+
+#if defined(BT_DHCP_eSCO_FIX)
+	/* set = 1, save & turn on  0 - off & restore prev settings */
+	set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+	WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
+	if (set == TRUE)
+		/* Forcing bt_flag7  */
+		dev_wlc_bufvar_set(dev, "btc_flags",
+			(char *)&buf_flag7_dhcp_on[0],
+			sizeof(buf_flag7_dhcp_on));
+	else
+		/* Restoring default bt flag7 */
+		dev_wlc_bufvar_set(dev, "btc_flags",
+			(char *)&buf_flag7_default[0],
+			sizeof(buf_flag7_default));
+#endif
+}
+
+static void wl_cfg80211_bt_timerfunc(ulong data)
+{
+	struct btcoex_info *bt_local = (struct btcoex_info *)data;
+	WL_TRACE(("%s\n", __FUNCTION__));
+	bt_local->timer_on = 0;
+	schedule_work(&bt_local->work);
+}
+
+static void wl_cfg80211_bt_handler(struct work_struct *work)
+{
+	struct btcoex_info *btcx_inf;
+
+	btcx_inf = container_of(work, struct btcoex_info, work);
+
+	if (btcx_inf->timer_on) {
+		btcx_inf->timer_on = 0;
+		del_timer_sync(&btcx_inf->timer);
+	}
+
+	switch (btcx_inf->bt_state) {
+		case BT_DHCP_START:
+			/* DHCP started
+			 * provide OPPORTUNITY window to get DHCP address
+			 */
+			WL_TRACE(("%s bt_dhcp stm: started \n",
+				__FUNCTION__));
+			btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
+			mod_timer(&btcx_inf->timer,
+				jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
+			btcx_inf->timer_on = 1;
+			break;
+
+		case BT_DHCP_OPPR_WIN:
+			if (btcx_inf->dhcp_done) {
+				WL_TRACE(("%s DHCP Done before T1 expiration\n",
+					__FUNCTION__));
+				goto btc_coex_idle;
+			}
+
+			/* DHCP is not over yet, start lowering BT priority
+			 * enforce btc_params + flags if necessary
+			 */
+			WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
+				BT_DHCP_OPPR_WIN_TIME));
+			if (btcx_inf->dev)
+				wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
+			btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
+			mod_timer(&btcx_inf->timer,
+				jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
+			btcx_inf->timer_on = 1;
+			break;
+
+		case BT_DHCP_FLAG_FORCE_TIMEOUT:
+			if (btcx_inf->dhcp_done) {
+				WL_TRACE(("%s DHCP Done before T2 expiration\n",
+					__FUNCTION__));
+			} else {
+				/* Noo dhcp during T1+T2, restore BT priority */
+				WL_TRACE(("%s DHCP wait interval T2:%d"
+					  "msec expired\n", __FUNCTION__,
+					  BT_DHCP_FLAG_FORCE_TIME));
+			}
+
+			/* Restoring default bt priority */
+			if (btcx_inf->dev)
+				wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+btc_coex_idle:
+			btcx_inf->bt_state = BT_DHCP_IDLE;
+			btcx_inf->timer_on = 0;
+			break;
+
+		default:
+			WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
+				btcx_inf->bt_state));
+			if (btcx_inf->dev)
+				wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+			btcx_inf->bt_state = BT_DHCP_IDLE;
+			btcx_inf->timer_on = 0;
+			break;
+	}
+
+	net_os_wake_unlock(btcx_inf->dev);
+}
+
+int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+{
+	struct btcoex_info *btco_inf = NULL;
+
+	btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
+	if (!btco_inf)
+		return -ENOMEM;
+
+	btco_inf->bt_state = BT_DHCP_IDLE;
+	btco_inf->ts_dhcp_start = 0;
+	btco_inf->ts_dhcp_ok = 0;
+	/* Set up timer for BT  */
+	btco_inf->timer_ms = 10;
+	init_timer(&btco_inf->timer);
+	btco_inf->timer.data = (ulong)btco_inf;
+	btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+
+	btco_inf->dev = wl->wdev->netdev;
+
+	INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+
+	wl->btcoex_info = btco_inf;
+	return 0;
+}
+
+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+{
+	if (!wl->btcoex_info)
+		return;
+
+	if (!wl->btcoex_info->timer_on) {
+		wl->btcoex_info->timer_on = 0;
+		del_timer_sync(&wl->btcoex_info->timer);
+	}
+
+	cancel_work_sync(&wl->btcoex_info->work);
+
+	kfree(wl->btcoex_info);
+	wl->btcoex_info = NULL;
+}
+#endif 
+
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
+{
+
+	struct wl_priv *wl = wlcfg_drv_priv;
+	char powermode_val = 0;
+	char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
+	char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
+	char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
+
+	uint32 regaddr;
+	static uint32 saved_reg66;
+	static uint32 saved_reg41;
+	static uint32 saved_reg68;
+	static bool saved_status = FALSE;
+
+#ifdef COEX_DHCP
+	char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+	struct btcoex_info *btco_inf = wl->btcoex_info;
+#endif /* COEX_DHCP */
+
+	/* Figure out powermode 1 or o command */
+	strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
+
+	if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
+
+		WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
+
+		/* Retrieve and saved orig regs value */
+		if ((saved_status == FALSE) &&
+			(!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
+			(!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
+			(!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
+				saved_status = TRUE;
+				WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
+					saved_reg66, saved_reg41, saved_reg68));
+
+				/* Disable PM mode during dhpc session */
+
+				/* Disable PM mode during dhpc session */
+#ifdef COEX_DHCP
+				/* Start  BT timer only for SCO connection */
+				if (btcoex_is_sco_active(dev)) {
+					/* btc_params 66 */
+					dev_wlc_bufvar_set(dev, "btc_params",
+						(char *)&buf_reg66va_dhcp_on[0],
+						sizeof(buf_reg66va_dhcp_on));
+					/* btc_params 41 0x33 */
+					dev_wlc_bufvar_set(dev, "btc_params",
+						(char *)&buf_reg41va_dhcp_on[0],
+						sizeof(buf_reg41va_dhcp_on));
+					/* btc_params 68 0x190 */
+					dev_wlc_bufvar_set(dev, "btc_params",
+						(char *)&buf_reg68va_dhcp_on[0],
+						sizeof(buf_reg68va_dhcp_on));
+					saved_status = TRUE;
+
+					btco_inf->bt_state = BT_DHCP_START;
+					btco_inf->timer_on = 1;
+					mod_timer(&btco_inf->timer, btco_inf->timer.expires);
+					WL_TRACE(("%s enable BT DHCP Timer\n",
+					__FUNCTION__));
+				}
+#endif /* COEX_DHCP */
+		}
+		else if (saved_status == TRUE) {
+			WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
+		}
+	}
+	else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
+
+
+		/* Restoring PM mode */
+
+#ifdef COEX_DHCP
+		/* Stop any bt timer because DHCP session is done */
+		WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
+		if (btco_inf->timer_on) {
+			btco_inf->timer_on = 0;
+			del_timer_sync(&btco_inf->timer);
+
+			if (btco_inf->bt_state != BT_DHCP_IDLE) {
+			/* need to restore original btc flags & extra btc params */
+				WL_TRACE(("%s bt->bt_state:%d\n",
+					__FUNCTION__, btco_inf->bt_state));
+				/* wake up btcoex thread to restore btlags+params  */
+				schedule_work(&btco_inf->work);
+			}
+		}
+
+		/* Restoring btc_flag paramter anyway */
+		if (saved_status == TRUE)
+			dev_wlc_bufvar_set(dev, "btc_flags",
+				(char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
+#endif /* COEX_DHCP */
+
+		/* Restore original values */
+		if (saved_status == TRUE) {
+			regaddr = 66;
+			dev_wlc_intvar_set_reg(dev, "btc_params",
+				(char *)&regaddr, (char *)&saved_reg66);
+			regaddr = 41;
+			dev_wlc_intvar_set_reg(dev, "btc_params",
+				(char *)&regaddr, (char *)&saved_reg41);
+			regaddr = 68;
+			dev_wlc_intvar_set_reg(dev, "btc_params",
+				(char *)&regaddr, (char *)&saved_reg68);
+
+			WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
+				saved_reg66, saved_reg41, saved_reg68));
+		}
+		saved_status = FALSE;
+
+	}
+	else {
+		WL_ERR(("%s Unkwown yet power setting, ignored\n",
+			__FUNCTION__));
+	}
+
+	snprintf(command, 3, "OK");
+
+	return (strlen("OK"));
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h
new file mode 100644
index 0000000..8dab652
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h
@@ -0,0 +1,42 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ * 
+ *         Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+
+#ifndef __DHD_CFG80211__
+#define __DHD_CFG80211__
+
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+
+s32 dhd_cfg80211_init(struct wl_priv *wl);
+s32 dhd_cfg80211_deinit(struct wl_priv *wl);
+s32 dhd_cfg80211_down(struct wl_priv *wl);
+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock);
+
+int wl_cfg80211_btcoex_init(struct wl_priv *wl);
+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
+
+#endif /* __DHD_CFG80211__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index a29c2fa..a54c391 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_common.c 290546 2011-10-19 01:55:21Z $
+ * $Id: dhd_common.c 307573 2012-01-12 00:04:39Z $
  */
 #include <typedefs.h>
 #include <osl.h>
@@ -336,6 +336,11 @@
 
 	case IOV_SVAL(IOV_MSGLEVEL):
 		dhd_msg_level = int_val;
+#ifdef WL_CFG80211
+		/* Enable DHD and WL logs in oneshot */
+		if (dhd_msg_level & DHD_WL_VAL)
+			wl_cfg80211_enable_trace(dhd_msg_level);
+#endif
 		break;
 	case IOV_GVAL(IOV_BCMERRORSTR):
 		bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
@@ -857,6 +862,8 @@
 		break;
 
 	case WLC_E_SCAN_COMPLETE:
+	case WLC_E_ASSOC_REQ_IE:
+	case WLC_E_ASSOC_RESP_IE:
 	case WLC_E_PMKID_CACHE:
 		DHD_EVENT(("MACEVENT: %s\n", event_name));
 		break;
@@ -1489,7 +1496,7 @@
 		return -1;
 
 	iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
-	retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, TRUE, 0);
+	retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0);
 
 	if (retcode) {
 		DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
@@ -1902,6 +1909,7 @@
 	if ((!dhd) && (!ssids_local)) {
 		DHD_ERROR(("%s error exit\n", __FUNCTION__));
 		err = -1;
+		return err;
 	}
 
 	if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
@@ -2155,14 +2163,14 @@
 int
 wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left)
 {
-	char* str =  *list_str;
+	char* str;
 	int idx = 0;
 
 	if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
 		DHD_ERROR(("%s error paramters\n", __FUNCTION__));
 		return -1;
 	}
-
+	str = *list_str;
 	while (*bytes_left > 0) {
 
 		if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 92cdc9b..233c891 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_linux.c 291449 2011-10-22 12:16:26Z $
+ * $Id: dhd_linux.c 308879 2012-01-17 22:03:47Z $
  */
 
 #include <typedefs.h>
@@ -109,6 +109,7 @@
 #include <wl_android.h>
 
 #ifdef ARP_OFFLOAD_SUPPORT
+void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add);
 static int dhd_device_event(struct notifier_block *this,
 	unsigned long event,
 	void *ptr);
@@ -273,6 +274,10 @@
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	struct early_suspend early_suspend;
 #endif /* CONFIG_HAS_EARLYSUSPEND */
+
+#ifdef ARP_OFFLOAD_SUPPORT
+	u32 pend_ipaddr;
+#endif /* ARP_OFFLOAD_SUPPORT */
 } dhd_info_t;
 
 /* Definitions to provide path to the firmware and nvram
@@ -281,6 +286,8 @@
 char firmware_path[MOD_PARAM_PATHLEN];
 char nvram_path[MOD_PARAM_PATHLEN];
 
+int op_mode = 0;
+module_param(op_mode, int, 0644);
 extern int wl_control_wl_start(struct net_device *dev);
 extern int net_os_send_hang_message(struct net_device *dev);
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -353,19 +360,6 @@
 module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-#define DAEMONIZE(a) daemonize(a); \
-	allow_signal(SIGKILL); \
-	allow_signal(SIGTERM);
-#else /* Linux 2.4 (w/o preemption patch) */
-#define RAISE_RX_SOFTIRQ() \
-	cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
-#define DAEMONIZE(a) daemonize(); \
-	do { if (a) \
-		strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
-	} while (0);
-#endif /* LINUX_VERSION_CODE  */
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
 #define BLOCKABLE()	(!in_atomic())
 #else
 #define BLOCKABLE()	(!in_interrupt())
@@ -436,6 +430,9 @@
 ;
 static void dhd_net_if_lock_local(dhd_info_t *dhd);
 static void dhd_net_if_unlock_local(dhd_info_t *dhd);
+#if !defined(AP) && defined(WLP2P)
+static u32 dhd_concurrent_fw(dhd_pub_t *dhd);
+#endif 
 
 #ifdef WLMEDIA_HTSF
 void htsf_update(dhd_info_t *dhd, void *data);
@@ -498,7 +495,7 @@
 
 static struct notifier_block dhd_sleep_pm_notifier = {
 	.notifier_call = dhd_sleep_pm_callback,
-	.priority = 0
+	.priority = 10
 };
 extern int register_pm_notifier(struct notifier_block *nb);
 extern int unregister_pm_notifier(struct notifier_block *nb);
@@ -693,8 +690,9 @@
 	return DHD_BAD_IF;
 }
 
-struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx)
+struct net_device * dhd_idx2net(void *pub, int ifidx)
 {
+	struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
 	struct dhd_info *dhd_info;
 
 	if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
@@ -922,6 +920,7 @@
 		DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
 	} else {
 		memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
+		memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
 	}
 
 	return ret;
@@ -941,8 +940,9 @@
 	unsigned long flags;
 #endif
 
+	if (!ifp || !ifp->info || !ifp->idx)
+		return;
 	ASSERT(ifp && ifp->info && ifp->idx);	/* Virtual interfaces only */
-
 	dhd = ifp->info;
 
 	DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state));
@@ -977,7 +977,7 @@
 #ifdef WL_CFG80211
 			if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
 				if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
-					dhd_net_attach)) {
+					(void*)dhd_net_attach)) {
 					ifp->state = DHD_IF_NONE;
 					return;
 				}
@@ -1033,6 +1033,7 @@
 		ifp->set_multicast = FALSE;
 		if (ifp->net) {
 			free_netdev(ifp->net);
+			ifp->net = NULL;
 		}
 		dhd->iflist[ifp->idx] = NULL;
 #ifdef SOFTAP
@@ -1134,7 +1135,7 @@
 	if (ifidx == DHD_BAD_IF)
 		return -1;
 
-	ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+	ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
 	memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
 	dhd->set_macaddress = TRUE;
 	up(&dhd->thr_sysioc_ctl.sema);
@@ -1152,7 +1153,7 @@
 	if (ifidx == DHD_BAD_IF)
 		return;
 
-	ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+	ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
 	dhd->iflist[ifidx]->set_multicast = TRUE;
 	up(&dhd->thr_sysioc_ctl.sema);
 }
@@ -1163,6 +1164,7 @@
 {
 	dhd_info_t *di = (dhd_info_t *)(pub->info);
 	ASSERT(di != NULL);
+
 	spin_lock_bh(&di->wlfc_spinlock);
 	return 1;
 }
@@ -1196,7 +1198,7 @@
 	}
 
 	/* Update multicast statistic */
-	if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) {
+	if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
 		uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
 		eh = (struct ether_header *)pktdata;
 
@@ -1204,6 +1206,9 @@
 			dhdp->tx_multicast++;
 		if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
 			atomic_inc(&dhd->pend_8021x_cnt);
+	} else {
+		PKTFREE(dhd->pub.osh, pktbuf, TRUE);
+		return BCME_ERROR;
 	}
 
 	/* Look into the packet and update the packet priority */
@@ -1397,7 +1402,7 @@
 	int i;
 	dhd_if_t *ifp;
 	wl_event_msg_t event;
-	int tout = DHD_PACKET_TIMEOUT;
+	int tout = DHD_PACKET_TIMEOUT_MS;
 
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
@@ -1414,7 +1419,7 @@
 			PKTFREE(dhdp->osh, pktbuf, TRUE);
 			continue;
 		}
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
 		/* Dropping packets before registering net device to avoid kernel panic */
 		if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED ||
 			!dhd->pub.up) {
@@ -1423,6 +1428,7 @@
 			PKTFREE(dhdp->osh, pktbuf, TRUE);
 			continue;
 		}
+#endif
 
 		pnext = PKTNEXT(dhdp->osh, pktbuf);
 		PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
@@ -1498,10 +1504,12 @@
 			&data);
 
 			wl_event_to_host_order(&event);
+			tout = DHD_EVENT_TIMEOUT_MS;
 			if (event.event_type == WLC_E_BTA_HCI_EVENT) {
 				dhd_bta_doevt(dhdp, data, event.datalen);
+			} else if (event.event_type == WLC_E_PFN_NET_FOUND) {
+				tout *= 2;
 			}
-			tout = DHD_EVENT_TIMEOUT;
 		}
 
 		ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
@@ -1588,8 +1596,10 @@
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
 	ifidx = dhd_net2idx(dhd, net);
-	if (ifidx == DHD_BAD_IF)
+	if (ifidx == DHD_BAD_IF) {
+		DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
 		return NULL;
+	}
 
 	ifp = dhd->iflist[ifidx];
 	ASSERT(dhd && ifp);
@@ -2029,7 +2039,7 @@
 	/* send to dongle only if we are not waiting for reload already */
 	if (dhd->pub.hang_was_sent) {
 		DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
-		DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT);
+		DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
 		DHD_OS_WAKE_UNLOCK(&dhd->pub);
 		return OSL_ERROR(BCME_DONGLE_DOWN);
 	}
@@ -2038,6 +2048,7 @@
 	DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
 
 	if (ifidx == DHD_BAD_IF) {
+		DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
 		DHD_OS_WAKE_UNLOCK(&dhd->pub);
 		return -1;
 	}
@@ -2235,6 +2246,7 @@
 #endif
 
 	for (i = 1; i < DHD_MAX_IFS; i++) {
+		dhd_net_if_lock_local(dhd);
 		if (dhd->iflist[i]) {
 			DHD_TRACE(("Deleting IF: %d \n", i));
 			if ((dhd->iflist[i]->state != DHD_IF_DEL) &&
@@ -2244,6 +2256,7 @@
 				dhd_op_if(dhd->iflist[i]);
 			}
 		}
+		dhd_net_if_unlock_local(dhd);
 	}
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -2261,7 +2274,7 @@
 	int ifidx;
 	dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
 	DHD_OS_WAKE_LOCK(&dhd->pub);
-	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+	DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
 	if (dhd->pub.up == 0) {
 		goto exit;
 	}
@@ -2269,7 +2282,7 @@
 
 #ifdef WL_CFG80211
 	if (ifidx == 0) {
-		wl_cfg80211_down();
+		wl_cfg80211_down(NULL);
 
 		/*
 		 * For CFG80211: Clean up all the left over virtual interfaces
@@ -2296,7 +2309,6 @@
 	if (ifidx == 0 && !dhd_download_fw_on_driverload)
 		wl_android_wifi_off(net);
 #endif
-	dhd->pub.hang_was_sent = 0;
 	dhd->pub.rxcnt_timeout = 0;
 	dhd->pub.txcnt_timeout = 0;
 	OLD_MOD_DEC_USE_COUNT;
@@ -2325,13 +2337,20 @@
 		firmware_path[0] = '\0';
 	}
 
+	dhd->pub.hang_was_sent = 0;
+
 #if !defined(WL_CFG80211)
 	/*
 	 * Force start if ifconfig_up gets called before START command
 	 * We keep WEXT's wl_control_wl_start to provide backward compatibility
 	 * This should be removed in the future
 	 */
-	wl_control_wl_start(net);
+	ret = wl_control_wl_start(net);
+	if (ret != 0) {
+		DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+		ret = -1;
+		goto exit;
+	}
 #endif
 
 	ifidx = dhd_net2idx(dhd, net);
@@ -2353,12 +2372,17 @@
 		atomic_set(&dhd->pend_8021x_cnt, 0);
 #if defined(WL_CFG80211)
 		DHD_ERROR(("\n%s\n", dhd_version));
-		if (!dhd_download_fw_on_driverload)
-			wl_android_wifi_on(net);
+		if (!dhd_download_fw_on_driverload) {
+			ret = wl_android_wifi_on(net);
+			if (ret != 0) {
+				DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+				ret = -1;
+				goto exit;
+			}
+		}
 #endif /* defined(WL_CFG80211) */
 
 		if (dhd->pub.busstate != DHD_BUS_DATA) {
-			int ret;
 
 			/* try to bring up bus */
 			if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
@@ -2381,7 +2405,7 @@
 #endif /* TOE */
 
 #if defined(WL_CFG80211)
-		if (unlikely(wl_cfg80211_up())) {
+		if (unlikely(wl_cfg80211_up(NULL))) {
 			DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
 			ret = -1;
 			goto exit;
@@ -2403,6 +2427,32 @@
 	return ret;
 }
 
+int dhd_do_driver_init(struct net_device *net)
+{
+	dhd_info_t *dhd = NULL;
+
+	if (!net) {
+		DHD_ERROR(("Primary Interface not initialized \n"));
+		return -EINVAL;
+	}
+
+	dhd = *(dhd_info_t **)netdev_priv(net);
+
+	/* If driver is already initialized, do nothing
+	 */
+	if (dhd->pub.busstate == DHD_BUS_DATA) {
+		DHD_TRACE(("Driver already Inititalized. Nothing to do"));
+		return 0;
+	}
+
+	if (dhd_open(net) < 0) {
+		DHD_ERROR(("Driver Init Failed \n"));
+		return -1;
+	}
+
+	return 0;
+}
+
 osl_t *
 dhd_osl_attach(void *pdev, uint bustype)
 {
@@ -2456,7 +2506,7 @@
 		ifp->state = DHD_IF_ADD;
 		ifp->idx = ifidx;
 		ifp->bssidx = bssidx;
-		ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+		ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
 		up(&dhd->thr_sysioc_ctl.sema);
 	} else
 		ifp->net = (struct net_device *)handle;
@@ -2480,10 +2530,30 @@
 
 	ifp->state = DHD_IF_DEL;
 	ifp->idx = ifidx;
-	ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+	ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
 	up(&dhd->thr_sysioc_ctl.sema);
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+static struct net_device_ops dhd_ops_pri = {
+	.ndo_open = dhd_open,
+	.ndo_stop = dhd_stop,
+	.ndo_get_stats = dhd_get_stats,
+	.ndo_do_ioctl = dhd_ioctl_entry,
+	.ndo_start_xmit = dhd_start_xmit,
+	.ndo_set_mac_address = dhd_set_mac_address,
+	.ndo_set_multicast_list = dhd_set_multicast_list,
+};
+
+static struct net_device_ops dhd_ops_virt = {
+	.ndo_get_stats = dhd_get_stats,
+	.ndo_do_ioctl = dhd_ioctl_entry,
+	.ndo_start_xmit = dhd_start_xmit,
+	.ndo_set_mac_address = dhd_set_mac_address,
+	.ndo_set_multicast_list = dhd_set_multicast_list,
+};
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
+
 dhd_pub_t *
 dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 {
@@ -2676,6 +2746,7 @@
 #endif
 
 #ifdef ARP_OFFLOAD_SUPPORT
+	dhd->pend_ipaddr = 0;
 	register_inetaddr_notifier(&dhd_notifier);
 #endif /* ARP_OFFLOAD_SUPPORT */
 
@@ -2709,7 +2780,8 @@
 	DHD_TRACE(("Enter %s:\n", __FUNCTION__));
 
 #ifdef DHDTHREAD
-	dhd_os_sdlock(dhdp);
+	if (dhd->threads_only)
+		dhd_os_sdlock(dhdp);
 #endif /* DHDTHREAD */
 
 	/* try to download image and nvram to the dongle */
@@ -2722,14 +2794,16 @@
 			DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
 			           __FUNCTION__, fw_path, nv_path));
 #ifdef DHDTHREAD
-			dhd_os_sdunlock(dhdp);
+			if (dhd->threads_only)
+				dhd_os_sdunlock(dhdp);
 #endif /* DHDTHREAD */
 			return -1;
 		}
 	}
 	if (dhd->pub.busstate != DHD_BUS_LOAD) {
 #ifdef DHDTHREAD
-		dhd_os_sdunlock(dhdp);
+		if (dhd->threads_only)
+			dhd_os_sdunlock(dhdp);
 #endif /* DHDTHREAD */
 		return -ENETDOWN;
 	}
@@ -2743,7 +2817,8 @@
 
 		DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
 #ifdef DHDTHREAD
-		dhd_os_sdunlock(dhdp);
+		if (dhd->threads_only)
+			dhd_os_sdunlock(dhdp);
 #endif /* DHDTHREAD */
 		return ret;
 	}
@@ -2759,7 +2834,8 @@
 
 		DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
 #ifdef DHDTHREAD
-		dhd_os_sdunlock(dhdp);
+		if (dhd->threads_only)
+			dhd_os_sdunlock(dhdp);
 #endif /* DHDTHREAD */
 		return -ENODEV;
 	}
@@ -2776,13 +2852,15 @@
 		del_timer_sync(&dhd->timer);
 		DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
 #ifdef DHDTHREAD
-		dhd_os_sdunlock(dhdp);
+		if (dhd->threads_only)
+			dhd_os_sdunlock(dhdp);
 #endif /* DHDTHREAD */
 		return -ENODEV;
 	}
 
 #ifdef DHDTHREAD
-	dhd_os_sdunlock(dhdp);
+	if (dhd->threads_only)
+		dhd_os_sdunlock(dhdp);
 #endif /* DHDTHREAD */
 
 #ifdef READ_MACADDR
@@ -2797,9 +2875,49 @@
 	dhd_write_macaddr(dhd->pub.mac.octet);
 #endif
 
+#ifdef ARP_OFFLOAD_SUPPORT
+	if (dhd->pend_ipaddr) {
+#ifdef AOE_IP_ALIAS_SUPPORT
+		aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+		dhd->pend_ipaddr = 0;
+	}
+#endif /* ARP_OFFLOAD_SUPPORT */
+
 	return 0;
 }
 
+#if !defined(AP) && defined(WLP2P)
+/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware
+ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
+ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
+ * would still be named as fw_bcmdhd_apsta.
+ */
+static u32
+dhd_concurrent_fw(dhd_pub_t *dhd)
+{
+	int ret = 0;
+	char buf[WLC_IOCTL_SMLEN];
+
+	if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) &&
+		(strstr(fw_path, "_apsta") == NULL)) {
+		/* Given path is for the STA firmware. Check whether P2P support is present in
+		 * the firmware. If so, set mode as P2P (concurrent support).
+		 */
+		memset(buf, 0, sizeof(buf));
+		bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
+		if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+			FALSE, 0)) < 0) {
+			DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
+		} else if (buf[0] == 1) {
+			DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__));
+			return 1;
+		}
+	}
+	return 0;
+}
+#endif 
+
 int
 dhd_preinit_ioctls(dhd_pub_t *dhd)
 {
@@ -2816,9 +2934,9 @@
 #if defined(ARP_OFFLOAD_SUPPORT)
 	int arpoe = 1;
 #endif
-	int scan_assoc_time = 40;
+	int scan_assoc_time = DHD_SCAN_ACTIVE_TIME;
 	int scan_unassoc_time = 40;
-	int scan_passive_time = 130;
+	int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
 	char buf[WLC_IOCTL_SMLEN];
 	char *ptr;
 	uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
@@ -2865,7 +2983,7 @@
 #endif /* GET_CUSTOM_MAC_ENABLE */
 
 #ifdef SET_RANDOM_MAC_SOFTAP
-	if (strstr(fw_path, "_apsta") != NULL) {
+	if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) {
 		uint rand_mac;
 
 		srandom32((uint)jiffies);
@@ -2889,7 +3007,8 @@
 	DHD_TRACE(("Firmware = %s\n", fw_path));
 #if !defined(AP) && defined(WLP2P)
 	/* Check if firmware with WFD support used */
-	if (strstr(fw_path, "_p2p") != NULL) {
+	if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || (op_mode == 0x04) ||
+		(dhd_concurrent_fw(dhd))) {
 		bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
 		if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
 			iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
@@ -2906,7 +3025,7 @@
 
 #if !defined(AP) && defined(WL_CFG80211)
 	/* Check if firmware with HostAPD support used */
-	if (strstr(fw_path, "_apsta") != NULL) {
+	if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) {
 			/* Turn off MPC in AP mode */
 			bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
 			if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
@@ -3016,6 +3135,8 @@
 	setbit(eventmask, WLC_E_LINK);
 	setbit(eventmask, WLC_E_NDIS_LINK);
 	setbit(eventmask, WLC_E_MIC_ERROR);
+	setbit(eventmask, WLC_E_ASSOC_REQ_IE);
+	setbit(eventmask, WLC_E_ASSOC_RESP_IE);
 	setbit(eventmask, WLC_E_PMKID_CACHE);
 	setbit(eventmask, WLC_E_TXFAIL);
 	setbit(eventmask, WLC_E_JOIN_START);
@@ -3136,26 +3257,6 @@
 	return ret;
 }
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
-static struct net_device_ops dhd_ops_pri = {
-	.ndo_open = dhd_open,
-	.ndo_stop = dhd_stop,
-	.ndo_get_stats = dhd_get_stats,
-	.ndo_do_ioctl = dhd_ioctl_entry,
-	.ndo_start_xmit = dhd_start_xmit,
-	.ndo_set_mac_address = dhd_set_mac_address,
-	.ndo_set_multicast_list = dhd_set_multicast_list,
-};
-
-static struct net_device_ops dhd_ops_virt = {
-	.ndo_get_stats = dhd_get_stats,
-	.ndo_do_ioctl = dhd_ioctl_entry,
-	.ndo_start_xmit = dhd_start_xmit,
-	.ndo_set_mac_address = dhd_set_mac_address,
-	.ndo_set_multicast_list = dhd_set_multicast_list,
-};
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
-
 int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
 {
 	struct dhd_info *dhd = dhdp->info;
@@ -3259,9 +3360,13 @@
 			DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
 				__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
 
-			/* firmware not downloaded, do nothing */
-			if (dhd->pub.busstate == DHD_BUS_DOWN) {
-				DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__));
+			if (dhd->pub.busstate != DHD_BUS_DATA) {
+				DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
+				if (dhd->pend_ipaddr) {
+					DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
+						__FUNCTION__, dhd->pend_ipaddr));
+				}
+				dhd->pend_ipaddr = ifa->ifa_address;
 				break;
 			}
 
@@ -3279,7 +3384,7 @@
 		case NETDEV_DOWN:
 			DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
 				__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
-
+			dhd->pend_ipaddr = 0;
 #ifdef AOE_IP_ALIAS_SUPPORT
 		if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
 				DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
@@ -3353,7 +3458,8 @@
 		 * portable hotspot.  This will not work in simultaneous AP/STA mode,
 		 * nor with P2P.  Need to set the Donlge's MAC address, and then use that.
 		 */
-		if (ifidx > 0) {
+		if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
+			ETHER_ADDR_LEN)) {
 			DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
 			__func__, net->name));
 			temp_addr[0] |= 0x02;
@@ -3480,7 +3586,7 @@
 	}
 #endif /* defined(CONFIG_WIRELESS_EXT) */
 
-	if (&dhd->thr_sysioc_ctl.thr_pid >= 0) {
+	if (dhd->thr_sysioc_ctl.thr_pid >= 0) {
 		PROC_STOP(&dhd->thr_sysioc_ctl);
 	}
 
@@ -3490,13 +3596,15 @@
 		dhd_if_t *ifp;
 
 		/* Cleanup virtual interfaces */
-		for (i = 1; i < DHD_MAX_IFS; i++)
+		for (i = 1; i < DHD_MAX_IFS; i++) {
+			dhd_net_if_lock_local(dhd);
 			if (dhd->iflist[i]) {
 				dhd->iflist[i]->state = DHD_IF_DEL;
 				dhd->iflist[i]->idx = i;
 				dhd_op_if(dhd->iflist[i]);
 			}
-
+			dhd_net_if_unlock_local(dhd);
+		}
 		/*  delete primary interface 0 */
 		ifp = dhd->iflist[0];
 		ASSERT(ifp);
@@ -3547,7 +3655,7 @@
 
 #ifdef WL_CFG80211
 	if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
-		wl_cfg80211_detach();
+		wl_cfg80211_detach(NULL);
 		dhd_monitor_uninit();
 	}
 #endif
@@ -3594,7 +3702,6 @@
 	dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
 }
 
-
 static int __init
 dhd_module_init(void)
 {
@@ -3653,7 +3760,7 @@
 		}
 #endif
 #if defined(WL_CFG80211)
-	error = wl_android_post_init();
+	wl_android_post_init();
 #endif
 
 	return error;
@@ -3672,7 +3779,11 @@
 	return error;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
 late_initcall(dhd_module_init);
+#else
+module_init(dhd_module_init);
+#endif
 module_exit(dhd_module_cleanup);
 
 /*
@@ -3915,7 +4026,7 @@
 	dhd_os_sdunlock(pub);
 }
 
-#if defined(DHD_USE_STATIC_BUF)
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
 uint8* dhd_os_prealloc(void *osh, int section, uint size)
 {
 	return (uint8*)wl_android_prealloc(section, size);
@@ -3924,7 +4035,7 @@
 void dhd_os_prefree(void *osh, void *addr, uint size)
 {
 }
-#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
 
 #if defined(CONFIG_WIRELESS_EXT)
 struct iw_statistics *
@@ -3973,7 +4084,13 @@
 #endif /* defined(CONFIG_WIRELESS_EXT)  */
 
 #ifdef WL_CFG80211
-
+	if ((ntoh32(event->event_type) == WLC_E_IF) &&
+		(((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD))
+		/* If ADD_IF has been called directly by wl utility then we
+		 * should not report this. In case if ADD_IF was called from
+		 * CFG stack, then too this event need not be reported back
+		 */
+		return (BCME_OK);
 	if ((wl_cfg80211_is_progress_ifchange() ||
 		wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) {
 		/*
@@ -4282,6 +4399,8 @@
 #endif
 #if defined(WL_CFG80211)
 			ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+			dev_close(dev);
+			dev_open(dev);
 #endif
 		}
 	}
@@ -4421,7 +4540,7 @@
 #ifdef CONFIG_HAS_WAKELOCK
 		if (dhd->wakelock_timeout_enable)
 			wake_lock_timeout(&dhd->wl_rxwake,
-				dhd->wakelock_timeout_enable * HZ);
+				msecs_to_jiffies(dhd->wakelock_timeout_enable));
 #endif
 		dhd->wakelock_timeout_enable = 0;
 		spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
@@ -4530,15 +4649,6 @@
 	return 0;
 }
 
-int dhd_os_check_if_up(void *dhdp)
-{
-	dhd_pub_t *pub = (dhd_pub_t *)dhdp;
-
-	if (!pub)
-		return 0;
-	return pub->up;
-}
-
 int net_os_wake_unlock(struct net_device *dev)
 {
 	dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4549,6 +4659,15 @@
 	return ret;
 }
 
+int dhd_os_check_if_up(void *dhdp)
+{
+	dhd_pub_t *pub = (dhd_pub_t *)dhdp;
+
+	if (!pub)
+		return 0;
+	return pub->up;
+}
+
 int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
 {
 	int ifidx;
@@ -4588,8 +4707,8 @@
 	uint8 iftype, uint8* ea);
 extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits);
 
-int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype,
-	uint8* ea)
+int dhd_wlfc_interface_event(struct dhd_info *dhd,
+	ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
 {
 	if (dhd->pub.wlfc_state == NULL)
 		return BCME_OK;
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index 2930115..d782316 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_sdio.c 288105 2011-10-06 01:58:02Z $
+ * $Id: dhd_sdio.c 309234 2012-01-19 01:44:16Z $
  */
 
 #include <typedefs.h>
@@ -382,7 +382,7 @@
 
 /* To check if there's window offered */
 #define DATAOK(bus) \
-	(((uint8)(bus->tx_max - bus->tx_seq) > 2) && \
+	(((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
 	(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
 
 /* To check if there's window offered for ctrl frame */
@@ -851,8 +851,10 @@
 		                 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
 
 		/* Isolate the bus */
-		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
-		                 SBSDIO_DEVCTL_PADS_ISO, NULL);
+		if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
+			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
+				SBSDIO_DEVCTL_PADS_ISO, NULL);
+		}
 
 		/* Change state */
 		bus->sleeping = TRUE;
@@ -1366,9 +1368,7 @@
 		/* Send from dpc */
 		bus->ctrl_frame_buf = frame;
 		bus->ctrl_frame_len = len;
-
 		dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
-
 		if (bus->ctrl_frame_stat == FALSE) {
 			DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
 			ret = 0;
@@ -1520,7 +1520,7 @@
 #ifdef DHD_DEBUG
 	IOV_CHECKDIED,
 	IOV_SERIALCONS,
-#endif
+#endif /* DHD_DEBUG */
 	IOV_DOWNLOAD,
 	IOV_SOCRAM_STATE,
 	IOV_FORCEEVEN,
@@ -2785,6 +2785,9 @@
 	uint retries;
 	int bcmerror = 0;
 
+	if (!bus->sih)
+		return BCME_ERROR;
+
 	/* To enter download state, disable ARM and reset SOCRAM.
 	 * To exit download state, simply reset ARM (default is RAM boot).
 	 */
@@ -3565,7 +3568,7 @@
 		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
 			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
 			           __FUNCTION__, txmax, bus->tx_seq));
-			txmax = bus->tx_seq;
+			txmax = bus->tx_max;
 		}
 		bus->tx_max = txmax;
 
@@ -3766,6 +3769,14 @@
 	     !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
 	     rxseq++, rxleft--) {
 
+#ifdef DHDTHREAD
+		/* tx more to improve rx performance */
+		if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
+			pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
+			dhdsdio_sendfromq(bus, dhd_txbound);
+		}
+#endif /* DHDTHREAD */
+
 		/* Handle glomming separately */
 		if (bus->glom || bus->glomd) {
 			uint8 cnt;
@@ -3986,7 +3997,7 @@
 			if ((uint8)(txmax - bus->tx_seq) > 0x40) {
 					DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
 						__FUNCTION__, txmax, bus->tx_seq));
-					txmax = bus->tx_seq;
+					txmax = bus->tx_max;
 			}
 			bus->tx_max = txmax;
 
@@ -4143,7 +4154,7 @@
 		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
 			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
 			           __FUNCTION__, txmax, bus->tx_seq));
-			txmax = bus->tx_seq;
+			txmax = bus->tx_max;
 		}
 		bus->tx_max = txmax;
 
@@ -5183,16 +5194,17 @@
 		return TRUE;
 	if (chipid == BCM4319_CHIP_ID)
 		return TRUE;
-	if (chipid == BCM4336_CHIP_ID)
-		return TRUE;
 	if (chipid == BCM4330_CHIP_ID)
 		return TRUE;
+	if (chipid == BCM43239_CHIP_ID)
+		return TRUE;
+	if (chipid == BCM4336_CHIP_ID)
+		return TRUE;
 	if (chipid == BCM43237_CHIP_ID)
 		return TRUE;
 	if (chipid == BCM43362_CHIP_ID)
 		return TRUE;
-	if (chipid == BCM43239_CHIP_ID)
-		return TRUE;
+
 	return FALSE;
 }
 
@@ -5369,6 +5381,7 @@
 		if (ret == BCME_NOTUP)
 			goto fail;
 	}
+
 	/* Ok, have the per-port tell the stack we're open for business */
 	if (dhd_net_attach(bus->dhd, 0) != 0) {
 		DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
@@ -5545,8 +5558,10 @@
 	return TRUE;
 
 fail:
-	if (bus->sih != NULL)
+	if (bus->sih != NULL) {
 		si_detach(bus->sih);
+		bus->sih = NULL;
+	}
 	return FALSE;
 }
 
@@ -5736,7 +5751,7 @@
 		return;
 
 	if (bus->rxbuf) {
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
 		MFREE(osh, bus->rxbuf, bus->rxblen);
 #endif
 		bus->rxctl = bus->rxbuf = NULL;
@@ -5744,7 +5759,7 @@
 	}
 
 	if (bus->databuf) {
-#ifndef DHD_USE_STATIC_BUF
+#ifndef CONFIG_DHD_USE_STATIC_BUF
 		MFREE(osh, bus->databuf, MAX_DATA_BUF);
 #endif
 		bus->databuf = NULL;
@@ -5779,6 +5794,7 @@
 			dhdsdio_clkctl(bus, CLK_NONE, FALSE);
 		}
 		si_detach(bus->sih);
+		bus->sih = NULL;
 		if (bus->vars && bus->varsz)
 			MFREE(osh, bus->vars, bus->varsz);
 		bus->vars = NULL;
diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
index 59d018b..c4d2518 100644
--- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h
+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
@@ -18,7 +18,7 @@
 *      Notwithstanding the above, under no circumstances may you combine this
 * software in any way with any other Broadcom software provided under a license
 * other than the GPL, without Broadcom's express prior written consent.
-* $Id: dhd_wlfc.h,v 1.1.8.1 2010-09-09 22:41:08 Exp $
+* $Id: dhd_wlfc.h 286994 2011-09-29 21:27:44Z $
 *
 */
 #ifndef __wlfc_host_driver_definitions_h__
@@ -201,6 +201,7 @@
 #define WLFC_FCMODE_IMPLIED_CREDIT		1
 #define WLFC_FCMODE_EXPLICIT_CREDIT		2
 
+/* How long to defer borrowing in milliseconds */
 #define WLFC_BORROW_DEFER_PERIOD_MS 100
 
 /* Mask to represent available ACs (note: BC/MC is ignored */
@@ -261,6 +262,15 @@
 
 	/* Timestamp to compute how long to defer borrowing for */
 	uint32  borrow_defer_timestamp;
+
 } athost_wl_status_info_t;
 
+int dhd_wlfc_enable(dhd_pub_t *dhd);
+int dhd_wlfc_interface_event(struct dhd_info *,
+	ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea);
+int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data);
+int dhd_wlfc_event(struct dhd_info *dhd);
+int dhd_os_wlfc_block(dhd_pub_t *pub);
+int dhd_os_wlfc_unblock(dhd_pub_t *pub);
+
 #endif /* __wlfc_host_driver_definitions_h__ */
diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c
index b9586e4..0e49334 100644
--- a/drivers/net/wireless/bcmdhd/hndpmu.c
+++ b/drivers/net/wireless/bcmdhd/hndpmu.c
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 Exp $
+ * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 $
  */
 
 #include <typedefs.h>
@@ -93,26 +93,8 @@
 	{0, 0x1} };
 
 /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */
-static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v2[] = {
-	{16, 0x3},
-	{13, 0x2},
-	{11, 0x1},
-	{8, 0x0},
-	{6, 0x7},
-	{4, 0x6},
-	{2, 0x5},
-	{0, 0x4} };
 
 /* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */
-static const sdiod_drive_str_t sdiod_drive_strength_tab4_2v5[] = {
-	{80, 0x5},
-	{65, 0x4},
-	{55, 0x7},
-	{40, 0x6},
-	{30, 0x1},
-	{20, 0x0},
-	{10, 0x3},
-	{0, 0x2} };
 
 /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
 static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = {
@@ -125,14 +107,6 @@
 	{0, 0x0} };
 
 /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */
-static const sdiod_drive_str_t sdiod_drive_strength_tab5_3v3[] = {
-	{12, 0x7},
-	{10, 0x6},
-	{8, 0x5},
-	{6, 0x4},
-	{4, 0x2},
-	{2, 0x1},
-	{0, 0x0} };
 
 
 #define SDIOD_DRVSTR_KEY(chip, pmu)	(((chip) << 16) | (pmu))
diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile
index c07266f..67c4906 100644
--- a/drivers/net/wireless/bcmdhd/include/Makefile
+++ b/drivers/net/wireless/bcmdhd/include/Makefile
@@ -10,7 +10,7 @@
 #
 # Copyright 2005, Broadcom, Inc.
 #
-# $Id: Makefile 241702 2011-02-19 00:41:03Z automrgr $
+# $Id: Makefile 241702 2011-02-19 00:41:03Z $
 #
 
 SRCBASE := ..
diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h
index 375df44..b993a03 100644
--- a/drivers/net/wireless/bcmdhd/include/aidmp.h
+++ b/drivers/net/wireless/bcmdhd/include/aidmp.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: aidmp.h,v 13.4.14.1 2010-03-09 18:40:06 Exp $
+ * $Id: aidmp.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
index ce45c50..77a20f8 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmcdc.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmcdc.h,v 13.25.10.3 2010-12-22 23:47:26 Exp $
+ * $Id: bcmcdc.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef _bcmcdc_h_
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
index da1fd5e..17cc0e9 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmdefs.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmdefs.h,v 13.68.2.8 2011-01-08 04:04:19 Exp $
+ * $Id: bcmdefs.h 279282 2011-08-23 22:44:02Z $
  */
 
 
@@ -30,12 +30,26 @@
 
 
 
+
+#define BCM_REFERENCE(data)	((void)(data))
+
+
+
 #define bcmreclaimed 		0
 #define _data	_data
 #define _fn	_fn
+#define BCMPREATTACHDATA(_data)	_data
+#define BCMPREATTACHFN(_fn)	_fn
 #define _data	_data
 #define _fn		_fn
 #define _fn	_fn
+#define	BCMNMIATTACHFN(_fn)	_fn
+#define	BCMNMIATTACHDATA(_data)	_data
+#define BCMOVERLAY0DATA(_sym)	_sym
+#define BCMOVERLAY0FN(_fn)	_fn
+#define BCMOVERLAY1DATA(_sym)	_sym
+#define BCMOVERLAY1FN(_fn)	_fn
+#define BCMOVERLAYERRFN(_fn)	_fn
 #define CONST	const
 #define BCMFASTPATH
 
@@ -43,9 +57,30 @@
 
 
 #define _data	_data
+#define BCMROMDAT_NAME(_data)	_data
 #define _fn		_fn
 #define _fn	_fn
 #define STATIC	static
+#define BCMROMDAT_ARYSIZ(data)	ARRAYSIZE(data)
+#define BCMROMDAT_SIZEOF(data)	sizeof(data)
+#define BCMROMDAT_APATCH(data)
+#define BCMROMDAT_SPATCH(data)
+
+
+
+#define OVERLAY_INLINE
+#define OSTATIC			static
+#define BCMOVERLAYDATA(_ovly, _sym)	_sym
+#define BCMOVERLAYFN(_ovly, _fn)	_fn
+#define BCMOVERLAYERRFN(_fn)	_fn
+#define BCMROMOVERLAYDATA(_ovly, _data)	_data
+#define BCMROMOVERLAYFN(_ovly, _fn)		_fn
+#define BCMATTACHOVERLAYDATA(_ovly, _sym)	_sym
+#define BCMATTACHOVERLAYFN(_ovly, _fn)		_fn
+#define BCMINITOVERLAYDATA(_ovly, _sym)		_sym
+#define BCMINITOVERLAYFN(_ovly, _fn)		_fn
+#define BCMUNINITOVERLAYFN(_ovly, _fn)		_fn
+
 
 
 #define	SI_BUS			0	
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
index 4f707c0..ee01d8b 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmdevs.h,v 13.285.2.39 2011-02-04 05:03:16 Exp $
+ * $Id: bcmdevs.h 295140 2011-11-09 17:22:01Z $
  */
 
 
@@ -31,7 +31,16 @@
 
 #define	VENDOR_EPIGRAM		0xfeda
 #define	VENDOR_BROADCOM		0x14e4
+#define	VENDOR_3COM		0x10b7
+#define	VENDOR_NETGEAR		0x1385
+#define	VENDOR_DIAMOND		0x1092
+#define	VENDOR_INTEL		0x8086
+#define	VENDOR_DELL		0x1028
+#define	VENDOR_HP		0x103c
+#define	VENDOR_HP_COMPAQ	0x0e11
+#define	VENDOR_APPLE		0x106b
 #define VENDOR_SI_IMAGE		0x1095		
+#define VENDOR_BUFFALO		0x1154		
 #define VENDOR_TI		0x104c		
 #define VENDOR_RICOH		0x1180		
 #define VENDOR_JMICRON		0x197b
@@ -54,9 +63,37 @@
 #define BCM_DNGL_BL_PID_43239   0xbd1b
 #define BCM_DNGL_BDC_PID	0x0bdc
 #define BCM_DNGL_JTAG_PID	0x4a44
+
+
+#define BCM_HWUSB_PID_43239     43239
+
+
+#define	BCM4210_DEVICE_ID	0x1072		
+#define	BCM4230_DEVICE_ID	0x1086		
+#define	BCM4401_ENET_ID		0x170c		
+#define	BCM3352_DEVICE_ID	0x3352		
+#define	BCM3360_DEVICE_ID	0x3360		
+#define	BCM4211_DEVICE_ID	0x4211
+#define	BCM4231_DEVICE_ID	0x4231
+#define	BCM4303_D11B_ID		0x4303		
+#define	BCM4311_D11G_ID		0x4311		
+#define	BCM4311_D11DUAL_ID	0x4312		
+#define	BCM4311_D11A_ID		0x4313		
+#define	BCM4328_D11DUAL_ID	0x4314		
+#define	BCM4328_D11G_ID		0x4315		
+#define	BCM4328_D11A_ID		0x4316		
+#define	BCM4318_D11G_ID		0x4318		
+#define	BCM4318_D11DUAL_ID	0x4319		
+#define	BCM4318_D11A_ID		0x431a		
 #define	BCM4325_D11DUAL_ID	0x431b		
 #define	BCM4325_D11G_ID		0x431c		
 #define	BCM4325_D11A_ID		0x431d		
+#define	BCM4306_D11G_ID		0x4320		
+#define	BCM4306_D11A_ID		0x4321		
+#define	BCM4306_UART_ID		0x4322		
+#define	BCM4306_V90_ID		0x4323		
+#define	BCM4306_D11DUAL_ID	0x4324		
+#define	BCM4306_D11G_ID2	0x4325		
 #define	BCM4321_D11N_ID		0x4328		
 #define	BCM4321_D11N2G_ID	0x4329		
 #define	BCM4321_D11N5G_ID	0x432a		
@@ -98,17 +135,58 @@
 #define BCM43237_D11N5G_ID	0x4356		
 #define BCM43227_D11N2G_ID	0x4358		
 #define BCM43228_D11N_ID		0x4359		
-#define BCM43228_D11N5G_ID	0x435a		 
+#define BCM43228_D11N5G_ID	0x435a		
 #define BCM43362_D11N_ID	0x4363		
 #define BCM43239_D11N_ID	0x4370		
+#define BCM4324_D11N_ID		0x4374		
+#define BCM43217_D11N2G_ID	0x43a9		
+#define BCM43131_D11N2G_ID	0x43aa		
 
+#define BCM4314_D11N2G_ID	0x4364		
+#define BCM43142_D11N2G_ID	0x4365		
 
+#define	BCMGPRS_UART_ID		0x4333		
+#define	BCMGPRS2_UART_ID	0x4344		
+#define FPGA_JTAGM_ID		0x43f0		
+#define BCM_JTAGM_ID		0x43f1		
 #define SDIOH_FPGA_ID		0x43f2		
+#define BCM_SDIOH_ID		0x43f3		
+#define SDIOD_FPGA_ID		0x43f4		
 #define SPIH_FPGA_ID		0x43f5		
+#define BCM_SPIH_ID		0x43f6		
+#define MIMO_FPGA_ID		0x43f8		
+#define BCM_JTAGM2_ID		0x43f9		
+#define SDHCI_FPGA_ID		0x43fa		
+#define	BCM4402_ENET_ID		0x4402		
+#define	BCM4402_V90_ID		0x4403		
+#define	BCM4410_DEVICE_ID	0x4410		
+#define	BCM4412_DEVICE_ID	0x4412		
+#define	BCM4430_DEVICE_ID	0x4430		
+#define	BCM4432_DEVICE_ID	0x4432		
+#define	BCM4704_ENET_ID		0x4706		
 #define	BCM4710_DEVICE_ID	0x4710		
+#define	BCM47XX_AUDIO_ID	0x4711		
+#define	BCM47XX_V90_ID		0x4712		
+#define	BCM47XX_ENET_ID		0x4713		
+#define	BCM47XX_EXT_ID		0x4714		
+#define	BCM47XX_GMAC_ID		0x4715		
+#define	BCM47XX_USBH_ID		0x4716		
+#define	BCM47XX_USBD_ID		0x4717		
+#define	BCM47XX_IPSEC_ID	0x4718		
+#define	BCM47XX_ROBO_ID		0x4719		
+#define	BCM47XX_USB20H_ID	0x471a		
+#define	BCM47XX_USB20D_ID	0x471b		
+#define	BCM47XX_ATA100_ID	0x471d		
+#define	BCM47XX_SATAXOR_ID	0x471e		
+#define	BCM47XX_GIGETH_ID	0x471f		
+#define	BCM4712_MIPS_ID		0x4720		
+#define	BCM4716_DEVICE_ID	0x4722		
+#define BCM47XX_SMBUS_EMU_ID	0x47fe		
+#define	BCM47XX_XOR_EMU_ID	0x47ff		
+#define	EPI41210_DEVICE_ID	0xa0fa		
+#define	EPI41230_DEVICE_ID	0xa10e		
+#define JINVANI_SDIOH_ID	0x4743		
 #define BCM27XX_SDIOH_ID	0x2702		
-#define PCIXX21_FLASHMEDIA0_ID	0x8033		
-#define PCIXX21_SDIOH0_ID	0x8034		
 #define PCIXX21_FLASHMEDIA_ID	0x803b		
 #define PCIXX21_SDIOH_ID	0x803c		
 #define R5C822_SDIOH_ID		0x0822		
@@ -121,11 +199,13 @@
 #define	BCM43112_CHIP_ID	43112		
 #define	BCM4312_CHIP_ID		0x4312		
 #define BCM4313_CHIP_ID		0x4313		
+#define	BCM43131_CHIP_ID	43131		
 #define	BCM4315_CHIP_ID		0x4315		
 #define	BCM4318_CHIP_ID		0x4318		
 #define	BCM4319_CHIP_ID		0x4319		
 #define	BCM4320_CHIP_ID		0x4320		
 #define	BCM4321_CHIP_ID		0x4321		
+#define	BCM43217_CHIP_ID	43217		
 #define	BCM4322_CHIP_ID		0x4322		
 #define	BCM43221_CHIP_ID	43221		
 #define	BCM43222_CHIP_ID	43222		
@@ -152,15 +232,28 @@
 #define BCM4336_CHIP_ID		0x4336		
 #define BCM43362_CHIP_ID	43362		
 #define BCM4330_CHIP_ID		0x4330		
+#define BCM6362_CHIP_ID		0x6362		
+#define BCM4314_CHIP_ID		0x4314		
+#define BCM43142_CHIP_ID	43142		
+#define BCM4324_CHIP_ID		0x4324		
+
+#define	BCM4342_CHIP_ID		4342		
 #define	BCM4402_CHIP_ID		0x4402		
 #define	BCM4704_CHIP_ID		0x4704		
 #define	BCM4710_CHIP_ID		0x4710		
 #define	BCM4712_CHIP_ID		0x4712		
+#define	BCM4716_CHIP_ID		0x4716		
+#define	BCM47162_CHIP_ID	47162		
+#define	BCM4748_CHIP_ID		0x4748		
+#define	BCM4749_CHIP_ID		0x4749		
 #define BCM4785_CHIP_ID		0x4785		
 #define	BCM5350_CHIP_ID		0x5350		
 #define	BCM5352_CHIP_ID		0x5352		
 #define	BCM5354_CHIP_ID		0x5354		
 #define BCM5365_CHIP_ID		0x5365		
+#define	BCM5356_CHIP_ID		0x5356		
+#define	BCM5357_CHIP_ID		0x5357		
+#define	BCM53572_CHIP_ID	53572		
 
 
 #define	BCM4303_PKG_ID		2		
@@ -175,8 +268,478 @@
 #define BCM4329_289PIN_PKG_ID	0		
 #define BCM4329_182PIN_PKG_ID	1		
 #define BCM5354E_PKG_ID		1		
+#define	BCM4716_PKG_ID		8		
+#define	BCM4717_PKG_ID		9		
+#define	BCM4718_PKG_ID		10		
+#define BCM5356_PKG_NONMODE	1		
+#define BCM5358U_PKG_ID		8		
+#define BCM5358_PKG_ID		9		
+#define BCM47186_PKG_ID		10		
+#define BCM5357_PKG_ID		11		
+#define BCM5356U_PKG_ID		12		
+#define BCM53572_PKG_ID		8		
+#define BCM47188_PKG_ID		9		
+#define BCM4331TT_PKG_ID        8		
+#define BCM4331TN_PKG_ID        9		
+#define BCM4331TNA0_PKG_ID     0xb		
+
+
 #define HDLSIM5350_PKG_ID	1		
 #define HDLSIM_PKG_ID		14		
 #define HWSIM_PKG_ID		15		
+#define BCM43224_FAB_CSM	0x8		
+#define BCM43224_FAB_SMIC	0xa		
+#define BCM4336_WLBGA_PKG_ID	0x8
+#define BCM4330_WLBGA_PKG_ID	0x0
+#define BCM4314PCIE_ARM_PKG_ID		(8 | 0)	
+#define BCM4314SDIO_PKG_ID		(8 | 1)	
+#define BCM4314PCIE_PKG_ID		(8 | 2)	
+#define BCM4314SDIO_ARM_PKG_ID		(8 | 3)	
+#define BCM4314SDIO_FPBGA_PKG_ID	(8 | 4)	
+#define BCM4314DEV_PKG_ID		(8 | 6)	
+
+#define PCIXX21_FLASHMEDIA0_ID	0x8033		
+#define PCIXX21_SDIOH0_ID	0x8034		
+
+
+#define	BFL_BTC2WIRE		0x00000001  
+#define BFL_BTCOEX      0x00000001      
+#define	BFL_PACTRL		0x00000002  
+#define BFL_AIRLINEMODE	0x00000004  
+#define	BFL_ADCDIV		0x00000008  
+#define	BFL_ENETROBO		0x00000010  
+#define	BFL_NOPLLDOWN		0x00000020  
+#define	BFL_CCKHIPWR		0x00000040  
+#define	BFL_ENETADM		0x00000080  
+#define	BFL_ENETVLAN		0x00000100  
+#ifdef WLAFTERBURNER
+#define	BFL_AFTERBURNER		0x00000200  
+#endif 
+#define BFL_NOPCI		0x00000400  
+#define BFL_FEM			0x00000800  
+#define BFL_EXTLNA		0x00001000  
+#define BFL_HGPA		0x00002000  
+#define	BFL_BTC2WIRE_ALTGPIO	0x00004000  
+#define	BFL_ALTIQ		0x00008000  
+#define BFL_NOPA		0x00010000  
+#define BFL_RSSIINV		0x00020000  
+#define BFL_PAREF		0x00040000  
+#define BFL_3TSWITCH		0x00080000  
+#define BFL_PHASESHIFT		0x00100000  
+#define BFL_BUCKBOOST		0x00200000  
+#define BFL_FEM_BT		0x00400000  
+#define BFL_NOCBUCK		0x00800000  
+#define BFL_CCKFAVOREVM		0x01000000  
+#define BFL_PALDO		0x02000000  
+#define BFL_LNLDO2_2P5		0x04000000  
+#define BFL_FASTPWR		0x08000000
+#define BFL_UCPWRCTL_MININDX	0x08000000  
+#define BFL_EXTLNA_5GHz		0x10000000  
+#define BFL_TRSW_1by2		0x20000000  
+#define BFL_LO_TRSW_R_5GHz	0x40000000  
+#define BFL_ELNA_GAINDEF	0x80000000  
+#define BFL_EXTLNA_TX	0x20000000	
+
+
+#define BFL2_RXBB_INT_REG_DIS	0x00000001  
+#define BFL2_APLL_WAR		0x00000002  
+#define BFL2_TXPWRCTRL_EN	0x00000004  
+#define BFL2_2X4_DIV		0x00000008  
+#define BFL2_5G_PWRGAIN		0x00000010  
+#define BFL2_PCIEWAR_OVR	0x00000020  
+#define BFL2_CAESERS_BRD	0x00000040  
+#define BFL2_BTC3WIRE		0x00000080  
+#define BFL2_BTCLEGACY          0x00000080  
+#define BFL2_SKWRKFEM_BRD	0x00000100  
+#define BFL2_SPUR_WAR		0x00000200  
+#define BFL2_GPLL_WAR		0x00000400  
+#define BFL2_TRISTATE_LED	0x00000800  
+#define BFL2_SINGLEANT_CCK	0x00001000  
+#define BFL2_2G_SPUR_WAR	0x00002000  
+#define BFL2_BPHY_ALL_TXCORES	0x00004000  
+#define BFL2_FCC_BANDEDGE_WAR	0x00008000  
+#define BFL2_GPLL_WAR2	        0x00010000  
+#define BFL2_IPALVLSHIFT_3P3    0x00020000
+#define BFL2_INTERNDET_TXIQCAL  0x00040000  
+#define BFL2_XTALBUFOUTEN       0x00080000  
+#define BFL2_ANAPACTRL_2G	0x00100000  
+#define BFL2_ANAPACTRL_5G	0x00200000  
+#define BFL2_ELNACTRL_TRSW_2G	0x00400000  
+#define BFL2_BT_SHARE_ANT0	0x00800000  
+#define BFL2_TEMPSENSE_HIGHER	0x01000000  
+#define BFL2_BTC3WIREONLY       0x02000000  
+#define BFL2_PWR_NOMINAL	0x04000000  
+#define BFL2_EXTLNA_TX		0x08000000  
+						
+#define BFL2_4313_RADIOREG	0x10000000
+									   
+
+
+#define	BOARD_GPIO_BTC3W_IN	0x850	
+#define	BOARD_GPIO_BTC3W_OUT	0x020	
+#define	BOARD_GPIO_BTCMOD_IN	0x010	
+#define	BOARD_GPIO_BTCMOD_OUT	0x020	
+#define	BOARD_GPIO_BTC_IN	0x080	
+#define	BOARD_GPIO_BTC_OUT	0x100	
+#define	BOARD_GPIO_PACTRL	0x200	
+#define BOARD_GPIO_12		0x1000	
+#define BOARD_GPIO_13		0x2000	
+#define BOARD_GPIO_BTC4_IN	0x0800	
+#define BOARD_GPIO_BTC4_BT	0x2000	
+#define BOARD_GPIO_BTC4_STAT	0x4000	
+#define BOARD_GPIO_BTC4_WLAN	0x8000	
+#define	BOARD_GPIO_1_WLAN_PWR	0x2	
+#define	BOARD_GPIO_4_WLAN_PWR	0x10	
+
+#define GPIO_BTC4W_OUT_4312  0x010  
+#define GPIO_BTC4W_OUT_43224  0x020  
+#define GPIO_BTC4W_OUT_43224_SHARED  0x0e0  
+#define GPIO_BTC4W_OUT_43225  0x0e0  
+#define GPIO_BTC4W_OUT_43421  0x020  
+#define GPIO_BTC4W_OUT_4313  0x060  
+
+#define	PCI_CFG_GPIO_SCS	0x10	
+#define PCI_CFG_GPIO_HWRAD	0x20	
+#define PCI_CFG_GPIO_XTAL	0x40	
+#define PCI_CFG_GPIO_PLL	0x80	
+
+
+#define PLL_DELAY		150		
+#define FREF_DELAY		200		
+#define MIN_SLOW_CLK		32		
+#define	XTAL_ON_DELAY		1000		
+
+
+#define	BU4710_BOARD		0x0400
+#define	VSIM4710_BOARD		0x0401
+#define	QT4710_BOARD		0x0402
+
+#define	BU4309_BOARD		0x040a
+#define	BCM94309CB_BOARD	0x040b
+#define	BCM94309MP_BOARD	0x040c
+#define	BCM4309AP_BOARD		0x040d
+
+#define	BCM94302MP_BOARD	0x040e
+
+#define	BU4306_BOARD		0x0416
+#define	BCM94306CB_BOARD	0x0417
+#define	BCM94306MP_BOARD	0x0418
+
+#define	BCM94710D_BOARD		0x041a
+#define	BCM94710R1_BOARD	0x041b
+#define	BCM94710R4_BOARD	0x041c
+#define	BCM94710AP_BOARD	0x041d
+
+#define	BU2050_BOARD		0x041f
+
+#define	BCM94306P50_BOARD	0x0420
+
+#define	BCM94309G_BOARD		0x0421
+
+#define	BU4704_BOARD		0x0423
+#define	BU4702_BOARD		0x0424
+
+#define	BCM94306PC_BOARD	0x0425		
+
+#define	MPSG4306_BOARD		0x0427
+
+#define	BCM94702MN_BOARD	0x0428
+
+
+#define	BCM94702CPCI_BOARD	0x0429
+
+
+#define	BCM95380RR_BOARD	0x042a
+
+
+#define	BCM94306CBSG_BOARD	0x042b
+
+
+#define	PCSG94306_BOARD		0x042d
+
+
+#define	BU4704SD_BOARD		0x042e
+
+
+#define	BCM94704AGR_BOARD	0x042f
+
+
+#define	BCM94308MP_BOARD	0x0430
+
+
+#define	BCM94306GPRS_BOARD	0x0432
+
+
+#define BU5365_FPGA_BOARD	0x0433
+
+#define BU4712_BOARD		0x0444
+#define	BU4712SD_BOARD		0x045d
+#define	BU4712L_BOARD		0x045f
+
+
+#define BCM94712AP_BOARD	0x0445
+#define BCM94712P_BOARD		0x0446
+
+
+#define BU4318_BOARD		0x0447
+#define CB4318_BOARD		0x0448
+#define MPG4318_BOARD		0x0449
+#define MP4318_BOARD		0x044a
+#define SD4318_BOARD		0x044b
+
+
+#define BCM94313BU_BOARD	0x050f
+#define BCM94313HM_BOARD	0x0510
+#define BCM94313EPA_BOARD	0x0511
+#define BCM94313HMG_BOARD       0x051C
+
+
+#define BCM96338_BOARD		0x6338
+#define BCM96348_BOARD		0x6348
+#define BCM96358_BOARD		0x6358
+#define BCM96368_BOARD		0x6368
+
+
+#define	BCM94306P_BOARD		0x044c
+
+
+#define	BCM94303MP_BOARD	0x044e
+
+
+#define	BCM94306MPSGH_BOARD	0x044f
+
+
+#define BCM94306MPM		0x0450
+#define BCM94306MPL		0x0453
+
+
+#define	BCM94712AGR_BOARD	0x0451
+
+
+#define	PC4303_BOARD		0x0454
+
+
+#define	BCM95350K_BOARD		0x0455
+
+
+#define	BCM95350R_BOARD		0x0456
+
+
+#define	BCM94306MPLNA_BOARD	0x0457
+
+
+#define	BU4320_BOARD		0x0458
+#define	BU4320S_BOARD		0x0459
+#define	BCM94320PH_BOARD	0x045a
+
+
+#define	BCM94306MPH_BOARD	0x045b
+
+
+#define	BCM94306PCIV_BOARD	0x045c
+
+#define	BU4712SD_BOARD		0x045d
+
+#define	BCM94320PFLSH_BOARD	0x045e
+
+#define	BU4712L_BOARD		0x045f
+#define	BCM94712LGR_BOARD	0x0460
+#define	BCM94320R_BOARD		0x0461
+
+#define	BU5352_BOARD		0x0462
+
+#define	BCM94318MPGH_BOARD	0x0463
+
+#define	BU4311_BOARD		0x0464
+#define	BCM94311MC_BOARD	0x0465
+#define	BCM94311MCAG_BOARD	0x0466
+
+#define	BCM95352GR_BOARD	0x0467
+
+
+#define	BCM95351AGR_BOARD	0x0470
+
+
+#define	BCM94704MPCB_BOARD	0x0472
+
+
+#define BU4785_BOARD		0x0478
+
+
+#define BU4321_BOARD		0x046b
+#define BU4321E_BOARD		0x047c
+#define MP4321_BOARD		0x046c
+#define CB2_4321_BOARD		0x046d
+#define CB2_4321_AG_BOARD	0x0066
+#define MC4321_BOARD		0x046e
+
+
+#define BU4328_BOARD		0x0481
+#define BCM4328SDG_BOARD	0x0482
+#define BCM4328SDAG_BOARD	0x0483
+#define BCM4328UG_BOARD		0x0484
+#define BCM4328UAG_BOARD	0x0485
+#define BCM4328PC_BOARD		0x0486
+#define BCM4328CF_BOARD		0x0487
+
+
+#define BCM94325DEVBU_BOARD	0x0490
+#define BCM94325BGABU_BOARD	0x0491
+
+#define BCM94325SDGWB_BOARD	0x0492
+
+#define BCM94325SDGMDL_BOARD	0x04aa
+#define BCM94325SDGMDL2_BOARD	0x04c6
+#define BCM94325SDGMDL3_BOARD	0x04c9
+
+#define BCM94325SDABGWBA_BOARD	0x04e1
+
+
+#define BCM94322MC_SSID		0x04a4
+#define BCM94322USB_SSID	0x04a8	
+#define BCM94322HM_SSID		0x04b0
+#define BCM94322USB2D_SSID	0x04bf	
+
+
+#define	BCM4312MCGSG_BOARD	0x04b5
+
+
+#define BCM94315DEVBU_SSID	0x04c2
+#define BCM94315USBGP_SSID	0x04c7
+#define BCM94315BGABU_SSID	0x04ca
+#define BCM94315USBGP41_SSID	0x04cb
+
+
+#define BCM94319DEVBU_SSID	0X04e5
+#define BCM94319USB_SSID	0X04e6
+#define BCM94319SD_SSID		0X04e7
+
+
+#define BCM94716NR2_SSID	0x04cd
+
+
+#define BCM94319DEVBU_SSID	0X04e5
+#define BCM94319USBNP4L_SSID	0X04e6
+#define BCM94319WLUSBN4L_SSID	0X04e7
+#define BCM94319SDG_SSID	0X04ea
+#define BCM94319LCUSBSDN4L_SSID	0X04eb
+#define BCM94319USBB_SSID       0x04ee
+#define BCM94319LCSDN4L_SSID	0X0507
+#define BCM94319LSUSBN4L_SSID	0X0508
+#define BCM94319SDNA4L_SSID	0X0517
+#define BCM94319SDELNA4L_SSID	0X0518
+#define BCM94319SDELNA6L_SSID	0X0539
+#define BCM94319ARCADYAN_SSID	0X0546
+#define BCM94319WINDSOR_SSID    0x0561
+#define BCM94319MLAP_SSID       0x0562
+#define BCM94319SDNA_SSID       0x058b
+#define BCM94319BHEMU3_SSID     0x0563
+#define BCM94319SDHMB_SSID     0x058c
+#define BCM94319SDBREF_SSID     0x05a1
+#define BCM94319USBSDB_SSID     0x05a2
+
+
+
+#define BCM94329AGB_SSID	0X04b9
+#define BCM94329TDKMDL1_SSID	0X04ba
+#define BCM94329TDKMDL11_SSID	0X04fc
+#define BCM94329OLYMPICN18_SSID	0X04fd
+#define BCM94329OLYMPICN90_SSID	0X04fe
+#define BCM94329OLYMPICN90U_SSID 0X050c
+#define BCM94329OLYMPICN90M_SSID 0X050b
+#define BCM94329AGBF_SSID	0X04ff
+#define BCM94329OLYMPICX17_SSID	0X0504
+#define BCM94329OLYMPICX17M_SSID	0X050a
+#define BCM94329OLYMPICX17U_SSID	0X0509
+#define BCM94329OLYMPICUNO_SSID	0X0564
+#define BCM94329MOTOROLA_SSID   0X0565
+#define BCM94329OLYMPICLOCO_SSID	0X0568
+
+#define BCM94336SD_WLBGABU_SSID		0x0511
+#define BCM94336SD_WLBGAREF_SSID	0x0519
+#define BCM94336SDGP_SSID	0x0538
+#define BCM94336SDG_SSID	0x0519
+#define BCM94336SDGN_SSID	0x0538
+#define BCM94336SDGFC_SSID	0x056B
+
+
+#define BCM94330SDG_SSID	0x0528
+#define BCM94330SD_FCBGABU_SSID	0x052e
+#define BCM94330SD_WLBGABU_SSID	0x052f
+#define BCM94330SD_FCBGA_SSID	0x0530
+#define BCM94330FCSDAGB_SSID		0x0532
+#define BCM94330OLYMPICAMG_SSID		0x0549
+#define BCM94330OLYMPICAMGEPA_SSID		0x054F
+#define BCM94330OLYMPICUNO3_SSID	0x0551
+#define BCM94330WLSDAGB_SSID	0x0547
+#define BCM94330CSPSDAGBB_SSID	0x054A
+
+
+#define BCM943224X21        0x056e
+#define BCM943224X21_FCC    0x00d1
+
+
+#define BCM943228BU8_SSID	0x0540
+#define BCM943228BU9_SSID	0x0541
+#define BCM943228BU_SSID	0x0542
+#define BCM943227HM4L_SSID	0x0543
+#define BCM943227HMB_SSID	0x0544
+#define BCM943228HM4L_SSID	0x0545
+#define BCM943228SD_SSID	0x0573
+
+
+#define BCM943239MOD_SSID	0x05ac
+#define BCM943239REF_SSID	0x05aa
+
+
+#define BCM94331X19               0x00D6	
+#define BCM94331PCIEBT3Ax_SSID    0x00E4	
+#define BCM94331X12_2G_SSID       0x00EC	
+#define BCM94331X12_5G_SSID       0x00ED	
+#define BCM94331X29B              0x00EF	
+#define BCM94331BU_SSID           0x0523
+#define BCM94331S9BU_SSID         0x0524
+#define BCM94331MC_SSID           0x0525
+#define BCM94331MCI_SSID          0x0526
+#define BCM94331PCIEBT4_SSID      0x0527
+#define BCM94331HM_SSID           0x0574
+#define BCM94331PCIEDUAL_SSID     0x059B
+#define BCM94331MCH5_SSID         0x05A9
+#define BCM94331PCIEDUALV2_SSID   0x05B7
+#define BCM94331CS_SSID           0x05C6
+#define BCM94331CSAX_SSID         0x00EF
+
+
+#define BCM953572BU_SSID       0x058D
+#define BCM953572NR2_SSID      0x058E
+#define BCM947188NR2_SSID      0x058F
+#define BCM953572SDRNR2_SSID   0x0590
+
+
+#define BCM943236OLYMPICSULLEY_SSID 0x594
+#define BCM943236PREPROTOBLU2O3_SSID 0x5b9
+#define BCM943236USBELNA_SSID 0x5f8
+
+
+#define GPIO_NUMPINS		32
+
+
+#define RDL_RAM_BASE_4319 0x60000000
+#define RDL_RAM_BASE_4329 0x60000000
+#define RDL_RAM_SIZE_4319 0x48000
+#define RDL_RAM_SIZE_4329  0x48000
+#define RDL_RAM_SIZE_43236 0x70000
+#define RDL_RAM_BASE_43236 0x60000000
+#define RDL_RAM_SIZE_4328 0x60000
+#define RDL_RAM_BASE_4328 0x80000000
+#define RDL_RAM_SIZE_4322 0x60000
+#define RDL_RAM_BASE_4322 0x60000000
+
+
+#define MUXENAB_UART		0x00000001
+#define MUXENAB_GPIO		0x00000002
+#define MUXENAB_ERCX		0x00000004
+#define MUXENAB_JTAG		0x00000008
+#define MUXENAB_HOST_WAKE	0x00000010
 
 #endif 
diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h
index 04b07ec..f3356a7 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmendian.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmendian.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- *  $Id: bcmendian.h,v 1.36 2009-11-09 05:29:43 Exp $
+ *  $Id: bcmendian.h 277737 2011-08-16 17:54:59Z $
  *
  * This file by default provides proper behavior on little-endian architectures.
  * On big-endian architectures, IL_BIGENDIAN should be defined.
diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
index fd148c5..51e0427 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmpcispi.h,v 13.15.112.1 2010-11-15 18:22:12 Exp $
+ * $Id: bcmpcispi.h 277737 2011-08-16 17:54:59Z $
  */
 #ifndef	_BCM_PCI_SPI_H
 #define	_BCM_PCI_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h
index a3985cf..a503edb 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmperf.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmperf.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmperf.h,v 13.5 2007-09-14 22:00:59 Exp $
+ * $Id: bcmperf.h 277737 2011-08-16 17:54:59Z $
  */
 /* essai */
 #ifndef _BCMPERF_H_
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
index 5fda5e9..21a58b4 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdbus.h,v 13.17.86.2 2010-12-23 01:13:20 Exp $
+ * $Id: bcmsdbus.h 300017 2011-12-01 20:30:27Z $
  */
 
 #ifndef	_sdio_api_h_
@@ -117,4 +117,12 @@
 
 
 
+extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab);
+
+/* GPIO support */
+extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd);
+extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio);
+extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio);
+extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab);
+
 #endif /* _sdio_api_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
index 6131d8a..def3c02 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdh.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
@@ -23,7 +23,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh.h,v 13.46.52.3 2010-10-19 00:41:44 Exp $
+ * $Id: bcmsdh.h 300017 2011-12-01 20:30:27Z $
  */
 
 #ifndef	_bcmsdh_h_
@@ -208,4 +208,12 @@
 extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev);
 
 
+extern int bcmsdh_sleep(void *sdh, bool enab);
+
+/* GPIO support */
+extern int bcmsdh_gpio_init(void *sd);
+extern bool bcmsdh_gpioin(void *sd, uint32 gpio);
+extern int bcmsdh_gpioouten(void *sd, uint32 gpio);
+extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab);
+
 #endif	/* _bcmsdh_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
index d188c4e..bea97b6 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_sdmmc.h,v 13.5.88.1 2010-12-23 01:13:20 Exp $
+ * $Id: bcmsdh_sdmmc.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef __BCMSDH_SDMMC_H__
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
index ee29b5c..1b9d39f 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdpcm.h,v 13.4.90.2 2010-05-12 04:14:25 Exp $
+ * $Id: bcmsdpcm.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_bcmsdpcm_h_
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
index 0bff355..a62bee4 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdspi.h,v 13.11.86.1 2010-11-15 18:14:56 Exp $
+ * $Id: bcmsdspi.h 277737 2011-08-16 17:54:59Z $
  */
 #ifndef	_BCM_SD_SPI_H
 #define	_BCM_SD_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
index 0f4c026..c14444c 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdstd.h,v 13.21.2.6 2010-11-15 18:14:01 Exp $
+ * $Id: bcmsdstd.h 281604 2011-09-02 18:58:49Z $
  */
 #ifndef	_BCM_SD_STD_H
 #define	_BCM_SD_STD_H
@@ -78,6 +78,7 @@
 #define SDIOH_CMD7_EXP_STATUS   0x00001E00
 
 #define RETRIES_LARGE 100000
+#define sdstd_os_yield(sd)	do {} while (0)
 #define RETRIES_SMALL 100
 
 
@@ -148,8 +149,8 @@
 	bool		got_hcint;		/* local interrupt flag */
 	uint16		last_intrstatus;	/* to cache intrstatus */
 	int 	host_UHSISupported;		/* whether UHSI is supported for HC. */
-	int 	card_UHSI_voltage_Supported; 	/* whether UHSI is supported for 
-						 * Card in terms of Voltage [1.8 or 3.3]. 
+	int 	card_UHSI_voltage_Supported; 	/* whether UHSI is supported for
+						 * Card in terms of Voltage [1.8 or 3.3].
 						 */
 	int	global_UHSI_Supp;	/* type of UHSI support in both host and card.
 					 * HOST_SDR_UNSUPP: capabilities not supported/matched
@@ -171,21 +172,6 @@
 
 #define USE_DMA(sd)		((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE))
 
-/* SDIO Host Control Register DMA Mode Definitions */
-#define SDIOH_SDMA_MODE			0
-#define SDIOH_ADMA1_MODE		1
-#define SDIOH_ADMA2_MODE		2
-#define SDIOH_ADMA2_64_MODE		3
-
-#define ADMA2_ATTRIBUTE_VALID		(1 << 0)	/* ADMA Descriptor line valid */
-#define ADMA2_ATTRIBUTE_END			(1 << 1)	/* End of Descriptor */
-#define ADMA2_ATTRIBUTE_INT			(1 << 2)	/* Interrupt when line is done */
-#define ADMA2_ATTRIBUTE_ACT_NOP		(0 << 4)	/* Skip current line, go to next. */
-#define ADMA2_ATTRIBUTE_ACT_RSV		(1 << 4)	/* Same as NOP */
-#define ADMA1_ATTRIBUTE_ACT_SET		(1 << 4)	/* ADMA1 Only - set transfer length */
-#define ADMA2_ATTRIBUTE_ACT_TRAN	(2 << 4)	/* Transfer Data of one descriptor line. */
-#define ADMA2_ATTRIBUTE_ACT_LINK	(3 << 4)	/* Link Descriptor */
-
 /* States for Tuning and corr data */
 #define TUNING_IDLE 			0
 #define TUNING_START 			1
@@ -195,17 +181,6 @@
 #define DATA_TRANSFER_IDLE 		0
 #define DATA_TRANSFER_ONGOING	1
 
-/* ADMA2 Descriptor Table Entry for 32-bit Address */
-typedef struct adma2_dscr_32b {
-	uint32 len_attr;
-	uint32 phys_addr;
-} adma2_dscr_32b_t;
-
-/* ADMA1 Descriptor Table Entry */
-typedef struct adma1_dscr {
-	uint32 phys_addr_attr;
-} adma1_dscr_t;
-
 /************************************************************
  * Internal interfaces: per-port references into bcmsdstd.c
  */
@@ -254,6 +229,7 @@
 extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd);
 extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd);
 extern int sdstd_3_get_tune_state(sdioh_info_t *sd);
+extern int sdstd_3_get_data_state(sdioh_info_t *sd);
 extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state);
 extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd);
 extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd);
diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h
index 0eb2a30..34a02d0 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmspi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmspi.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmspi.h,v 13.5.112.1 2010-11-15 18:13:09 Exp $
+ * $Id: bcmspi.h 277737 2011-08-16 17:54:59Z $
  */
 #ifndef	_BCM_SPI_H
 #define	_BCM_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h
index 530036f..6849c26 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmutils.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmutils.h,v 13.236.2.16 2011-01-26 00:45:06 Exp $
+ * $Id: bcmutils.h 294991 2011-11-09 00:17:28Z $
  */
 
 
@@ -221,7 +221,9 @@
 extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg);
 extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg);
 extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen);
+extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen);
 extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable);
+extern bool pktpool_emptycb_disabled(pktpool_t *pktp);
 
 #define POOLPTR(pp)			((pktpool_t *)(pp))
 #define pktpool_len(pp)			(POOLPTR(pp)->len - 1)
@@ -330,6 +332,8 @@
 
 extern void bcm_mdelay(uint ms);
 
+#define NVRAM_RECLAIM_CHECK(name)
+
 extern char *getvar(char *vars, const char *name);
 extern int getintvar(char *vars, const char *name);
 extern int getintvararray(char *vars, const char *name, int index);
@@ -534,9 +538,17 @@
 	                                         & ~((boundary) - 1))
 #define	ISPOWEROF2(x)		((((x)-1)&(x)) == 0)
 #define VALID_MASK(mask)	!((mask) & ((mask) + 1))
+
 #ifndef OFFSETOF
+#ifdef __ARMCC_VERSION
+
+#include <stddef.h>
+#define	OFFSETOF(type, member)	offsetof(type, member)
+#else
 #define	OFFSETOF(type, member)	((uint)(uintptr)&((type *)0)->member)
 #endif 
+#endif 
+
 #ifndef ARRAYSIZE
 #define ARRAYSIZE(a)		(sizeof(a)/sizeof(a[0]))
 #endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi.h b/drivers/net/wireless/bcmdhd/include/bcmwifi.h
index 45f3c03..e5207e9 100644
--- a/drivers/net/wireless/bcmdhd/include/bcmwifi.h
+++ b/drivers/net/wireless/bcmdhd/include/bcmwifi.h
@@ -23,7 +23,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmwifi.h,v 1.29.6.3 2010-08-03 17:47:04 Exp $
+ * $Id: bcmwifi.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
index 9661dac..0312d22 100644
--- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
@@ -25,7 +25,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhdioctl.h,v 13.11.10.1 2010-12-22 23:47:26 Exp $
+ * $Id: dhdioctl.h 307573 2012-01-12 00:04:39Z $
  */
 
 #ifndef _dhdioctl_h_
@@ -87,6 +87,7 @@
 #define DHD_BTA_VAL	0x1000
 #define DHD_ISCAN_VAL	0x2000
 #define DHD_ARPOE_VAL	0x4000
+#define DHD_WL_VAL	0x8000
 
 #ifdef SDTEST
 /* For pktgen iovar */
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
index ae1f975..53dd2f7 100644
--- a/drivers/net/wireless/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -19,7 +19,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 $
+ * $Id: epivers.h.in 277737 2011-08-16 17:54:59Z $
  *
 */
 
@@ -31,19 +31,19 @@
 
 #define	EPI_MINOR_VERSION	90
 
-#define	EPI_RC_NUMBER		125
+#define	EPI_RC_NUMBER		195
 
-#define	EPI_INCREMENTAL_NUMBER	94
+#define	EPI_INCREMENTAL_NUMBER	23
 
 #define	EPI_BUILD_NUMBER	0
 
-#define	EPI_VERSION		5, 90, 125, 94
+#define	EPI_VERSION		5, 90, 195, 23
 
-#define	EPI_VERSION_NUM		0x055a7d5e
+#define	EPI_VERSION_NUM		0x055ac317
 
-#define EPI_VERSION_DEV		5.90.125
+#define EPI_VERSION_DEV		5.90.195
 
 
-#define	EPI_VERSION_STR		"5.90.125.94"
+#define	EPI_VERSION_STR		"5.90.195.23"
 
 #endif 
diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h
index 51c51b9..69a834c 100644
--- a/drivers/net/wireless/bcmdhd/include/hndpmu.h
+++ b/drivers/net/wireless/bcmdhd/include/hndpmu.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: hndpmu.h,v 13.35.8.5 2011-02-11 00:56:32 Exp $
+ * $Id: hndpmu.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef _hndpmu_h_
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
index 8b9615c..7d862c4 100644
--- a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: hndrte_armtrap.h,v 13.4.14.1 2011-02-05 00:04:30 Exp $
+ * $Id: hndrte_armtrap.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_hndrte_armtrap_h
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
index b9ede53..859ddc8 100644
--- a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: hndrte_cons.h,v 13.4.10.4 2011-02-05 00:08:20 Exp $
+ * $Id: hndrte_cons.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_HNDRTE_CONS_H
diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h
index 4e26121..34f927c 100644
--- a/drivers/net/wireless/bcmdhd/include/hndsoc.h
+++ b/drivers/net/wireless/bcmdhd/include/hndsoc.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: hndsoc.h,v 13.11 2009-12-03 23:52:31 Exp $
+ * $Id: hndsoc.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_HNDSOC_H
diff --git a/drivers/net/wireless/bcmdhd/include/htsf.h b/drivers/net/wireless/bcmdhd/include/htsf.h
index 379fbbe..d875edb 100644
--- a/drivers/net/wireless/bcmdhd/include/htsf.h
+++ b/drivers/net/wireless/bcmdhd/include/htsf.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: htsf.h,v 1.1.2.4 2011-01-21 08:27:03 Exp $
+ * $Id: htsf.h 277737 2011-08-16 17:54:59Z $
  */
 #ifndef _HTSF_H_
 #define _HTSF_H_
diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h
index 1ec136e..830d351 100644
--- a/drivers/net/wireless/bcmdhd/include/linux_osl.h
+++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: linux_osl.h,v 13.158.6.3 2010-12-22 23:47:26 Exp $
+ * $Id: linux_osl.h 301794 2011-12-08 20:41:35Z $
  */
 
 
@@ -268,7 +268,7 @@
 #define PKTLIST_DUMP(osh, buf)
 #define PKTDBG_TRACE(osh, pkt, bit)
 #define	PKTFREE(osh, skb, send)		osl_pktfree((osh), (skb), (send))
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 #define	PKTGET_STATIC(osh, len, send)		osl_pktget_static((osh), (len))
 #define	PKTFREE_STATIC(osh, skb, send)		osl_pktfree_static((osh), (skb), (send))
 #endif
diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h
index 96844db..d269e66 100644
--- a/drivers/net/wireless/bcmdhd/include/linuxver.h
+++ b/drivers/net/wireless/bcmdhd/include/linuxver.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: linuxver.h,v 13.53.2.2 2010-12-22 23:47:26 Exp $
+ * $Id: linuxver.h 280266 2011-08-28 04:18:20Z $
  */
 
 
@@ -482,7 +482,11 @@
 #define DBG_THR(x)
 #endif
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x)
+#else
 #define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x)
+#endif
 
 
 #define PROC_START(thread_func, owner, tsk_ctl, flags) \
@@ -507,6 +511,18 @@
 	(tsk_ctl)->thr_pid = -1; \
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define DAEMONIZE(a) daemonize(a); \
+	allow_signal(SIGKILL); \
+	allow_signal(SIGTERM);
+#else /* Linux 2.4 (w/o preemption patch) */
+#define RAISE_RX_SOFTIRQ() \
+	cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
+#define DAEMONIZE(a) daemonize(); \
+	do { if (a) \
+		strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
+	} while (0);
+#endif /* LINUX_VERSION_CODE  */
 
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h
index f468420..77eace6 100644
--- a/drivers/net/wireless/bcmdhd/include/miniopt.h
+++ b/drivers/net/wireless/bcmdhd/include/miniopt.h
@@ -20,7 +20,7 @@
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
- * $Id: miniopt.h,v 1.3 2009-01-15 00:06:54 Exp $
+ * $Id: miniopt.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h
index 721d421..088f1e8 100644
--- a/drivers/net/wireless/bcmdhd/include/msgtrace.h
+++ b/drivers/net/wireless/bcmdhd/include/msgtrace.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: msgtrace.h,v 1.4 2009-04-10 04:15:32 Exp $
+ * $Id: msgtrace.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_MSGTRACE_H
diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h
index 80248ee..b8cc256 100644
--- a/drivers/net/wireless/bcmdhd/include/osl.h
+++ b/drivers/net/wireless/bcmdhd/include/osl.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: osl.h,v 13.44.96.1 2010-05-20 11:09:18 Exp $
+ * $Id: osl.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
index 5d4a876..71f8b2e 100644
--- a/drivers/net/wireless/bcmdhd/include/packed_section_end.h
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
@@ -34,7 +34,7 @@
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
- * $Id: packed_section_end.h,v 1.4 2008-12-09 23:43:22 Exp $
+ * $Id: packed_section_end.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h
index da2fed6..afc2ba3 100644
--- a/drivers/net/wireless/bcmdhd/include/packed_section_start.h
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_start.h
@@ -34,7 +34,7 @@
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
- * $Id: packed_section_start.h,v 1.4.124.1 2010-09-17 00:47:03 Exp $
+ * $Id: packed_section_start.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h
index fae063a..6619943 100644
--- a/drivers/net/wireless/bcmdhd/include/pcicfg.h
+++ b/drivers/net/wireless/bcmdhd/include/pcicfg.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: pcicfg.h,v 1.50 2009-12-07 21:56:06 Exp $
+ * $Id: pcicfg.h 277737 2011-08-16 17:54:59Z $
  */
 
 
@@ -39,6 +39,19 @@
 #define	PCI_INT_MASK		0x94	
 
 #define PCIE_EXTCFG_OFFSET	0x100
+#define	PCI_SPROM_CONTROL	0x88	
+#define	PCI_BAR1_CONTROL	0x8c	
+#define PCI_TO_SB_MB		0x98	
+#define PCI_BACKPLANE_ADDR	0xa0	
+#define PCI_BACKPLANE_DATA	0xa4	
+#define	PCI_CLK_CTL_ST		0xa8	
+#define	PCI_BAR0_WIN2		0xac	
+#define	PCI_GPIO_IN		0xb0	
+#define	PCI_GPIO_OUT		0xb4	
+#define	PCI_GPIO_OUTEN		0xb8	
+
+#define	PCI_BAR0_SHADOW_OFFSET	(2 * 1024)	
+#define	PCI_BAR0_SPROM_OFFSET	(4 * 1024)	
 #define	PCI_BAR0_PCIREGS_OFFSET	(6 * 1024)	
 #define	PCI_BAR0_PCISBR_OFFSET	(4 * 1024)	
 
@@ -49,4 +62,17 @@
 #define	PCI_16KB0_CCREGS_OFFSET	(12 * 1024)	
 #define PCI_16KBB0_WINSZ	(16 * 1024)	
 
+
+#define	PCI_16KB0_WIN2_OFFSET	(4 * 1024)	
+
+
+
+#define SPROM_SZ_MSK		0x02	
+#define SPROM_LOCKED		0x08	
+#define	SPROM_BLANK		0x04	
+#define SPROM_WRITEEN		0x10	
+#define SPROM_BOOTROM_WE	0x20	
+#define SPROM_BACKPLANE_EN	0x40	
+#define SPROM_OTPIN_USE		0x80	
+
 #endif	
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
index 2342cb3..fd69aac 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
@@ -21,7 +21,7 @@
  *
  * Fundamental types and constants relating to 802.11
  *
- * $Id: 802.11.h,v 9.260.2.6 2010-12-15 21:41:14 Exp $
+ * $Id: 802.11.h 304058 2011-12-21 00:39:12Z $
  */
 
 
@@ -429,10 +429,26 @@
 BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie {
 	uint8 id;
 	uint8 len;
-	uint8 cap;
+	uint8 cap[1];
 } BWL_POST_PACKED_STRUCT;
 typedef struct dot11_extcap_ie dot11_extcap_ie_t;
 #define DOT11_EXTCAP_LEN    1
+#define DOT11_EXTCAP_LEN_TDLS	5
+
+BWL_PRE_PACKED_STRUCT struct dot11_extcap {
+	uint8 extcap[DOT11_EXTCAP_LEN_TDLS];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_extcap dot11_extcap_t;
+
+
+#define TDLS_CAP_TDLS			37		
+#define TDLS_CAP_PU_BUFFER_STA	28		
+#define TDLS_CAP_PEER_PSM		20		
+#define TDLS_CAP_CH_SW			30		
+#define TDLS_CAP_PROH			38		
+#define TDLS_CAP_CH_SW_PROH		39		
+
+#define TDLS_CAP_MAX_BIT		39		
 
 
 
@@ -545,6 +561,9 @@
 #define WME_SUBTYPE_IE      0   
 #define WME_SUBTYPE_PARAM_IE    1   
 #define WME_SUBTYPE_TSPEC   2   
+#define WME_VERSION_LEN	1
+#define WME_PARAMETER_IE_LEN		24
+
 
 
 #define AC_BE           0   
@@ -709,6 +728,15 @@
 #define DOT11_MGMT_NOTIFICATION_LEN 4   
 
 
+BWL_PRE_PACKED_STRUCT struct ti_ie {
+	uint8 ti_type;
+	uint32 ti_val;
+} BWL_POST_PACKED_STRUCT;
+typedef struct ti_ie ti_ie_t;
+#define TI_TYPE_REASSOC_DEADLINE	1
+#define TI_TYPE_KEY_LIFETIME		2
+
+
 #define WME_ADDTS_REQUEST   0   
 #define WME_ADDTS_RESPONSE  1   
 #define WME_DELTS_REQUEST   2   
@@ -724,8 +752,7 @@
 
 #define DOT11_OPEN_SYSTEM   0   
 #define DOT11_SHARED_KEY    1   
-#define DOT11_OPEN_SHARED   2   
-#define DOT11_FAST_BSS      3   
+#define DOT11_FAST_BSS		2	
 #define DOT11_CHALLENGE_LEN 128 
 
 
@@ -926,9 +953,18 @@
 
 #define DOT11_RC_MAX            23  
 
+#define DOT11_RC_TDLS_PEER_UNREACH	25
+#define DOT11_RC_TDLS_DOWN_UNSPECIFIED	26
+
 
 #define DOT11_SC_SUCCESS        0   
 #define DOT11_SC_FAILURE        1   
+#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2	
+					
+#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3	
+#define DOT11_SC_TDLS_SEC_DISABLED	5	
+#define DOT11_SC_LIFETIME_REJ		6	
+#define DOT11_SC_NOT_SAME_BSS		7	
 #define DOT11_SC_CAP_MISMATCH       10  
 #define DOT11_SC_REASSOC_FAIL       11  
 #define DOT11_SC_ASSOC_FAIL     12  
@@ -947,13 +983,22 @@
 #define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED   25  
 #define DOT11_SC_ASSOC_ERPBCC_REQUIRED  26  
 #define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27  
+#define DOT11_SC_ASSOC_R0KH_UNREACHABLE	28	
+#define DOT11_SC_ASSOC_TRY_LATER	30	
+#define DOT11_SC_ASSOC_MFP_VIOLATION	31	
 
-#define DOT11_SC_DECLINED       37  
-#define DOT11_SC_INVALID_PARAMS     38  
-#define DOT11_SC_INVALID_AKMP       43  
-#define DOT11_SC_INVALID_MDID       54  
-#define DOT11_SC_INVALID_FTIE       55  
+#define	DOT11_SC_DECLINED		37	
+#define	DOT11_SC_INVALID_PARAMS		38	
+#define DOT11_SC_INVALID_PAIRWISE_CIPHER	42 
+#define	DOT11_SC_INVALID_AKMP		43	
+#define DOT11_SC_INVALID_RSNIE_CAP	45	
+#define	DOT11_SC_INVALID_PMKID		53	
+#define	DOT11_SC_INVALID_MDID		54	
+#define	DOT11_SC_INVALID_FTIE		55	
 
+#define DOT11_SC_UNEXP_MSG			70	
+#define DOT11_SC_INVALID_SNONCE		71	
+#define DOT11_SC_INVALID_RSNIE		72	
 
 #define DOT11_MNG_DS_PARAM_LEN          1   
 #define DOT11_MNG_IBSS_PARAM_LEN        2   
@@ -1008,6 +1053,7 @@
 #define DOT11_MNG_MDIE_ID       54  
 #define DOT11_MNG_FTIE_ID       55  
 #define DOT11_MNG_FT_TI_ID      56  
+#define DOT11_MNG_RDE_ID			57	
 #define DOT11_MNG_REGCLASS_ID           59  
 #define DOT11_MNG_EXT_CSA_ID            60  
 #define DOT11_MNG_HT_ADD            61  
@@ -1018,7 +1064,13 @@
 #define DOT11_MNG_HT_BSS_COEXINFO_ID        72  
 #define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID  73  
 #define DOT11_MNG_HT_OBSS_ID            74  
-#define DOT11_MNG_EXT_CAP           127 
+#define DOT11_MNG_CHANNEL_USAGE			97 
+#define DOT11_MNG_LINK_IDENTIFIER_ID	101	
+#define DOT11_MNG_WAKEUP_SCHEDULE_ID	102 
+#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID	104 
+#define DOT11_MNG_PTI_CONTROL_ID		105	
+#define DOT11_MNG_PU_BUFFER_STATUS_ID	106	
+#define DOT11_MNG_EXT_CAP_ID           127 
 #define DOT11_MNG_WPA_ID            221 
 #define DOT11_MNG_PROPR_ID          221 
 
@@ -1070,8 +1122,14 @@
 #define DOT11_ACTION_CAT_RRM        5   
 #define DOT11_ACTION_CAT_FBT    6   
 #define DOT11_ACTION_CAT_HT     7   
+#if defined(MFP) || defined(WLFBT) || defined(WLWNM)
+#define	DOT11_ACTION_CAT_SA_QUERY	8	
+#define	DOT11_ACTION_CAT_PDPA		9	
 #define DOT11_ACTION_CAT_BSSMGMT    10  
 #define DOT11_ACTION_NOTIFICATION   17
+#define DOT11_ACTION_CAT_VSP		126	
+#endif 
+#define DOT11_ACTION_NOTIFICATION	17
 #define DOT11_ACTION_CAT_VS     127 
 
 
@@ -1107,6 +1165,121 @@
 #define DOT11_ADDBA_POLICY_DELAYED  0   
 #define DOT11_ADDBA_POLICY_IMMEDIATE    1   
 
+
+#define DOT11_FT_ACTION_FT_RESERVED		0
+#define DOT11_FT_ACTION_FT_REQ			1	
+#define DOT11_FT_ACTION_FT_RES			2	
+#define DOT11_FT_ACTION_FT_CON			3	
+#define DOT11_FT_ACTION_FT_ACK			4	
+
+
+
+#define DOT11_WNM_ACTION_EVENT_REQ			0
+#define DOT11_WNM_ACTION_EVENT_REP			1
+#define DOT11_WNM_ACTION_DIAG_REQ			2
+#define DOT11_WNM_ACTION_DIAG_REP			3
+#define DOT11_WNM_ACTION_LOC_CFG_REQ		4
+#define DOT11_WNM_ACTION_LOC_RFG_RESP		5
+#define DOT11_WNM_ACTION_BSS_TRANS_QURY		6
+#define DOT11_WNM_ACTION_BSS_TRANS_REQ		7
+#define DOT11_WNM_ACTION_BSS_TRANS_RESP		8
+#define DOT11_WNM_ACTION_FMS_REQ			9
+#define DOT11_WNM_ACTION_FMS_RESP			10
+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ	11
+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP	12
+#define DOT11_WNM_ACTION_TFS_REQ			13
+#define DOT11_WNM_ACTION_TFS_RESP			14
+#define DOT11_WNM_ACTION_TFS_NOTIFY			15
+#define DOT11_WNM_ACTION_WNM_SLEEP_REQ		16
+#define DOT11_WNM_ACTION_WNM_SLEEP_RESP		17
+#define DOT11_WNM_ACTION_TIM_BCAST_REQ		18
+#define DOT11_WNM_ACTION_TIM_BCAST_RESP		19
+#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD	20
+#define DOT11_WNM_ACTION_CHAN_USAGE_REQ		21
+#define DOT11_WNM_ACTION_CHAN_USAGE_RESP	22
+#define DOT11_WNM_ACTION_DMS_REQ			23
+#define DOT11_WNM_ACTION_DMS_RESP			24
+#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ	25
+#define DOT11_WNM_ACTION_NOTFCTN_REQ		26
+#define DOT11_WNM_ACTION_NOTFCTN_RES		27
+
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query {
+	uint8 category;				
+	uint8 action;				
+	uint8 token;				
+	uint8 reason;				
+	uint8 data[1];				
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bss_trans_query dot11_bss_trans_query_t;
+#define DOT11_BSS_TRANS_QUERY_LEN 4	
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req {
+	uint8 category;				
+	uint8 action;				
+	uint8 token;				
+	uint8 reqmode;				
+	uint16 disassoc_tmr;		
+	uint8 validity_intrvl;		
+	uint8 data[1];				
+								
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bss_trans_req dot11_bss_trans_req_t;
+#define DOT11_BSS_TRANS_REQ_LEN 7	
+
+#define DOT11_BSS_TERM_DUR_LEN 12	
+
+
+
+#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL		0x01
+#define DOT11_BSS_TRNS_REQMODE_ABRIDGED				0x02
+#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT	0x04
+#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL		0x08
+#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT	0x10
+
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res {
+	uint8 category;				
+	uint8 action;				
+	uint8 token;				
+	uint8 status;				
+	uint8 term_delay;			
+	uint8 data[1];				
+								
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bss_trans_res dot11_bss_trans_res_t;
+#define DOT11_BSS_TRANS_RES_LEN 5	
+
+
+#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT				0
+#define DOT11_BSS_TRNS_RES_STATUS_REJECT				1
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN		2
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP		3
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED	4
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ	5
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED	6
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS	7
+#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS		8
+
+
+
+#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY		0x0003
+#define DOT11_NBR_RPRT_BSSID_INFO_SEC				0x0004
+#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE			0x0008
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP				0x03f0
+
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT		0x0010
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS			0x0020
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD			0x0040
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT		0x0080
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA		0x0100
+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA		0x0200
+
+
+#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID	3
 BWL_PRE_PACKED_STRUCT struct dot11_addba_req {
 	uint8 category;             
 	uint8 action;               
@@ -1145,6 +1318,48 @@
 #define DOT11_DELBA_LEN         6   
 
 
+#define SA_QUERY_REQUEST		0
+#define SA_QUERY_RESPONSE		1
+
+
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_ft_req {
+	uint8 category;			
+	uint8 action;			
+	uint8 sta_addr[ETHER_ADDR_LEN];
+	uint8 tgt_ap_addr[ETHER_ADDR_LEN];
+	uint8 data[1];			
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ft_req dot11_ft_req_t;
+#define DOT11_FT_REQ_FIXED_LEN 14
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_ft_res {
+	uint8 category;			
+	uint8 action;			
+	uint8 sta_addr[ETHER_ADDR_LEN];
+	uint8 tgt_ap_addr[ETHER_ADDR_LEN];
+	uint16 status;			
+	uint8 data[1];			
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ft_res dot11_ft_res_t;
+#define DOT11_FT_RES_FIXED_LEN 16
+
+
+BWL_PRE_PACKED_STRUCT struct dot11_rde_ie {
+	uint8 id; 			
+	uint8 length;
+	uint8 rde_id;			
+	uint8 rd_count;			
+	uint16 status;			
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rde_ie dot11_rde_ie_t;
+
+
+#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t)
+
+
 
 
 
@@ -1166,6 +1381,28 @@
 #define DOT11_RRM_CAP_AP_CHANREP    16
 
 
+
+#define DOT11_EXT_CAP_LEN		4	
+BWL_PRE_PACKED_STRUCT struct dot11_ext_cap_ie {
+	uint8 cap[DOT11_EXT_CAP_LEN];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ext_cap_ie dot11_ext_cap_ie_t;
+
+
+#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT	19
+
+
+#define DOT11_OP_CLASS_NONE			255
+
+BWL_PRE_PACKED_STRUCT struct do11_ap_chrep {
+	uint8 id;
+	uint8 len;
+	uint8 reg;
+	uint8 chanlist[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct do11_ap_chrep dot11_ap_chrep_t;
+
+
 #define DOT11_RM_ACTION_RM_REQ      0   
 #define DOT11_RM_ACTION_RM_REP      1   
 #define DOT11_RM_ACTION_LM_REQ      2   
@@ -1255,7 +1492,7 @@
 #define DOT11_RMREQ_BCN_REPINFO_ID  1
 #define DOT11_RMREQ_BCN_REPDET_ID   2
 #define DOT11_RMREQ_BCN_REQUEST_ID  10
-#define DOT11_RMREQ_BCN_APCHREP_ID  51
+#define DOT11_RMREQ_BCN_APCHREP_ID  DOT11_MNG_AP_CHREP_ID
 
 
 #define DOT11_RMREQ_BCN_REPDET_FIXED    0   
@@ -1272,6 +1509,7 @@
 	uint8 reg;
 	uint8 channel;
 	uint8 phytype;
+	uchar sub_elements[1]; 	
 } BWL_POST_PACKED_STRUCT;
 typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t;
 #define DOT11_RMREP_NBR_LEN 13
@@ -1660,6 +1898,9 @@
 #define RSN_AKM_PSK     2   
 #define RSN_AKM_FBT_1X      3   
 #define RSN_AKM_FBT_PSK     4   
+#define RSN_AKM_MFP_1X		5	
+#define RSN_AKM_MFP_PSK		6	
+#define RSN_AKM_TPK			7	
 
 
 #define DOT11_MAX_DEFAULT_KEYS  4   
@@ -1724,6 +1965,66 @@
 } BWL_POST_PACKED_STRUCT;
 typedef struct dot11_gtk_ie dot11_gtk_ie_t;
 
+#define BSSID_INVALID           "\x00\x00\x00\x00\x00\x00"
+#define BSSID_BROADCAST         "\xFF\xFF\xFF\xFF\xFF\xFF"
+
+
+
+BWL_PRE_PACKED_STRUCT struct link_id_ie {
+	uint8 id;
+	uint8 len;
+	struct ether_addr	bssid;
+	struct ether_addr	tdls_init_mac;
+	struct ether_addr	tdls_resp_mac;
+} BWL_POST_PACKED_STRUCT;
+typedef struct link_id_ie link_id_ie_t;
+#define TDLS_LINK_ID_IE_LEN		18
+
+
+BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie {
+	uint8 id;
+	uint8 len;
+	uint32 offset;			
+	uint32 interval;		
+	uint32 awake_win_slots;	
+	uint32 max_wake_win;	
+	uint16 idle_cnt;		
+} BWL_POST_PACKED_STRUCT;
+typedef struct wakeup_sch_ie wakeup_sch_ie_t;
+#define TDLS_WAKEUP_SCH_IE_LEN		18
+
+
+BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie {
+	uint8 id;
+	uint8 len;
+	uint16 switch_time;		
+	uint16 switch_timeout;	
+} BWL_POST_PACKED_STRUCT;
+typedef struct channel_switch_timing_ie channel_switch_timing_ie_t;
+#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN		4
+
+
+BWL_PRE_PACKED_STRUCT struct pti_control_ie {
+	uint8 id;
+	uint8 len;
+	uint8 tid;
+	uint16 seq_control;
+} BWL_POST_PACKED_STRUCT;
+typedef struct pti_control_ie pti_control_ie_t;
+#define TDLS_PTI_CONTROL_IE_LEN		3
+
+
+BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie {
+	uint8 id;
+	uint8 len;
+	uint8 status;
+} BWL_POST_PACKED_STRUCT;
+typedef struct pu_buffer_status_ie pu_buffer_status_ie_t;
+#define TDLS_PU_BUFFER_STATUS_IE_LEN	1
+#define TDLS_PU_BUFFER_STATUS_AC_BK		1
+#define TDLS_PU_BUFFER_STATUS_AC_BE		2
+#define TDLS_PU_BUFFER_STATUS_AC_VI		4
+#define TDLS_PU_BUFFER_STATUS_AC_VO		8
 
 
 #include <packed_section_end.h>
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
index 4ccfab0..cbdd05e 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: 802.11_bta.h,v 9.2 2008-10-28 23:27:13 Exp $
+ * $Id: 802.11_bta.h 277737 2011-08-16 17:54:59Z $
 */
 
 #ifndef _802_11_BTA_H_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
index ce8ad08..0e070a4 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: 802.11e.h,v 1.6 2008-12-01 22:55:11 Exp $
+ * $Id: 802.11e.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef _802_11e_H_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
index cf20625..c7e07bd 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
@@ -21,7 +21,7 @@
  *
  * Fundamental types and constants relating to 802.1D
  *
- * $Id: 802.1d.h,v 9.3 2007-04-10 21:33:06 Exp $
+ * $Id: 802.1d.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
index 46fa4c9..0f75d3c 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmeth.h,v 9.12 2009-12-29 19:57:18 Exp $
+ * $Id: bcmeth.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
index 30ec848..e8c2387 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
@@ -23,7 +23,7 @@
  *
  * Dependencies: proto/bcmeth.h
  *
- * $Id: bcmevent.h,v 9.64.2.9 2011-02-01 06:24:21 Exp $
+ * $Id: bcmevent.h 288077 2011-10-06 00:08:47Z $
  *
  */
 
@@ -182,7 +182,10 @@
 #define WLC_E_PFN_SCAN_NONE		82	
 #define WLC_E_PFN_SCAN_ALLGONE	83	
 #define WLC_E_GTK_PLUMBED 84
-#define WLC_E_LAST	85
+#define WLC_E_ASSOC_REQ_IE 85
+#define WLC_E_ASSOC_RESP_IE 86
+#define WLC_E_LAST	87	
+
 
 
 typedef struct {
@@ -226,6 +229,8 @@
 #define WLC_E_REASON_TSPEC_REJECTED	7	
 #define WLC_E_REASON_BETTER_AP		8	
 
+#define WLC_E_REASON_REQUESTED_ROAM 11	
+
 
 #define WLC_E_PRUNE_ENCR_MISMATCH	1	
 #define WLC_E_PRUNE_BCAST_BSSID		2	
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
index 8a8f314..55eff24 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
@@ -21,7 +21,7 @@
  *
  * Fundamental constants relating to IP Protocol
  *
- * $Id: bcmip.h,v 9.19 2009-11-10 20:08:33 Exp $
+ * $Id: bcmip.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
index 89c1181..91ab4fe 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bt_amp_hci.h,v 9.14.8.2 2010-09-10 18:37:47 Exp $
+ * $Id: bt_amp_hci.h 277737 2011-08-16 17:54:59Z $
 */
 
 #ifndef _bt_amp_hci_h
diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
index 5781d13..92634c1 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/eapol.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 2002 Broadcom Corporation
  *
- * $Id: eapol.h,v 9.23.86.1 2010-09-02 18:09:39 Exp $
+ * $Id: eapol.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef _eapol_h_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
index 6a6dd14..20865dc 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: ethernet.h,v 9.56 2009-10-15 22:54:58 Exp $
+ * $Id: ethernet.h 285437 2011-09-21 22:16:56Z $
  */
 
 
@@ -69,6 +69,7 @@
 #define	ETHER_TYPE_802_1X	0x888e		
 #define	ETHER_TYPE_802_1X_PREAUTH 0x88c7	
 #define ETHER_TYPE_WAI		0x88b4		
+#define ETHER_TYPE_89_0D	0x890d		
 
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
index 4a0c9d1..d2bf3f2 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/p2p.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
@@ -21,7 +21,7 @@
  *
  * Fundamental types and constants relating to WFA P2P (aka WiFi Direct)
  *
- * $Id: p2p.h,v 9.17.2.4 2010-12-15 21:41:21 Exp $
+ * $Id: p2p.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef _P2P_H_
diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
index 7fe4fbc..7353ff0 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sdspi.h,v 9.2.120.1 2010-11-15 17:56:25 Exp $
+ * $Id: sdspi.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_SD_SPI_H
diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
index 07fa7e4..27f0055 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/vlan.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: vlan.h,v 9.7 2009-03-13 01:11:50 Exp $
+ * $Id: vlan.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
index 1ff06dc..7361cbf 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/wpa.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wpa.h,v 1.19 2009-07-13 08:29:58 Exp $
+ * $Id: wpa.h 285437 2011-09-21 22:16:56Z $
  */
 
 
@@ -114,6 +114,8 @@
 #define WPA_CIPHER_AES_OCB	3	
 #define WPA_CIPHER_AES_CCM	4	
 #define WPA_CIPHER_WEP_104	5	
+#define WPA_CIPHER_BIP		6	
+#define WPA_CIPHER_TPK		7	
 
 
 #define IS_WPA_CIPHER(cipher)	((cipher) == WPA_CIPHER_NONE || \
@@ -121,7 +123,9 @@
 				 (cipher) == WPA_CIPHER_WEP_104 || \
 				 (cipher) == WPA_CIPHER_TKIP || \
 				 (cipher) == WPA_CIPHER_AES_OCB || \
-				 (cipher) == WPA_CIPHER_AES_CCM)
+				 (cipher) == WPA_CIPHER_AES_CCM || \
+				 (cipher) == WPA_CIPHER_TPK)
+
 
 
 #define WPA_TKIP_CM_DETECT	60	
@@ -149,7 +153,11 @@
 #define WPA_CAP_REPLAY_CNTR_MASK	RSN_CAP_PTK_REPLAY_CNTR_MASK
 
 
+#define WPA_CAP_PEER_KEY_ENABLE		(0x1 << 1)	
+
+
 #define WPA_CAP_LEN	RSN_CAP_LEN	
+#define WPA_PMKID_CNT_LEN	2	
 
 #define	WPA_CAP_WPA2_PREAUTH		RSN_CAP_PREAUTH
 
diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h
index cbd3749..3fe2a5a 100644
--- a/drivers/net/wireless/bcmdhd/include/sbchipc.h
+++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h
@@ -5,7 +5,7 @@
  * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer,
  * GPIO interface, extbus, and support for serial and parallel flashes.
  *
- * $Id: sbchipc.h,v 13.169.2.14 2011-02-10 23:43:55 Exp $
+ * $Id: sbchipc.h 277737 2011-08-16 17:54:59Z $
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
  * 
@@ -41,6 +41,50 @@
 #define	PAD		_XSTR(__LINE__)
 #endif	
 
+typedef struct eci_prerev35 {
+	uint32	eci_output;
+	uint32	eci_control;
+	uint32	eci_inputlo;
+	uint32	eci_inputmi;
+	uint32	eci_inputhi;
+	uint32	eci_inputintpolaritylo;
+	uint32	eci_inputintpolaritymi;
+	uint32	eci_inputintpolarityhi;
+	uint32	eci_intmasklo;
+	uint32	eci_intmaskmi;
+	uint32	eci_intmaskhi;
+	uint32	eci_eventlo;
+	uint32	eci_eventmi;
+	uint32	eci_eventhi;
+	uint32	eci_eventmasklo;
+	uint32	eci_eventmaskmi;
+	uint32	eci_eventmaskhi;
+	uint32	PAD[3];
+} eci_prerev35_t;
+
+typedef struct eci_rev35 {
+	uint32	eci_outputlo;
+	uint32	eci_outputhi;
+	uint32	eci_controllo;
+	uint32	eci_controlhi;
+	uint32	eci_inputlo;
+	uint32	eci_inputhi;
+	uint32	eci_inputintpolaritylo;
+	uint32	eci_inputintpolarityhi;
+	uint32	eci_intmasklo;
+	uint32	eci_intmaskhi;
+	uint32	eci_eventlo;
+	uint32	eci_eventhi;
+	uint32	eci_eventmasklo;
+	uint32	eci_eventmaskhi;
+	uint32	eci_auxtx;
+	uint32	eci_auxrx;
+	uint32	eci_datatag;
+	uint32	eci_uartescvalue;
+	uint32	eci_autobaudctr;
+	uint32	eci_uartfifolevel;
+} eci_rev35_t;
+
 typedef volatile struct {
 	uint32	chipid;			
 	uint32	capabilities;
@@ -153,10 +197,26 @@
 	uint32	prog_waitcount;
 	uint32	flash_config;
 	uint32	flash_waitcount;
-	uint32	PAD[4];
-	uint32	PAD[40];
+	uint32  SECI_config;		
+	uint32	SECI_status;
+	uint32	SECI_statusmask;
+	uint32	SECI_rxnibchanged;
+
+	uint32	PAD[20];
 
 	
+	uint32	sromcontrol;		
+	uint32	sromaddress;
+	uint32	sromdata;
+	uint32	PAD[9];		
+	uint32  seci_uart_data;		
+	uint32  seci_uart_bauddiv;
+	uint32  seci_uart_fcr;
+	uint32  seci_uart_lcr;
+	uint32  seci_uart_mcr;
+	uint32  seci_uart_lsr;
+	uint32  seci_uart_msr;
+	uint32  seci_uart_baudadj;
 	
 	uint32	clk_ctl_st;		
 	uint32	hw_war;
@@ -1332,9 +1392,27 @@
 #define CST43237_BOOT_FROM_INVALID	3
 
 
+#define RES43239_CBUCK_LPOM		0
+#define RES43239_CBUCK_BURST		1
+#define RES43239_CBUCK_LP_PWM		2
+#define RES43239_CBUCK_PWM		3
+#define RES43239_CLDO_PU		4
+#define RES43239_DIS_INT_RESET_PD	5
+#define RES43239_ILP_REQUEST		6
+#define RES43239_LNLDO_PU		7
+#define RES43239_LDO3P3_PU		8
 #define RES43239_OTP_PU			9
+#define RES43239_XTAL_PU		10
+#define RES43239_ALP_AVAIL		11
+#define RES43239_RADIO_PU		12
 #define RES43239_MACPHY_CLKAVAIL	23
 #define RES43239_HT_AVAIL		24
+#define RES43239_XOLDO_PU		25
+#define RES43239_WL_XTAL_CTL_SEL	26
+#define RES43239_SR_CLK_STABLE		27
+#define RES43239_SR_SAVE_RESTORE	28
+#define RES43239_SR_PHY_PIC		29
+#define RES43239_SR_PHY_PWR_SW		30
 
 
 #define CST43239_SPROM_MASK			0x00000002
@@ -1342,7 +1420,7 @@
 #define	CST43239_RES_INIT_MODE_SHIFT	7
 #define	CST43239_RES_INIT_MODE_MASK		0x000001f0
 #define CST43239_CHIPMODE_SDIOD(cs)	((cs) & (1 << 15))	
-#define CST43239_CHIPMODE_USB20D(cs)	((cs) & !(1 << 15))	
+#define CST43239_CHIPMODE_USB20D(cs)	(~(cs) & (1 << 15))	
 #define CST43239_CHIPMODE_SDIO(cs)	(((cs) & (1 << 0)) == 0)	
 #define CST43239_CHIPMODE_GSPI(cs)	(((cs) & (1 << 0)) == (1 << 0))	
 
@@ -1350,6 +1428,40 @@
 #define CCTRL43239_XTAL_STRENGTH(ctl)	((ctl & 0x3F) << 12)
 
 
+#define RES4331_REGULATOR		0
+#define RES4331_ILP_REQUEST		1
+#define RES4331_XTAL_PU			2
+#define RES4331_ALP_AVAIL		3
+#define RES4331_SI_PLL_ON		4
+#define RES4331_HT_SI_AVAIL		5
+
+
+#define CCTRL4331_BT_COEXIST		(1<<0)	
+#define CCTRL4331_SECI			(1<<1)	
+#define CCTRL4331_EXT_LNA_G		(1<<2)	
+#define CCTRL4331_SPROM_GPIO13_15       (1<<3)  
+#define CCTRL4331_EXTPA_EN		(1<<4)	
+#define CCTRL4331_GPIOCLK_ON_SPROMCS	<1<<5)	
+#define CCTRL4331_PCIE_MDIO_ON_SPROMCS	(1<<6)	
+#define CCTRL4331_EXTPA_ON_GPIO2_5	(1<<7)	
+#define CCTRL4331_OVR_PIPEAUXCLKEN	(1<<8)	
+#define CCTRL4331_OVR_PIPEAUXPWRDOWN	(1<<9)	
+#define CCTRL4331_PCIE_AUXCLKEN		<1<<10)	
+#define CCTRL4331_PCIE_PIPE_PLLDOWN	<1<<11)	
+#define CCTRL4331_EXTPA_EN2		(1<<12)	
+#define CCTRL4331_EXT_LNA_A		(1<<13)	
+#define CCTRL4331_BT_SHD0_ON_GPIO4	<1<<16)	
+#define CCTRL4331_BT_SHD1_ON_GPIO5	<1<<17)	
+#define CCTRL4331_EXTPA_ANA_EN		(1<<24)	
+
+
+#define	CST4331_XTAL_FREQ		0x00000001	
+#define	CST4331_SPROM_OTP_SEL_MASK	0x00000006
+#define	CST4331_SPROM_OTP_SEL_SHIFT	1
+#define	CST4331_SPROM_PRESENT		0x00000002
+#define	CST4331_OTP_PRESENT		0x00000004
+#define	CST4331_LDO_RF			0x00000008
+#define	CST4331_LDO_PAR			0x00000010
 
 
 #define RES4315_CBUCK_LPOM		1	
@@ -1597,6 +1709,54 @@
 
 
 
+#define SECI_MODE_UART			0x0
+#define SECI_MODE_SECI			0x1
+#define SECI_MODE_LEGACY_3WIRE_BT	0x2
+#define SECI_MODE_LEGACY_3WIRE_WLAN	0x3
+#define SECI_MODE_HALF_SECI		0x4
+
+#define SECI_RESET		(1 << 0)
+#define SECI_RESET_BAR_UART	(1 << 1)
+#define SECI_ENAB_SECI_ECI	(1 << 2)
+#define SECI_ENAB_SECIOUT_DIS	(1 << 3)
+#define SECI_MODE_MASK		0x7
+#define SECI_MODE_SHIFT		4 
+#define SECI_UPD_SECI		(1 << 7)
+
+
+#define CLKCTL_STS_SECI_CLK_REQ		(1 << 8)
+#define CLKCTL_STS_SECI_CLK_AVAIL	(1 << 24)
+
+#define SECI_UART_MSR_CTS_STATE		(1 << 0)
+#define SECI_UART_MSR_RTS_STATE		(1 << 1)
+#define SECI_UART_SECI_IN_STATE		(1 << 2)
+#define SECI_UART_SECI_IN2_STATE	(1 << 3)
+
+
+#define SECI_UART_LCR_STOP_BITS		(1 << 0) 
+#define SECI_UART_LCR_PARITY_EN		(1 << 1)
+#define SECI_UART_LCR_PARITY		(1 << 2) 
+#define SECI_UART_LCR_RX_EN		(1 << 3)
+#define SECI_UART_LCR_LBRK_CTRL		(1 << 4) 
+#define SECI_UART_LCR_TXO_EN		(1 << 5)
+#define SECI_UART_LCR_RTSO_EN		(1 << 6)
+#define SECI_UART_LCR_SLIPMODE_EN	(1 << 7)
+#define SECI_UART_LCR_RXCRC_CHK		(1 << 8)
+#define SECI_UART_LCR_TXCRC_INV		(1 << 9)
+#define SECI_UART_LCR_TXCRC_LSBF	(1 << 10)
+#define SECI_UART_LCR_TXCRC_EN		(1 << 11)
+
+#define SECI_UART_MCR_TX_EN		(1 << 0)
+#define SECI_UART_MCR_PRTS		(1 << 1)
+#define SECI_UART_MCR_SWFLCTRL_EN	(1 << 2)
+#define SECI_UART_MCR_HIGHRATE_EN	(1 << 3)
+#define SECI_UART_MCR_LOOPBK_EN		(1 << 4)
+#define SECI_UART_MCR_AUTO_RTS		(1 << 5)
+#define SECI_UART_MCR_AUTO_TX_DIS	(1 << 6)
+#define SECI_UART_MCR_BAUD_ADJ_EN	(1 << 7)
+#define SECI_UART_MCR_XONOFF_RPT	(1 << 9)
+
+
 
 
 #define ECI_BW_20   0x0
diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h
index 76f05ae..f45351a 100644
--- a/drivers/net/wireless/bcmdhd/include/sbconfig.h
+++ b/drivers/net/wireless/bcmdhd/include/sbconfig.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sbconfig.h,v 13.70 2008-03-28 19:17:04 Exp $
+ * $Id: sbconfig.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
index 05d0587..77c413f 100644
--- a/drivers/net/wireless/bcmdhd/include/sbhnddma.h
+++ b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sbhnddma.h,v 13.20.2.3 2010-10-14 22:21:29 Exp $
+ * $Id: sbhnddma.h 278779 2011-08-19 22:07:18Z $
  */
 
 
@@ -217,7 +217,7 @@
 #define D64_XC_BL_SHIFT		18
 
 
-#define	D64_XP_LD_MASK		0x00000fff	
+#define	D64_XP_LD_MASK		0x00001fff	
 
 
 #define	D64_XS0_CD_MASK		0x00001fff	
@@ -260,7 +260,7 @@
 #define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4)
 
 
-#define	D64_RP_LD_MASK		0x00000fff	
+#define	D64_RP_LD_MASK		0x00001fff	
 
 
 #define	D64_RS0_CD_MASK		0x00001fff	
diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
index aba914b..d84f69a 100644
--- a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
+++ b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sbpcmcia.h,v 13.48.12.6 2010-11-04 09:39:42 Exp $
+ * $Id: sbpcmcia.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h
index 4280d5b..7aaeb73 100644
--- a/drivers/net/wireless/bcmdhd/include/sbsdio.h
+++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sbsdio.h,v 13.34 2009-03-11 20:27:16 Exp $
+ * $Id: sbsdio.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_SBSDIO_H
diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
index 107a8b0..e517648 100644
--- a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
+++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sbsdpcmdev.h,v 13.38 2009-09-22 22:56:45 Exp $
+ * $Id: sbsdpcmdev.h 282638 2011-09-08 21:18:10Z $
  */
 
 #ifndef	_sbsdpcmdev_h_
diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h
index 1cba422..45c4dc2 100644
--- a/drivers/net/wireless/bcmdhd/include/sbsocram.h
+++ b/drivers/net/wireless/bcmdhd/include/sbsocram.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sbsocram.h,v 13.15 2009-10-02 16:55:44 Exp $
+ * $Id: sbsocram.h 277737 2011-08-16 17:54:59Z $
  */
 
 
diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h
index ca93226..c8ac7b7 100644
--- a/drivers/net/wireless/bcmdhd/include/sdio.h
+++ b/drivers/net/wireless/bcmdhd/include/sdio.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sdio.h,v 13.27.14.1 2010-09-07 13:37:45 Exp $
+ * $Id: sdio.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef	_SDIO_H
@@ -366,7 +366,7 @@
  *  SDIO Commands and responses
  *
  *  I/O only commands are:
- *      CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53
+ *      CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53
  * ------------------------------------------------
  */
 
@@ -412,6 +412,7 @@
 
 #define CMD7_RCA_M		BITFIELD_MASK(16)
 #define CMD7_RCA_S		16
+
 #define CMD14_RCA_M		BITFIELD_MASK(16)
 #define CMD14_RCA_S		16
 #define CMD14_SLEEP_M		BITFIELD_MASK(1)
diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h
index 3d37c7a..5f47d6f 100644
--- a/drivers/net/wireless/bcmdhd/include/sdioh.h
+++ b/drivers/net/wireless/bcmdhd/include/sdioh.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sdioh.h,v 13.17.2.3 2011-01-08 05:28:21 Exp $
+ * $Id: sdioh.h 300017 2011-12-01 20:30:27Z $
  */
 
 #ifndef	_SDIOH_H
@@ -68,6 +68,10 @@
 #define SD_ADMA_SysAddr			0x58
 #define SD_SlotInterruptStatus		0x0FC
 #define SD_HostControllerVersion 	0x0FE
+#define	SD_GPIO_Reg			0x100
+#define	SD_GPIO_OE			0x104
+#define	SD_GPIO_Enable			0x108
+
 
 /* SD specific registers in PCI config space */
 #define SD_SlotInfo	0x40
@@ -409,4 +413,30 @@
 /* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */
 /* SD_HostControllerVersion : Offset 0x0FE , size = bytes */
 
+/* SDIO Host Control Register DMA Mode Definitions */
+#define SDIOH_SDMA_MODE			0
+#define SDIOH_ADMA1_MODE		1
+#define SDIOH_ADMA2_MODE		2
+#define SDIOH_ADMA2_64_MODE		3
+
+#define ADMA2_ATTRIBUTE_VALID		(1 << 0)	/* ADMA Descriptor line valid */
+#define ADMA2_ATTRIBUTE_END			(1 << 1)	/* End of Descriptor */
+#define ADMA2_ATTRIBUTE_INT			(1 << 2)	/* Interrupt when line is done */
+#define ADMA2_ATTRIBUTE_ACT_NOP		(0 << 4)	/* Skip current line, go to next. */
+#define ADMA2_ATTRIBUTE_ACT_RSV		(1 << 4)	/* Same as NOP */
+#define ADMA1_ATTRIBUTE_ACT_SET		(1 << 4)	/* ADMA1 Only - set transfer length */
+#define ADMA2_ATTRIBUTE_ACT_TRAN	(2 << 4)	/* Transfer Data of one descriptor line. */
+#define ADMA2_ATTRIBUTE_ACT_LINK	(3 << 4)	/* Link Descriptor */
+
+/* ADMA2 Descriptor Table Entry for 32-bit Address */
+typedef struct adma2_dscr_32b {
+	uint32 len_attr;
+	uint32 phys_addr;
+} adma2_dscr_32b_t;
+
+/* ADMA1 Descriptor Table Entry */
+typedef struct adma1_dscr {
+	uint32 phys_addr_attr;
+} adma1_dscr_t;
+
 #endif /* _SDIOH_H */
diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h
index 2c5bcf9..55a3d34 100644
--- a/drivers/net/wireless/bcmdhd/include/sdiovar.h
+++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: sdiovar.h,v 13.9 2009-12-08 22:30:15 Exp $
+ * $Id: sdiovar.h 277737 2011-08-16 17:54:59Z $
  */
 
 #ifndef _sdiovar_h_
diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h
index c5a3383..6a7b93c 100644
--- a/drivers/net/wireless/bcmdhd/include/siutils.h
+++ b/drivers/net/wireless/bcmdhd/include/siutils.h
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: siutils.h,v 13.251.2.10 2011-02-04 05:06:32 Exp $
+ * $Id: siutils.h 285387 2011-09-21 18:38:37Z $
  */
 
 
@@ -60,6 +60,7 @@
 typedef const struct si_pub si_t;
 
 
+
 #define	SI_OSH		NULL	
 
 #define	BADIDX		(SI_MAXCORES + 1)
@@ -213,8 +214,34 @@
 #define si_eci(sih) 0
 #define si_eci_init(sih) (0)
 #define si_eci_notify_bt(sih, type, val)  (0)
+#define si_seci(sih) 0
+static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;}
+#define si_seci_down(sih) do { } while (0)
 
 
+extern bool si_is_otp_disabled(si_t *sih);
+extern bool si_is_otp_powered(si_t *sih);
+extern void si_otp_power(si_t *sih, bool on);
+
+
+extern bool si_is_sprom_available(si_t *sih);
+extern bool si_is_sprom_enabled(si_t *sih);
+extern void si_sprom_enable(si_t *sih, bool enable);
+
+
+extern int si_cis_source(si_t *sih);
+#define CIS_DEFAULT	0
+#define CIS_SROM	1
+#define CIS_OTP		2
+
+
+#define	DEFAULT_FAB	0x0	
+#define	CSM_FAB7	0x1	
+#define	TSMC_FAB12	0x2	
+#define	SMIC_FAB4	0x3	
+extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw);
+extern uint16 si_fabid(si_t *sih);
+
 
 extern int si_devpath(si_t *sih, char *path, int size);
 
@@ -244,4 +271,5 @@
 
 char *si_getnvramflvar(si_t *sih, const char *name);
 
+
 #endif	
diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h
index 397006a..b52fb15 100644
--- a/drivers/net/wireless/bcmdhd/include/trxhdr.h
+++ b/drivers/net/wireless/bcmdhd/include/trxhdr.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: trxhdr.h,v 13.15.108.2 2010-11-15 17:57:30 Exp $
+ * $Id: trxhdr.h 286295 2011-09-27 06:39:43Z $
  */
 
 #ifndef	_TRX_HDR_H_
@@ -37,6 +37,7 @@
 #define TRX_OVERLAYS	0x4     /* Contains an overlay header after the trx header */
 #define TRX_MAX_OFFSET	3		/* Max number of individual files */
 #define TRX_UNCOMP_IMAGE	0x20	/* Trx contains uncompressed rtecdc.bin image */
+#define TRX_ROMSIM_IMAGE	0x10	/* Trx contains ROM simulation image */
 
 struct trx_header {
 	uint32 magic;		/* "HDR0" */
diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h
index 228b5dc..d0902fe 100644
--- a/drivers/net/wireless/bcmdhd/include/typedefs.h
+++ b/drivers/net/wireless/bcmdhd/include/typedefs.h
@@ -18,7 +18,7 @@
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
- * $Id: typedefs.h,v 1.103.2.1 2010-05-11 18:19:28 Exp $
+ * $Id: typedefs.h 290055 2011-10-15 21:26:26Z $
  */
 
 
@@ -305,5 +305,8 @@
 #define UNUSED_PARAMETER(x) (void)(x)
 
 
+#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr))
+
+
 #include <bcmdefs.h>
 #endif 
diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
index 7230d3b..d371051 100644
--- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
+++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
@@ -18,7 +18,7 @@
 *      Notwithstanding the above, under no circumstances may you combine this
 * software in any way with any other Broadcom software provided under a license
 * other than the GPL, without Broadcom's express prior written consent.
-* $Id: wlfc_proto.h,v 1.1.6.2 2010-05-08 01:30:41 Exp $
+* $Id: wlfc_proto.h 277737 2011-08-16 17:54:59Z $
 *
 */
 #ifndef __wlfc_proto_definitions_h__
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index 9357552..e31bfa9 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wlioctl.h,v 1.767.2.38 2011-02-01 23:04:28 Exp $
+ * $Id: wlioctl.h 307468 2012-01-11 18:29:27Z $
  */
 
 
@@ -65,8 +65,8 @@
 
 typedef struct ssid_info
 {
-	uint8		ssid_len;
-	uint8		ssid[32];
+	uint8		ssid_len;	
+	uint8		ssid[32];	
 } ssid_info_t;
 
 typedef struct wl_af_params {
@@ -191,6 +191,7 @@
 #define WL_SCANFLAGS_PROHIBITED 0x04    
 
 #define WL_SCAN_PARAMS_SSID_MAX 	10
+
 typedef struct wl_scan_params {
 	wlc_ssid_t ssid;        
 	struct ether_addr bssid;    
@@ -376,6 +377,8 @@
 #define NRATE_SGI_SHIFT 23              
 #define NRATE_LDPC_CODING 0x00400000    
 #define NRATE_LDPC_SHIFT 22             
+#define NRATE_BCMC_OVERRIDE 0x00200000    
+#define NRATE_BCMC_SHIFT 21             
 
 #define NRATE_STF_SISO  0       
 #define NRATE_STF_CDD   1       
@@ -555,7 +558,7 @@
 #define CRYPTO_ALGO_AES_OCB_MSDU    5
 #define CRYPTO_ALGO_AES_OCB_MPDU    6
 #define CRYPTO_ALGO_NALG        7
-#define CRYPTO_ALGO_PMK			12
+#define CRYPTO_ALGO_PMK			12	
 
 #define WSEC_GEN_MIC_ERROR  0x0001
 #define WSEC_GEN_REPLAY     0x0002
@@ -617,9 +620,9 @@
 #define WPA2_AUTH_PSK       0x0080  
 #define BRCM_AUTH_PSK           0x0100  
 #define BRCM_AUTH_DPT       0x0200  
-#define WPA2_AUTH_MFP           0x1000
-#define WPA2_AUTH_TPK		0x2000
-#define WPA2_AUTH_FT		0x4000
+#define WPA2_AUTH_MFP           0x1000  
+#define WPA2_AUTH_TPK		0x2000 	
+#define WPA2_AUTH_FT		0x4000 	
 
 
 #define MAXPMKID        16
@@ -649,12 +652,12 @@
 	uint32      resp_len;
 	uint32      flags;
 	struct dot11_assoc_req req;
-	struct ether_addr reassoc_bssid;
+	struct ether_addr reassoc_bssid;	
 	struct dot11_assoc_resp resp;
 } wl_assoc_info_t;
 
 
-#define WLC_ASSOC_REQ_IS_REASSOC 0x01
+#define WLC_ASSOC_REQ_IS_REASSOC 0x01	
 
 
 typedef struct {
@@ -818,8 +821,14 @@
 #define WLC_IOCTL_MEDLEN        1536    
 #ifdef WLC_HIGH_ONLY
 #define WLC_SAMPLECOLLECT_MAXLEN    1024    
+#define WLC_SAMPLECOLLECT_MAXLEN_LCN40  1024
 #else
-#define WLC_SAMPLECOLLECT_MAXLEN    10240   
+#if defined(LCNCONF) || defined(LCN40CONF)
+#define WLC_SAMPLECOLLECT_MAXLEN	8192	
+#else
+#define WLC_SAMPLECOLLECT_MAXLEN	10240	
+#endif
+#define WLC_SAMPLECOLLECT_MAXLEN_LCN40  8192
 #endif 
 
 
@@ -851,6 +860,7 @@
 #define WLC_GET_SSID                25
 #define WLC_SET_SSID                26
 #define WLC_RESTART             27
+#define WLC_TERMINATED             28
  
 #define WLC_GET_CHANNEL             29
 #define WLC_SET_CHANNEL             30
@@ -1203,7 +1213,7 @@
 
 #define WL_AUTH_OPEN_SYSTEM     0   
 #define WL_AUTH_SHARED_KEY      1   
-#define WL_AUTH_OPEN_SHARED     2   
+#define WL_AUTH_OPEN_SHARED		3	
 
 
 #define WL_RADIO_SW_DISABLE     (1<<0)
@@ -1280,18 +1290,17 @@
 #define WL_CHAN_FREQ_RANGE_5GM     2
 #define WL_CHAN_FREQ_RANGE_5GH     3
 
-#define WL_CHAN_FREQ_RANGE_5GLL_VER2    4
-#define WL_CHAN_FREQ_RANGE_5GLH_VER2    5
-#define WL_CHAN_FREQ_RANGE_5GML_VER2    6
-#define WL_CHAN_FREQ_RANGE_5GMH_VER2    7
-#define WL_CHAN_FREQ_RANGE_5GH_VER2     8
-
 #define WL_CHAN_FREQ_RANGE_5GLL_5BAND    4
 #define WL_CHAN_FREQ_RANGE_5GLH_5BAND    5
 #define WL_CHAN_FREQ_RANGE_5GML_5BAND    6
 #define WL_CHAN_FREQ_RANGE_5GMH_5BAND    7
 #define WL_CHAN_FREQ_RANGE_5GH_5BAND     8
 
+#define WL_CHAN_FREQ_RANGE_5G_BAND0     1
+#define WL_CHAN_FREQ_RANGE_5G_BAND1     2
+#define WL_CHAN_FREQ_RANGE_5G_BAND2     3
+#define WL_CHAN_FREQ_RANGE_5G_BAND3     4
+
 
 #define WLC_PHY_TYPE_A      0
 #define WLC_PHY_TYPE_B      1
@@ -1363,7 +1372,7 @@
 #define PM_MAX  1
 #define PM_FAST 2
 
-#define LISTEN_INTERVAL		10
+#define LISTEN_INTERVAL			10
 
 #define INTERFERE_OVRRIDE_OFF   -1  
 #define INTERFERE_NONE  0   
@@ -1408,7 +1417,7 @@
 #define TRIGGER_BADPLCP             0x10
 #define TRIGGER_CRSGLITCH           0x20
 #define WL_ACI_ARGS_LEGACY_LENGTH   16  
-#define WL_SAMPLECOLLECT_T_VERSION  1   
+#define	WL_SAMPLECOLLECT_T_VERSION	2	
 typedef struct wl_samplecollect_args {
 	
 	uint8 coll_us;
@@ -1416,7 +1425,7 @@
 	
 	uint16 version;     
 	uint16 length;      
-	uint8 trigger;
+	int8 trigger;
 	uint16 timeout;
 	uint16 mode;
 	uint32 pre_dur;
@@ -1426,6 +1435,11 @@
 	bool be_deaf;
 	bool agc;       
 	bool filter;        
+	
+	uint8 trigger_state;
+	uint8 module_sel1;
+	uint8 module_sel2;
+	uint16 nsamps;
 } wl_samplecollect_args_t;
 
 #define WL_SAMPLEDATA_HEADER_TYPE   1
@@ -1493,6 +1507,7 @@
 #define WL_P2P_VAL      0x00000200
 #define WL_TXRX_VAL		0x00000400
 #define WL_MCHAN_VAL            0x00000800
+#define WL_TDLS_VAL		0x00001000
 
 
 #define WL_LED_NUMGPIO      16  
@@ -1546,7 +1561,7 @@
 #define WL_JOIN_PREF_WPA    2   
 #define WL_JOIN_PREF_BAND   3   
 #define WL_JOIN_PREF_RSSI_DELTA 4   
-#define WL_JOIN_PREF_TRANS_PREF	5
+#define WL_JOIN_PREF_TRANS_PREF	5	
 
 
 #define WLJP_BAND_ASSOC_PREF    255 
@@ -1797,17 +1812,19 @@
 };
 
 typedef struct wl_mkeep_alive_pkt {
-	uint16	version;
-	uint16	length;
+	uint16	version; 
+	uint16	length; 
 	uint32	period_msec;
 	uint16	len_bytes;
-	uint8	keep_alive_id;
+	uint8	keep_alive_id; 
 	uint8	data[1];
 } wl_mkeep_alive_pkt_t;
 
-#define WL_MKEEP_ALIVE_VERSION          1
-#define WL_MKEEP_ALIVE_FIXED_LEN        OFFSETOF(wl_mkeep_alive_pkt_t, data)
-#define WL_MKEEP_ALIVE_PRECISION        500
+#define WL_MKEEP_ALIVE_VERSION		1
+#define WL_MKEEP_ALIVE_FIXED_LEN	OFFSETOF(wl_mkeep_alive_pkt_t, data)
+#define WL_MKEEP_ALIVE_PRECISION	500
+
+
 
 #define WLC_ROAM_TRIGGER_DEFAULT    0 
 #define WLC_ROAM_TRIGGER_BANDWIDTH  1 
@@ -1897,7 +1914,7 @@
 	uint8 mscan; 
 	uint8 repeat; 
 	uint8 exp; 
-	int32 slow_freq;
+	int32 slow_freq; 
 } wl_pfn_param_t;
 
 typedef struct wl_pfn_bssid {
@@ -2016,8 +2033,31 @@
 
 
 
+#define MAX_WAKE_PACKET_BYTES 128
+
+
+typedef struct pm_wake_packet {
+	uint32	status;		
+	uint32	pattern_id;	
+	uint32	original_packet_size;
+	uint32	saved_packet_size;
+	uchar	packet[MAX_WAKE_PACKET_BYTES];
+} pm_wake_packet_t;
+
+
+
+#define PKT_FILTER_MODE_FORWARD_ON_MATCH      		1
+
+#define PKT_FILTER_MODE_DISABLE					2
+
+#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH    		4
+
+#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8
+
+
 typedef enum wl_pkt_filter_type {
-	WL_PKT_FILTER_TYPE_PATTERN_MATCH    
+	WL_PKT_FILTER_TYPE_PATTERN_MATCH,	
+	WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH	
 } wl_pkt_filter_type_t;
 
 #define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
@@ -2550,6 +2590,12 @@
 #define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core)
 #endif 
 
+#ifdef WLDSTA
+typedef struct wl_dsta_if {
+	struct ether_addr addr;
+} wl_dsta_if_t;
+#endif
+
 #ifdef WLP2P
 
 typedef struct wl_p2p_disc_st {
diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c
index 1a54437..4ef7bf7 100644
--- a/drivers/net/wireless/bcmdhd/linux_osl.c
+++ b/drivers/net/wireless/bcmdhd/linux_osl.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 Exp $
+ * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 $
  */
 
 
@@ -47,7 +47,7 @@
 #define OS_HANDLE_MAGIC		0x1234abcd	
 #define BCM_MEM_FILENAME_LEN 	24		
 
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 #define STATIC_BUF_MAX_NUM	16
 #define STATIC_BUF_SIZE		(PAGE_SIZE * 2)
 #define STATIC_BUF_TOTAL_LEN	(STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
@@ -70,7 +70,7 @@
 } bcm_static_pkt_t;
 
 static bcm_static_pkt_t *bcm_static_skb = 0;
-#endif 
+#endif
 
 typedef struct bcm_mem_link {
 	struct bcm_mem_link *prev;
@@ -211,7 +211,7 @@
 			break;
 	}
 
-#if defined(DHD_USE_STATIC_BUF)
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
 	if (!bcm_static_buf) {
 		if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+
 			STATIC_BUF_TOTAL_LEN))) {
@@ -220,7 +220,6 @@
 		else
 			printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf);
 
-
 		sema_init(&bcm_static_buf->static_sem, 1);
 
 		bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
@@ -238,7 +237,7 @@
 
 		sema_init(&bcm_static_skb->osl_pkt_sem, 1);
 	}
-#endif 
+#endif
 
 	return osh;
 }
@@ -388,7 +387,7 @@
 	if ((osh == NULL) || (osh->ctfpool == NULL))
 		return;
 
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 	if (bcm_static_buf) {
 		bcm_static_buf = 0;
 	}
@@ -548,14 +547,14 @@
 	}
 }
 
-#ifdef DHD_USE_STATIC_BUF
+#ifdef CONFIG_DHD_USE_STATIC_BUF
 void *
 osl_pktget_static(osl_t *osh, uint len)
 {
 	int i;
 	struct sk_buff *skb;
 
-	if (len > (PAGE_SIZE * 2)) {
+	if (!bcm_static_skb || (len > (PAGE_SIZE * 2))) {
 		printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
 		return osl_pktget(osh, len);
 	}
@@ -570,10 +569,10 @@
 
 		if (i != STATIC_PKT_MAX_NUM) {
 			bcm_static_skb->pkt_use[i] = 1;
-			up(&bcm_static_skb->osl_pkt_sem);
 			skb = bcm_static_skb->skb_4k[i];
 			skb->tail = skb->data + len;
 			skb->len = len;
+			up(&bcm_static_skb->osl_pkt_sem);
 			return skb;
 		}
 	}
@@ -586,10 +585,10 @@
 
 	if (i != STATIC_PKT_MAX_NUM) {
 		bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1;
-		up(&bcm_static_skb->osl_pkt_sem);
 		skb = bcm_static_skb->skb_8k[i];
 		skb->tail = skb->data + len;
 		skb->len = len;
+		up(&bcm_static_skb->osl_pkt_sem);
 		return skb;
 	}
 
@@ -603,9 +602,14 @@
 {
 	int i;
 
+	if (!bcm_static_skb) {
+		osl_pktfree(osh, p, send);
+		return;
+	}
+
+	down(&bcm_static_skb->osl_pkt_sem);
 	for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
 		if (p == bcm_static_skb->skb_4k[i]) {
-			down(&bcm_static_skb->osl_pkt_sem);
 			bcm_static_skb->pkt_use[i] = 0;
 			up(&bcm_static_skb->osl_pkt_sem);
 			return;
@@ -614,14 +618,15 @@
 
 	for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
 		if (p == bcm_static_skb->skb_8k[i]) {
-			down(&bcm_static_skb->osl_pkt_sem);
 			bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0;
 			up(&bcm_static_skb->osl_pkt_sem);
 			return;
 		}
 	}
+	up(&bcm_static_skb->osl_pkt_sem);
 
-	return osl_pktfree(osh, p, send);
+	osl_pktfree(osh, p, send);
+	return;
 }
 #endif 
 
diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c
index 22aa412..a655ac4 100644
--- a/drivers/net/wireless/bcmdhd/siutils.c
+++ b/drivers/net/wireless/bcmdhd/siutils.c
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 Exp $
+ * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 $
  */
 
 #include <typedefs.h>
@@ -213,11 +213,11 @@
 
 	/* figure out bus/orignal core idx */
 	sii->pub.buscoretype = NODEV_CORE_ID;
-	sii->pub.buscorerev = NOREV;
+	sii->pub.buscorerev = (uint)NOREV;
 	sii->pub.buscoreidx = BADIDX;
 
 	pci = pcie = FALSE;
-	pcirev = pcierev = NOREV;
+	pcirev = pcierev = (uint)NOREV;
 	pciidx = pcieidx = BADIDX;
 
 	for (i = 0; i < sii->numcores; i++) {
@@ -365,6 +365,19 @@
 		return NULL;
 	}
 
+#if defined(HW_OOB)
+	if (CHIPID(sih->chip) == BCM43362_CHIP_ID) {
+		uint32 gpiocontrol, addr;
+		addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol);
+		gpiocontrol = bcmsdh_reg_read(sdh, addr, 4);
+		gpiocontrol |= 0x2;
+		bcmsdh_reg_write(sdh, addr, 4, gpiocontrol);
+		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL);
+		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL);
+		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL);
+	}
+#endif
+
 	if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) &&
 		(sih->chippkg != BCM4329_289PIN_PKG_ID)) {
 		sih->chippkg = BCM4329_182PIN_PKG_ID;
@@ -401,8 +414,9 @@
 	}
 
 	/* assume current core is CC */
-	if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID ||
+	if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43234_CHIP_ID ||
 	                                  CHIPID(sih->chip) == BCM43235_CHIP_ID ||
+	                                  CHIPID(sih->chip) == BCM43236_CHIP_ID ||
 	                                  CHIPID(sih->chip) == BCM43238_CHIP_ID) &&
 	                                 (CHIPREV(sii->pub.chiprev) == 0))) {
 
@@ -1093,6 +1107,126 @@
 
 
 
+/* return the slow clock source - LPO, XTAL, or PCI */
+static uint
+si_slowclk_src(si_info_t *sii)
+{
+	chipcregs_t *cc;
+
+	ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
+
+	if (sii->pub.ccrev < 6) {
+		if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) &&
+		    (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) &
+		     PCI_CFG_GPIO_SCS))
+			return (SCC_SS_PCI);
+		else
+			return (SCC_SS_XTAL);
+	} else if (sii->pub.ccrev < 10) {
+		cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx);
+		return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK);
+	} else	/* Insta-clock */
+		return (SCC_SS_XTAL);
+}
+
+/* return the ILP (slowclock) min or max frequency */
+static uint
+si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc)
+{
+	uint32 slowclk;
+	uint div;
+
+	ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
+
+	/* shouldn't be here unless we've established the chip has dynamic clk control */
+	ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL);
+
+	slowclk = si_slowclk_src(sii);
+	if (sii->pub.ccrev < 6) {
+		if (slowclk == SCC_SS_PCI)
+			return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64));
+		else
+			return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32));
+	} else if (sii->pub.ccrev < 10) {
+		div = 4 *
+		        (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
+		if (slowclk == SCC_SS_LPO)
+			return (max_freq ? LPOMAXFREQ : LPOMINFREQ);
+		else if (slowclk == SCC_SS_XTAL)
+			return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div));
+		else if (slowclk == SCC_SS_PCI)
+			return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div));
+		else
+			ASSERT(0);
+	} else {
+		/* Chipc rev 10 is InstaClock */
+		div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
+		div = 4 * (div + 1);
+		return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div));
+	}
+	return (0);
+}
+
+static void
+si_clkctl_setdelay(si_info_t *sii, void *chipcregs)
+{
+	chipcregs_t *cc = (chipcregs_t *)chipcregs;
+	uint slowmaxfreq, pll_delay, slowclk;
+	uint pll_on_delay, fref_sel_delay;
+
+	pll_delay = PLL_DELAY;
+
+	/* If the slow clock is not sourced by the xtal then add the xtal_on_delay
+	 * since the xtal will also be powered down by dynamic clk control logic.
+	 */
+
+	slowclk = si_slowclk_src(sii);
+	if (slowclk != SCC_SS_XTAL)
+		pll_delay += XTAL_ON_DELAY;
+
+	/* Starting with 4318 it is ILP that is used for the delays */
+	slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc);
+
+	pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
+	fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
+
+	W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay);
+	W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay);
+}
+
+/* initialize power control delay registers */
+void
+si_clkctl_init(si_t *sih)
+{
+	si_info_t *sii;
+	uint origidx = 0;
+	chipcregs_t *cc;
+	bool fast;
+
+	if (!CCCTL_ENAB(sih))
+		return;
+
+	sii = SI_INFO(sih);
+	fast = SI_FAST(sii);
+	if (!fast) {
+		origidx = sii->curidx;
+		if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
+			return;
+	} else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL)
+		return;
+	ASSERT(cc != NULL);
+
+	/* set all Instaclk chip ILP to 1 MHz */
+	if (sih->ccrev >= 10)
+		SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
+		        (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
+
+	si_clkctl_setdelay(sii, (void *)(uintptr)cc);
+
+	if (!fast)
+		si_setcoreidx(sih, origidx);
+}
+
 /* change logical "focus" to the gpio core for optimized access */
 void *
 si_gpiosetcore(si_t *sih)
@@ -1718,3 +1852,64 @@
 	}
 	return FALSE;
 }
+
+bool
+si_is_sprom_available(si_t *sih)
+{
+	if (sih->ccrev >= 31) {
+		si_info_t *sii;
+		uint origidx;
+		chipcregs_t *cc;
+		uint32 sromctrl;
+
+		if ((sih->cccaps & CC_CAP_SROM) == 0)
+			return FALSE;
+
+		sii = SI_INFO(sih);
+		origidx = sii->curidx;
+		cc = si_setcoreidx(sih, SI_CC_IDX);
+		sromctrl = R_REG(sii->osh, &cc->sromcontrol);
+		si_setcoreidx(sih, origidx);
+		return (sromctrl & SRC_PRESENT);
+	}
+
+	switch (CHIPID(sih->chip)) {
+	case BCM4312_CHIP_ID:
+		return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL);
+	case BCM4325_CHIP_ID:
+		return (sih->chipst & CST4325_SPROM_SEL) != 0;
+	case BCM4322_CHIP_ID:
+	case BCM43221_CHIP_ID:
+	case BCM43231_CHIP_ID:
+	case BCM43222_CHIP_ID:
+	case BCM43111_CHIP_ID:
+	case BCM43112_CHIP_ID:
+	case BCM4342_CHIP_ID:
+	{
+		uint32 spromotp;
+		spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >>
+		        CST4322_SPROM_OTP_SEL_SHIFT;
+		return (spromotp & CST4322_SPROM_PRESENT) != 0;
+	}
+	case BCM4329_CHIP_ID:
+		return (sih->chipst & CST4329_SPROM_SEL) != 0;
+	case BCM4315_CHIP_ID:
+		return (sih->chipst & CST4315_SPROM_SEL) != 0;
+	case BCM4319_CHIP_ID:
+		return (sih->chipst & CST4319_SPROM_SEL) != 0;
+
+	case BCM4336_CHIP_ID:
+	case BCM43362_CHIP_ID:
+		return (sih->chipst & CST4336_SPROM_PRESENT) != 0;
+
+	case BCM4330_CHIP_ID:
+		return (sih->chipst & CST4330_SPROM_PRESENT) != 0;
+	case BCM4313_CHIP_ID:
+		return (sih->chipst & CST4313_SPROM_PRESENT) != 0;
+	case BCM43239_CHIP_ID:
+		return ((sih->chipst & CST43239_SPROM_MASK) &&
+			!(sih->chipst & CST43239_SFLASH_MASK));
+	default:
+		return TRUE;
+	}
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 9ca3d60..2cbe333 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -2,13 +2,13 @@
  * Linux cfg80211 driver - Android related functions
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
- *
+ * 
  *         Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
  * under the terms of the GNU General Public License version 2 (the "GPL"),
  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  * following added to such license:
- *
+ * 
  *      As a special exception, the copyright holders of this software give you
  * permission to link this software with independent modules, and to copy and
  * distribute the resulting executable under terms of your choice, provided that
@@ -16,7 +16,7 @@
  * the license of that module.  An independent module is a module which is not
  * derived from this software.  The special exception does not apply to any
  * modifications of the software.
- *
+ * 
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
@@ -73,7 +73,6 @@
 #define CMD_GETBAND				"GETBAND"
 #define CMD_COUNTRY				"COUNTRY"
 #define CMD_P2P_SET_NOA			"P2P_SET_NOA"
-#define CMD_P2P_GET_NOA			"P2P_GET_NOA"
 #define CMD_P2P_SET_PS			"P2P_SET_PS"
 #define CMD_SET_AP_WPS_P2P_IE	"SET_AP_WPS_P2P_IE"
 
@@ -537,9 +536,6 @@
 		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
 			priv_cmd.total_len - skip);
 	}
-	else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
-		bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
-	}
 	else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
 		int skip = strlen(CMD_P2P_SET_PS) + 1;
 		bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
@@ -559,8 +555,10 @@
 		bytes_written = strlen("OK");
 	}
 
-	if (bytes_written > 0) {
-		if (bytes_written > priv_cmd.total_len) {
+	if (bytes_written >= 0) {
+		if ((bytes_written == 0) && (priv_cmd.total_len > 0))
+			command[0] = '\0';
+		if (bytes_written >= priv_cmd.total_len) {
 			DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
 			bytes_written = priv_cmd.total_len;
 		} else {
@@ -571,7 +569,8 @@
 			DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
 			ret = -EFAULT;
 		}
-	} else {
+	}
+	else {
 		ret = bytes_written;
 	}
 
@@ -608,30 +607,14 @@
 	return ret;
 }
 
-int wl_android_post_init(void)
+void wl_android_post_init(void)
 {
-	struct net_device *ndev;
-	int ret = 0;
-	char buf[IFNAMSIZ];
 	if (!dhd_download_fw_on_driverload) {
 		/* Call customer gpio to turn off power with WL_REG_ON signal */
 		dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
 		g_wifi_on = 0;
-	} else {
-		memset(buf, 0, IFNAMSIZ);
-#ifdef CUSTOMER_HW2
-		snprintf(buf, IFNAMSIZ, "%s%d", iface_name, 0);
-#else
-		snprintf(buf, IFNAMSIZ, "%s%d", "eth", 0);
-#endif
-		if ((ndev = dev_get_by_name (&init_net, buf)) != NULL) {
-			dhd_dev_init_ioctl(ndev);
-			dev_put(ndev);
-		}
 	}
-	return ret;
 }
-
 /**
  * Functions for Android WiFi card detection
  */
@@ -675,20 +658,21 @@
 	}
 }
 
-void* wl_android_prealloc(int section, unsigned long size)
+void *wl_android_prealloc(int section, unsigned long size)
 {
 	void *alloc_ptr = NULL;
 	if (wifi_control_data && wifi_control_data->mem_prealloc) {
 		alloc_ptr = wifi_control_data->mem_prealloc(section, size);
 		if (alloc_ptr) {
 			DHD_INFO(("success alloc section %d\n", section));
-			bzero(alloc_ptr, size);
+			if (size != 0L)
+				bzero(alloc_ptr, size);
 			return alloc_ptr;
 		}
 	}
 
 	DHD_ERROR(("can't alloc section %d\n", section));
-	return 0;
+	return NULL;
 }
 
 int wifi_get_irq_number(unsigned long *irq_flags_ptr)
diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h
index 17373b7..3983306 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.h
+++ b/drivers/net/wireless/bcmdhd/wl_android.h
@@ -40,7 +40,7 @@
  */
 int wl_android_init(void);
 int wl_android_exit(void);
-int wl_android_post_init(void);
+void wl_android_post_init(void);
 int wl_android_wifi_on(struct net_device *dev);
 int wl_android_wifi_off(struct net_device *dev);
 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index daa7d26..125888d 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -2,13 +2,13 @@
  * Linux cfg80211 driver
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
- *
+ * 
  *         Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
  * under the terms of the GNU General Public License version 2 (the "GPL"),
  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  * following added to such license:
- *
+ * 
  *      As a special exception, the copyright holders of this software give you
  * permission to link this software with independent modules, and to copy and
  * distribute the resulting executable under terms of your choice, provided that
@@ -41,10 +41,9 @@
 #include <dhd.h>
 #include <dhdioctl.h>
 #include <wlioctl.h>
+#include <dhd_cfg80211.h>
 
 #include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/netdevice.h>
@@ -54,54 +53,33 @@
 #include <linux/ieee80211.h>
 #include <linux/wait.h>
 #include <net/cfg80211.h>
-
 #include <net/rtnetlink.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/firmware.h>
-#include <bcmsdbus.h>
 
 #include <wlioctl.h>
 #include <wldev_common.h>
 #include <wl_cfg80211.h>
 #include <wl_cfgp2p.h>
 
-static struct sdio_func *cfg80211_sdio_func;
-static struct wl_priv *wlcfg_drv_priv;
+static struct device *cfg80211_parent_dev = NULL;
+static int vsdb_supported = 0;
+struct wl_priv *wlcfg_drv_priv = NULL;
 
 u32 wl_dbg_level = WL_DBG_ERR;
 
-#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin"
-#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt"
 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAX_WAIT_TIME 1500
-static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
+#define WL_SCAN_ACTIVE_TIME	 40
+#define WL_SCAN_PASSIVE_TIME	130
 
+#define DNGL_FUNC(func, parameters) func parameters;
 #define COEX_DHCP
 
-#if defined(COEX_DHCP)
-#define BT_DHCP_eSCO_FIX		/* use New SCO/eSCO smart YG
-					 * suppression
-					 */
-#define BT_DHCP_USE_FLAGS		/* this flag boost wifi pkt priority
-					 * to max, caution: -not fair to sco
-					 */
-#define BT_DHCP_OPPR_WIN_TIME	2500	/* T1 start SCO/ESCo priority
-					 * suppression
-					 */
-#define BT_DHCP_FLAG_FORCE_TIME 5500	/* T2 turn off SCO/SCO supperesion
-					 * is (timeout)
-					 */
-enum wl_cfg80211_btcoex_status {
-	BT_DHCP_IDLE,
-	BT_DHCP_START,
-	BT_DHCP_OPPR_WIN,
-	BT_DHCP_FLAG_FORCE_TIMEOUT
-};
 
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
-static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
-#endif
+/* Set this to 1 to use a seperate interface (p2p0)
+ *  for p2p operations.
+ */
+#define ENABLE_P2P_INTERFACE	1
 
 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
  * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
@@ -224,7 +202,7 @@
 	struct cfg80211_pmksa *pmksa);
 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
 	struct net_device *dev);
-static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted);
+static void wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted);
 /*
  * event & event Q handlers for cfg80211 interfaces
  */
@@ -242,6 +220,8 @@
 	const wl_event_msg_t *msg, void *data);
 static void wl_put_event(struct wl_event_q *e);
 static void wl_wakeup_event(struct wl_priv *wl);
+static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
+	const wl_event_msg_t *e, void *data);
 static s32 wl_notify_connect_status(struct wl_priv *wl,
 	struct net_device *ndev,
 	const wl_event_msg_t *e, void *data);
@@ -256,22 +236,12 @@
 	const wl_event_msg_t *e, void *data);
 static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
 	const wl_event_msg_t *e, void *data);
+static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
+	const wl_event_msg_t *e, void *data);
 /*
- * register/deregister sdio function
+ * register/deregister parent device
  */
-struct sdio_func *wl_cfg80211_get_sdio_func(void);
-static void wl_clear_sdio_func(void);
-
-/*
- * ioctl utilites
- */
-static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
-	s32 buf_len);
-static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name,
-	s8 *buf, s32 len);
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
-static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name,
-	s32 *retval);
+static void wl_cfg80211_clear_parent_dev(void);
 
 /*
  * cfg80211 set_wiphy_params utilities
@@ -283,10 +253,10 @@
 /*
  * wl profile utilities
  */
-static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e,
-	void *data, s32 item);
-static void *wl_read_prof(struct wl_priv *wl, s32 item);
-static void wl_init_prof(struct wl_priv *wl);
+static s32 wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
+	const wl_event_msg_t *e, void *data, s32 item);
+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item);
+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev);
 
 /*
  * cfg80211 connect utilites
@@ -314,14 +284,14 @@
 static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
 static u32 wl_get_ielen(struct wl_priv *wl);
 
-static s32 wl_mode_to_nl80211_iftype(s32 mode);
 
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev);
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev);
 static void wl_free_wdev(struct wl_priv *wl);
 
 static s32 wl_inform_bss(struct wl_priv *wl);
 static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
 static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev);
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
 
 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
 	u8 key_idx, const u8 *mac_addr,
@@ -347,42 +317,19 @@
 static __used bool wl_is_ibssstarter(struct wl_priv *wl);
 
 /*
- * dongle up/down , default configuration utilities
+ * link up/down , default configuration utilities
  */
+static s32 __wl_cfg80211_up(struct wl_priv *wl);
+static s32 __wl_cfg80211_down(struct wl_priv *wl);
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
 static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
 static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev);
 static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
 static void wl_link_up(struct wl_priv *wl);
 static void wl_link_down(struct wl_priv *wl);
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
-static s32 __wl_cfg80211_up(struct wl_priv *wl);
-static s32 __wl_cfg80211_down(struct wl_priv *wl);
-static s32 wl_dongle_probecap(struct wl_priv *wl);
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
 static void wl_init_conf(struct wl_conf *conf);
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
-
-/*
- * dongle configuration utilities
- */
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode);
-static s32 wl_dongle_up(struct net_device *ndev, u32 up);
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
-static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
-	u32 dongle_align);
-static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
-	u32 bcn_timeout);
-static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
-	s32 scan_unassoc_time);
-static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
-	s32 arp_ol);
-static s32 wl_pattern_atoh(s8 *src, s8 *dst);
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
 static s32 wl_update_wiphybands(struct wl_priv *wl);
-#endif				/* !EMBEDDED_PLATFORM */
-static __used void wl_dongle_poweron(struct wl_priv *wl);
-static __used void wl_dongle_poweroff(struct wl_priv *wl);
-static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
 
 /*
  * iscan handler
@@ -406,33 +353,20 @@
 static s32 wl_iscan_aborted(struct wl_priv *wl);
 
 /*
- * fw/nvram downloading handler
- */
-static void wl_init_fw(struct wl_fw_ctrl *fw);
-
-/*
  * find most significant bit set
  */
 static __used u32 wl_find_msb(u16 bit16);
 
 /*
- * update pmklist to dongle
- */
-static __used s32 wl_update_pmklist(struct net_device *dev,
-	struct wl_pmk_list *pmk_list, s32 err);
-
-/*
- * debufs support
- */
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl);
-static void wl_debugfs_remove_netdev(struct wl_priv *wl);
-
-/*
  * rfkill support
  */
 static int wl_setup_rfkill(struct wl_priv *wl, bool setup);
 static int wl_rfkill_set(void *data, bool blocked);
 
+static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel,
+	int nprobes, int *out_params_size);
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac);
+
 /*
  * Some external functions, TODO: move them to dhd_linux.h
  */
@@ -444,10 +378,10 @@
 
 #define CHECK_SYS_UP(wlpriv)							\
 do {									\
-	if (unlikely(!wl_get_drv_status(wlpriv, READY))) {	\
-		WL_INFO(("device is not ready : status (%d)\n",		\
-			(int)wlpriv->status));			\
-		return -EIO;						\
+	struct net_device *ndev = wl_to_prmry_ndev(wlpriv);       \
+	if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) {	\
+		WL_INFO(("device is not ready\n"));		\
+			return -EIO;					\
 	}								\
 } while (0)
 
@@ -573,7 +507,22 @@
 	.channels = __wl_2ghz_channels,
 	.n_channels = ARRAY_SIZE(__wl_2ghz_channels),
 	.bitrates = wl_g_rates,
-	.n_bitrates = wl_g_rates_size
+	.n_bitrates = wl_g_rates_size,
+#if ENABLE_P2P_INTERFACE
+	/* wpa_supplicant sets wmm_enabled based on whether ht_cap
+	 * is present or not. The wmm_enabled is inturn used to
+	 * set the replay counters in the RSN IE. Without this
+	 * the 4way handshake will fail complaining that IE in beacon
+	 * doesn't match with the IE present in the 3/4 EAPOL msg.
+	 */
+	.ht_cap = {
+				IEEE80211_HT_CAP_SGI_20 |
+				IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
+				.ht_supported = TRUE,
+				.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+				.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
+	}
+#endif
 };
 
 static struct ieee80211_supported_band __wl_band_5ghz_a = {
@@ -740,6 +689,43 @@
 	}
 }
 
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+{
+	if (vsdb_supported) {
+		return wf_chspec_aton(WL_P2P_TEMP_CHAN);
+	}
+	else {
+		chanspec_t chspec;
+		int err = 0;
+		struct wl_priv *wl = wiphy_priv(wiphy);
+		struct net_device *dev = wl_to_prmry_ndev(wl);
+		struct ether_addr bssid;
+		struct wl_bss_info *bss = NULL;
+		if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
+			/* STA interface is not associated. So start the new interface on a temp
+			 * channel . Later proper channel will be applied by the above framework
+			 * via set_channel (cfg80211 API).
+			 */
+			WL_DBG(("Not associated. Return a temp channel. \n"));
+			return wf_chspec_aton(WL_P2P_TEMP_CHAN);
+		}
+
+
+		*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+		if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf,
+			sizeof(WL_EXTRA_BUF_MAX), false))) {
+				WL_ERR(("Failed to get associated bss info, use temp channel \n"));
+				chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+		}
+		else {
+				bss = (struct wl_bss_info *) (wl->extra_buf + 4);
+				chspec =  bss->chanspec;
+				WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec));
+		}
+		return chspec;
+	}
+}
+
 static struct net_device* wl_cfg80211_add_monitor_if(char *name)
 {
 	int ret = 0;
@@ -758,15 +744,17 @@
 	s32 err;
 	s32 timeout = -1;
 	s32 wlif_type = -1;
-	s32 index = 0;
 	s32 mode = 0;
 	chanspec_t chspec;
 	struct wl_priv *wl = wiphy_priv(wiphy);
 	struct net_device *_ndev;
-	dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
-	int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
+	struct ether_addr primary_mac;
+	int (*net_attach)(void *dhdp, int ifidx);
 	bool rollback_lock = false;
 
+	/* Use primary I/F for sending cmds down to firmware */
+	_ndev = wl_to_prmry_ndev(wl);
+
 	WL_DBG(("if name: %s, type: %d\n", name, type));
 	switch (type) {
 	case NL80211_IFTYPE_ADHOC:
@@ -798,6 +786,8 @@
 		WL_ERR(("name is NULL\n"));
 		return NULL;
 	}
+	if (wl->iface_cnt == IFACE_MAX_CNT)
+		return ERR_PTR(-ENOMEM);
 	if (wl->p2p_supported && (wlif_type != -1)) {
 		if (wl_get_p2p_status(wl, IF_DELETING)) {
 			/* wait till IF_DEL is complete
@@ -809,7 +799,7 @@
 			}
 			WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
 				__func__));
-			timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+			timeout = wait_event_interruptible_timeout(wl->netif_change_event,
 				(wl_get_p2p_status(wl, IF_DELETING) == false),
 				msecs_to_jiffies(MAX_WAIT_TIME));
 
@@ -826,17 +816,24 @@
 				return ERR_PTR(-EAGAIN);
 			}
 		}
-		if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+		if (!p2p_is_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
 			p2p_on(wl) = true;
 			wl_cfgp2p_set_firm_p2p(wl);
 			wl_cfgp2p_init_discovery(wl);
+			get_primary_mac(wl, &primary_mac);
+			wl_cfgp2p_generate_bss_mac(&primary_mac,
+				&wl->p2p->dev_addr, &wl->p2p->int_addr);
 		}
+
 		memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
 		strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
-		wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
 
-		/* Temporary use channel 11, in case GO will be changed with set_channel API  */
-		chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+
+		/* In concurrency case, STA may be already associated in a particular channel.
+		 * so retrieve the current channel of primary interface and then start the virtual
+		 * interface on that.
+		 */
+		 chspec = wl_cfg80211_get_shared_freq(wiphy);
 
 		/* For P2P mode, use P2P-specific driver features to create the
 		 * bss: "wl p2p_ifadd"
@@ -844,10 +841,12 @@
 		wl_set_p2p_status(wl, IF_ADD);
 		err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
 
-		if (unlikely(err))
+		if (unlikely(err)) {
+			WL_ERR((" virtual iface add failed (%d) \n", err));
 			return ERR_PTR(-ENOMEM);
+		}
 
-		timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+		timeout = wait_event_interruptible_timeout(wl->netif_change_event,
 			(wl_get_p2p_status(wl, IF_ADD) == false),
 			msecs_to_jiffies(MAX_WAIT_TIME));
 		if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
@@ -860,25 +859,22 @@
 			}
 			vwdev->wiphy = wl->wdev->wiphy;
 			WL_INFO((" virtual interface(%s) is created memalloc done \n",
-			wl->p2p->vir_ifname));
-			index = alloc_idx_vwdev(wl);
-			wl->vwdev[index] = vwdev;
-			vwdev->iftype =
-				(wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION
-				: NL80211_IFTYPE_AP;
+				wl->p2p->vir_ifname));
+			vwdev->iftype = type;
 			_ndev =  wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
 			_ndev->ieee80211_ptr = vwdev;
 			SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
 			vwdev->netdev = _ndev;
-			wl_set_drv_status(wl, READY);
+			wl_set_drv_status(wl, READY, _ndev);
 			wl->p2p->vif_created = true;
-			set_mode_by_netdev(wl, _ndev, mode);
+			wl_set_mode_by_netdev(wl, _ndev, mode);
 			net_attach =  wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
 			if (rtnl_is_locked()) {
 				rtnl_unlock();
 				rollback_lock = true;
 			}
-			if (net_attach && !net_attach(dhd, _ndev->ifindex)) {
+			if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) {
+				wl_alloc_netinfo(wl, _ndev, vwdev, mode);
 				WL_DBG((" virtual interface(%s) is "
 					"created net attach done\n", wl->p2p->vir_ifname));
 			} else {
@@ -911,30 +907,39 @@
 	s32 timeout = -1;
 	s32 ret = 0;
 	WL_DBG(("Enter\n"));
+
+	if (wl->p2p_net == dev) {
+		/* Since there is no ifidx corresponding to p2p0, cmds to
+		 * firmware should be routed through primary I/F
+		 */
+		dev = wl_to_prmry_ndev(wl);
+	}
+
 	if (wl->p2p_supported) {
 		memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
 		if (wl->p2p->vif_created) {
-			if (wl_get_drv_status(wl, SCANNING)) {
+			if (wl_get_drv_status(wl, SCANNING, dev)) {
 				wl_cfg80211_scan_abort(wl, dev);
 			}
 			wldev_iovar_setint(dev, "mpc", 1);
 			wl_set_p2p_status(wl, IF_DELETING);
 			ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
-			if (ret) {
 			/* Firmware could not delete the interface so we will not get WLC_E_IF
 			* event for cleaning the dhd virtual nw interace
 			* So lets do it here. Failures from fw will ensure the application to do
 			* ifconfig <inter> down and up sequnce, which will reload the fw
 			* however we should cleanup the linux network virtual interfaces
 			*/
-				dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
-				WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
-				WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
-				dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
+			/* Request framework to RESET and clean up */
+			if (ret) {
+				struct net_device *ndev = wl_to_prmry_ndev(wl);
+				WL_ERR(("Firmware returned an error (%d) from p2p_ifdel"
+					"HANG Notification sent to %s\n", ret, ndev->name));
+				wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED);
 			}
 
 			/* Wait for any pending scan req to get aborted from the sysioc context */
-			timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+			timeout = wait_event_interruptible_timeout(wl->netif_change_event,
 				(wl_get_p2p_status(wl, IF_DELETING) == false),
 				msecs_to_jiffies(MAX_WAIT_TIME));
 			if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) {
@@ -961,6 +966,7 @@
 	s32 mode = 0;
 	chanspec_t chspec;
 	struct wl_priv *wl = wiphy_priv(wiphy);
+
 	WL_DBG(("Enter \n"));
 	switch (type) {
 	case NL80211_IFTYPE_MONITOR:
@@ -988,28 +994,33 @@
 		return -EINVAL;
 	}
 
-
 	if (ap) {
-		set_mode_by_netdev(wl, ndev, mode);
+		wl_set_mode_by_netdev(wl, ndev, mode);
 		if (wl->p2p_supported && wl->p2p->vif_created) {
 			WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
 			p2p_on(wl)));
-			chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+			wldev_iovar_setint(ndev, "mpc", 0);
+			/* In concurrency case, STA may be already associated in a particular
+			 * channel. so retrieve the current channel of primary interface and
+			 * then start the virtual interface on that.
+			 */
+			chspec = wl_cfg80211_get_shared_freq(wiphy);
+
 			wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
 			WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
 				ndev->name, ap, infra, type));
 			wl_set_p2p_status(wl, IF_CHANGING);
 			wl_clr_p2p_status(wl, IF_CHANGED);
 			err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
-			timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+			timeout = wait_event_interruptible_timeout(wl->netif_change_event,
 				(wl_get_p2p_status(wl, IF_CHANGED) == true),
 				msecs_to_jiffies(MAX_WAIT_TIME));
-			set_mode_by_netdev(wl, ndev, mode);
+			wl_set_mode_by_netdev(wl, ndev, mode);
 			wl_clr_p2p_status(wl, IF_CHANGING);
 			wl_clr_p2p_status(wl, IF_CHANGED);
 		} else if (ndev == wl_to_prmry_ndev(wl) &&
-			!wl_get_drv_status(wl, AP_CREATED)) {
-			wl_set_drv_status(wl, AP_CREATING);
+			!wl_get_drv_status(wl, AP_CREATED, ndev)) {
+			wl_set_drv_status(wl, AP_CREATING, ndev);
 			if (!wl->ap_info &&
 				!(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) {
 				WL_ERR(("struct ap_saved_ie allocation failed\n"));
@@ -1027,15 +1038,16 @@
 
 s32
 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
-int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
+	void* _net_attach)
 {
 	struct wl_priv *wl = wlcfg_drv_priv;
 	s32 ret = BCME_OK;
+	WL_DBG(("Enter"));
 	if (!ndev) {
 		WL_ERR(("net is NULL\n"));
 		return 0;
 	}
-	if (wl->p2p_supported) {
+	if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) {
 		WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
 			"new name: %s\n", ndev->name, wl->p2p->vir_ifname));
 		/* Assign the net device to CONNECT BSSCFG */
@@ -1046,7 +1058,9 @@
 		ndev->ifindex = idx;
 		wl_clr_p2p_status(wl, IF_ADD);
 
-		wake_up_interruptible(&wl->dongle_event_wait);
+		wake_up_interruptible(&wl->netif_change_event);
+	} else {
+		ret = BCME_NOTREADY;
 	}
 	return ret;
 }
@@ -1063,8 +1077,10 @@
 		return 0;
 	}
 
-	if (p2p_is_on(wl) && wl->p2p->vif_created) {
-		if (wl->scan_request) {
+	if (p2p_is_on(wl) && wl->p2p->vif_created &&
+		wl_get_p2p_status(wl, IF_DELETING)) {
+		if (wl->scan_request &&
+			(wl->escan_info.ndev == ndev)) {
 			/* Abort any pending scan requests */
 			wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
 			if (!rtnl_is_locked()) {
@@ -1072,7 +1088,7 @@
 				rollback_lock = true;
 			}
 			WL_DBG(("ESCAN COMPLETED\n"));
-			wl_notify_escan_complete(wl, true);
+			wl_notify_escan_complete(wl, ndev, true);
 			if (rollback_lock)
 				rtnl_unlock();
 		}
@@ -1091,7 +1107,7 @@
 
 	}
 	/* Wake up any waiting thread */
-	wake_up_interruptible(&wl->dongle_event_wait);
+	wake_up_interruptible(&wl->netif_change_event);
 
 	return 0;
 }
@@ -1123,15 +1139,15 @@
 	struct wl_priv *wl = wlcfg_drv_priv;
 	if (wl_get_p2p_status(wl, IF_CHANGING)) {
 		wl_set_p2p_status(wl, IF_CHANGED);
-		wake_up_interruptible(&wl->dongle_event_wait);
+		wake_up_interruptible(&wl->netif_change_event);
 	}
 	return 0;
 }
 
 static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
 {
-	u32 n_ssids = request->n_ssids;
-	u32 n_channels = request->n_channels;
+	u32 n_ssids;
+	u32 n_channels;
 	u16 channel;
 	chanspec_t chanspec;
 	s32 i, offset;
@@ -1160,6 +1176,13 @@
 	params->passive_time = htod32(params->passive_time);
 	params->home_time = htod32(params->home_time);
 
+	/* if request is null just exit so it will be all channel broadcast scan */
+	if (!request)
+		return;
+
+	n_ssids = request->n_ssids;
+	n_channels = request->n_channels;
+
 	/* Copy channel array if applicable */
 	WL_SCAN(("### List of channelspecs to scan ###\n"));
 	if (n_channels > 0) {
@@ -1248,8 +1271,7 @@
 		return -ENOMEM;
 	}
 
-	if (request != NULL)
-		wl_scan_prep(&params->params, request);
+	wl_scan_prep(&params->params, request);
 
 	params->version = htod32(ISCAN_REQ_VERSION);
 	params->action = htod16(action);
@@ -1261,7 +1283,7 @@
 		goto done;
 	}
 	err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
-		iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
+		iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
 	if (unlikely(err)) {
 		if (err == -EBUSY) {
 			WL_ERR(("system busy : iscan canceled\n"));
@@ -1299,6 +1321,25 @@
 }
 
 static s32
+wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
+{
+	wl_uint32_list_t *list;
+	s32 err = BCME_OK;
+	if (valid_chan_list == NULL || size <= 0)
+		return -ENOMEM;
+
+	memset(valid_chan_list, 0, size);
+	list = (wl_uint32_list_t *)(void *) valid_chan_list;
+	list->count = htod32(WL_NUMCHANNELS);
+	err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false);
+	if (err != 0) {
+		WL_ERR(("get channels failed with %d\n", err));
+	}
+
+	return err;
+}
+
+static s32
 wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
 	struct cfg80211_scan_request *request, uint16 action)
 {
@@ -1306,12 +1347,16 @@
 	u32 n_channels;
 	u32 n_ssids;
 	s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
-	wl_escan_params_t *params;
+	wl_escan_params_t *params = NULL;
 	struct cfg80211_scan_request *scan_request = wl->scan_request;
+	u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
 	u32 num_chans = 0;
+	s32 channel;
+	s32 n_valid_chan;
 	s32 search_state = WL_P2P_DISC_ST_SCAN;
-	u32 i;
+	u32 i, j, n_nodfs = 0;
 	u16 *default_chan_list = NULL;
+	wl_uint32_list_t *list;
 	struct net_device *dev = NULL;
 	WL_DBG(("Enter \n"));
 
@@ -1340,8 +1385,7 @@
 			goto exit;
 		}
 
-		if (request != NULL)
-			wl_scan_prep(&params->params, request);
+		wl_scan_prep(&params->params, request);
 		params->version = htod32(ESCAN_REQ_VERSION);
 		params->action =  htod16(action);
 		params->sync_id = htod16(0x1234);
@@ -1352,13 +1396,15 @@
 			goto exit;
 		}
 		err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
-			wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
+			wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
 		if (unlikely(err))
 			WL_ERR((" Escan set error (%d)\n", err));
 		kfree(params);
 	}
-	else if (p2p_on(wl) && p2p_scan(wl)) {
+	else if (p2p_is_on(wl) && p2p_scan(wl)) {
 		/* P2P SCAN TRIGGER */
+		s32 _freq = 0;
+		n_nodfs = 0;
 		if (scan_request && scan_request->n_channels) {
 			num_chans = scan_request->n_channels;
 			WL_SCAN((" chann number : %d\n", num_chans));
@@ -1369,11 +1415,26 @@
 				err = -ENOMEM;
 				goto exit;
 			}
-			for (i = 0; i < num_chans; i++)
-			{
-				default_chan_list[i] =
-				ieee80211_frequency_to_channel(
-					scan_request->channels[i]->center_freq);
+			if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
+				list = (wl_uint32_list_t *) chan_buf;
+				n_valid_chan = dtoh32(list->count);
+				for (i = 0; i < num_chans; i++)
+				{
+					_freq = scan_request->channels[i]->center_freq;
+					channel = ieee80211_frequency_to_channel(_freq);
+					/* remove DFS channels */
+					if (channel < 52 || channel > 140) {
+						for (j = 0; j < n_valid_chan; j++) {
+							/* allows only supported channel on
+							*  current reguatory
+							*/
+							if (channel == (dtoh32(list->element[j])))
+								default_chan_list[n_nodfs++] =
+									channel;
+						}
+					}
+
+				}
 			}
 			if (num_chans == 3 && (
 						(default_chan_list[0] == SOCIAL_CHAN_1) &&
@@ -1383,12 +1444,15 @@
 				search_state = WL_P2P_DISC_ST_SEARCH;
 				WL_INFO(("P2P SEARCH PHASE START \n"));
 			} else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) &&
-				(get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
+				(wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
 				/* If you are already a GO, then do SEARCH only */
 				WL_INFO(("Already a GO. Do SEARCH Only"));
 				search_state = WL_P2P_DISC_ST_SEARCH;
+				num_chans = n_nodfs;
+
 			} else {
 				WL_INFO(("P2P SCAN STATE START \n"));
+				num_chans = n_nodfs;
 			}
 
 		}
@@ -1413,7 +1477,7 @@
 	s32 passive_scan;
 	wl_scan_results_t *results;
 	WL_SCAN(("Enter \n"));
-
+	wl->escan_info.ndev = ndev;
 	wl->escan_info.wiphy = wiphy;
 	wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
 	passive_scan = wl->active_scan ? 0 : 1;
@@ -1440,36 +1504,41 @@
 	struct wl_priv *wl = wiphy_priv(wiphy);
 	struct cfg80211_ssid *ssids;
 	struct wl_scan_req *sr = wl_to_sr(wl);
+	struct ether_addr primary_mac;
 	wpa_ie_fixed_t *wps_ie;
 	s32 passive_scan;
 	bool iscan_req;
 	bool escan_req;
-	bool spec_scan;
 	bool p2p_ssid;
 	s32 err = 0;
 	s32 i;
 	u32 wpsie_len = 0;
 	u8 wpsie[IE_MAX_LEN];
 
+	/* If scan req comes for p2p0, send it over primary I/F
+	 * Scan results will be delivered corresponding to cfg80211_scan_request
+	 */
+	if (ndev == wl->p2p_net) {
+		ndev = wl_to_prmry_ndev(wl);
+	}
+
 	WL_DBG(("Enter wiphy (%p)\n", wiphy));
-	if (unlikely(wl_get_drv_status(wl, SCANNING))) {
-		WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
+	if (wl_get_drv_status_all(wl, SCANNING)) {
+		WL_ERR(("Scanning already\n"));
 		return -EAGAIN;
 	}
-	if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) {
-		WL_ERR(("Scanning being aborted : status (%d)\n",
-			(int)wl->status));
+	if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) {
+		WL_ERR(("Scanning being aborted\n"));
 		return -EAGAIN;
 	}
-	if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
-		WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
+	if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
+		WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
 		return -EOPNOTSUPP;
 	}
 
 	/* Arm scan timeout timer */
 	mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000);
 	iscan_req = false;
-	spec_scan = false;
 	if (request) {		/* scan bss */
 		ssids = request->ssids;
 		if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) {
@@ -1490,6 +1559,9 @@
 						/* p2p on at the first time */
 						p2p_on(wl) = true;
 						wl_cfgp2p_set_firm_p2p(wl);
+						get_primary_mac(wl, &primary_mac);
+						wl_cfgp2p_generate_bss_mac(&primary_mac,
+							&wl->p2p->dev_addr, &wl->p2p->int_addr);
 					}
 					p2p_scan(wl) = true;
 				}
@@ -1543,7 +1615,7 @@
 		ssids = this_ssid;
 	}
 	wl->scan_request = request;
-	wl_set_drv_status(wl, SCANNING);
+	wl_set_drv_status(wl, SCANNING, ndev);
 	if (iscan_req) {
 		err = wl_do_iscan(wl, request);
 		if (likely(!err))
@@ -1578,7 +1650,6 @@
 			sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
 			WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n",
 				sr->ssid.SSID, sr->ssid.SSID_len));
-			spec_scan = true;
 		} else {
 			WL_SCAN(("Broadcast scan\n"));
 		}
@@ -1606,7 +1677,7 @@
 	return 0;
 
 scan_out:
-	wl_clr_drv_status(wl, SCANNING);
+	wl_clr_drv_status(wl, SCANNING, ndev);
 	wl->scan_request = NULL;
 	return err;
 }
@@ -1630,52 +1701,11 @@
 	return err;
 }
 
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
-{
-	s8 buf[WLC_IOCTL_SMLEN];
-	u32 len;
-	s32 err = 0;
-
-	val = htod32(val);
-	len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
-	BUG_ON(unlikely(!len));
-
-	err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false);
-	if (unlikely(err)) {
-		WL_ERR(("error (%d)\n", err));
-	}
-
-	return err;
-}
-
-static s32
-wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
-{
-	union {
-		s8 buf[WLC_IOCTL_SMLEN];
-		s32 val;
-	} var;
-	u32 len;
-	u32 data_null;
-	s32 err = 0;
-
-	len = bcm_mkiovar(name, (char *)(&data_null), 0,
-		(char *)(&var), sizeof(var.buf));
-	BUG_ON(unlikely(!len));
-	err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false);
-	if (unlikely(err)) {
-		WL_ERR(("error (%d)\n", err));
-	}
-	*retval = dtoh32(var.val);
-
-	return err;
-}
-
 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
 {
 	s32 err = 0;
 
-	err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
+	err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
 	if (unlikely(err)) {
 		WL_ERR(("Error (%d)\n", err));
 		return err;
@@ -1687,7 +1717,7 @@
 {
 	s32 err = 0;
 
-	err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
+	err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
 	if (unlikely(err)) {
 		WL_ERR(("Error (%d)\n", err));
 		return err;
@@ -1716,6 +1746,7 @@
 	s32 err = 0;
 
 	CHECK_SYS_UP(wl);
+	WL_DBG(("Enter\n"));
 	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
 		(wl->conf->rts_threshold != wiphy->rts_threshold)) {
 		wl->conf->rts_threshold = wiphy->rts_threshold;
@@ -1745,7 +1776,6 @@
 			return err;
 		}
 	}
-
 	return err;
 }
 
@@ -1862,7 +1892,7 @@
 		WL_ERR(("set wpa_auth failed (%d)\n", err));
 		return err;
 	}
-	sec = wl_read_prof(wl, WL_PROF_SEC);
+	sec = wl_read_prof(wl, dev, WL_PROF_SEC);
 	sec->wpa_versions = sme->crypto.wpa_versions;
 	return err;
 }
@@ -1901,7 +1931,7 @@
 		WL_ERR(("set auth failed (%d)\n", err));
 		return err;
 	}
-	sec = wl_read_prof(wl, WL_PROF_SEC);
+	sec = wl_read_prof(wl, dev, WL_PROF_SEC);
 	sec->auth_type = sme->auth_type;
 	return err;
 }
@@ -1973,7 +2003,7 @@
 		return err;
 	}
 
-	sec = wl_read_prof(wl, WL_PROF_SEC);
+	sec = wl_read_prof(wl, dev, WL_PROF_SEC);
 	sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
 	sec->cipher_group = sme->crypto.cipher_group;
 
@@ -1990,7 +2020,7 @@
 	s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
 
 	if (sme->crypto.n_akm_suites) {
-		err = wl_dev_intvar_get(dev, "wpa_auth", &val);
+		err = wldev_iovar_getint(dev, "wpa_auth", &val);
 		if (unlikely(err)) {
 			WL_ERR(("could not get wpa_auth (%d)\n", err));
 			return err;
@@ -2030,7 +2060,7 @@
 			return err;
 		}
 	}
-	sec = wl_read_prof(wl, WL_PROF_SEC);
+	sec = wl_read_prof(wl, dev, WL_PROF_SEC);
 	sec->wpa_auth = sme->crypto.akm_suites[0];
 
 	return err;
@@ -2049,13 +2079,14 @@
 
 	WL_DBG(("key len (%d)\n", sme->key_len));
 	if (sme->key_len) {
-		sec = wl_read_prof(wl, WL_PROF_SEC);
+		sec = wl_read_prof(wl, dev, WL_PROF_SEC);
 		WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
 			sec->wpa_versions, sec->cipher_pairwise));
 		if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
 			NL80211_WPA_VERSION_2)) &&
 			(sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
-			WLAN_CIPHER_SUITE_WEP104))) {
+		WLAN_CIPHER_SUITE_WEP104)))
+		{
 			memset(&key, 0, sizeof(key));
 			key.len = (u32) sme->key_len;
 			key.index = (u32) sme->key_idx;
@@ -2083,7 +2114,7 @@
 			WL_DBG(("key \"%s\"\n", key.data));
 			swap_key_from_BE(&key);
 			err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
-				ioctlbuf, sizeof(ioctlbuf), bssidx);
+				wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 			if (unlikely(err)) {
 				WL_ERR(("WLC_SET_KEY error (%d)\n", err));
 				return err;
@@ -2133,11 +2164,11 @@
 	}
 	/* Clean BSSID */
 	bzero(&bssid, sizeof(bssid));
-	wl_update_prof(wl, NULL, (void *)&bssid, WL_PROF_BSSID);
+	wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
 
 	if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) {
 		/* we only allow to connect using virtual interface in case of P2P */
-		if (p2p_on(wl) && is_wps_conn(sme)) {
+		if (p2p_is_on(wl) && is_wps_conn(sme)) {
 			WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n",
 				wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
 			/* Have to apply WPS IE + P2P IE in assoc req frame */
@@ -2148,7 +2179,7 @@
 				P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len);
 			wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
 				VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
-		} else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
+		} else if (p2p_is_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
 			/* This is the connect req after WPS is done [credentials exchanged]
 			 * currently identified with WPA_VERSION_2 .
 			 * Update the previously set IEs with
@@ -2177,10 +2208,10 @@
 				wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
 				wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
 				wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
-				ioctlbuf, sizeof(ioctlbuf));
+					wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 			} else {
 				wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
-				ioctlbuf, sizeof(ioctlbuf));
+					wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 			}
 
 			/* find the WPSIE */
@@ -2249,7 +2280,7 @@
 	ext_join_params =  (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
 	if (ext_join_params == NULL) {
 		err = -ENOMEM;
-		wl_clr_drv_status(wl, CONNECTING);
+		wl_clr_drv_status(wl, CONNECTING, dev);
 		goto exit;
 	}
 	ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
@@ -2258,12 +2289,13 @@
 	/* Set up join scan parameters */
 	ext_join_params->scan.scan_type = -1;
 	ext_join_params->scan.nprobes = 2;
-	/* increate dwell time to receive probe response
-	* from target AP at a noisy air
+	/* increate dwell time to receive probe response or detect Beacon
+	* from target AP at a noisy air only during connect command
 	*/
-	ext_join_params->scan.active_time = 150;
-	ext_join_params->scan.passive_time = 300;
+	ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*3;
+	ext_join_params->scan.passive_time = WL_SCAN_PASSIVE_TIME*3;
 	ext_join_params->scan.home_time = -1;
+
 	if (sme->bssid)
 		memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
 	else
@@ -2288,12 +2320,12 @@
 		WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
 			ext_join_params->ssid.SSID_len));
 	}
-	wl_set_drv_status(wl, CONNECTING);
-	err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf,
-		sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev));
+	wl_set_drv_status(wl, CONNECTING, dev);
+	err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
+		wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync);
 	kfree(ext_join_params);
 	if (err) {
-		wl_clr_drv_status(wl, CONNECTING);
+		wl_clr_drv_status(wl, CONNECTING, dev);
 		if (err == BCME_UNSUPPORTED) {
 			WL_DBG(("join iovar is not supported\n"));
 			goto set_ssid;
@@ -2309,7 +2341,7 @@
 	join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
 	memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
 	join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
-	wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
+	wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID);
 	if (sme->bssid)
 		memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
 	else
@@ -2322,11 +2354,11 @@
 		WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
 			join_params.ssid.SSID_len));
 	}
-	wl_set_drv_status(wl, CONNECTING);
+	wl_set_drv_status(wl, CONNECTING, dev);
 	err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
 	if (err) {
 		WL_ERR(("error (%d)\n", err));
-		wl_clr_drv_status(wl, CONNECTING);
+		wl_clr_drv_status(wl, CONNECTING, dev);
 	}
 exit:
 	return err;
@@ -2343,23 +2375,23 @@
 	u8 *curbssid;
 	WL_ERR(("Reason %d\n", reason_code));
 	CHECK_SYS_UP(wl);
-	act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
-	curbssid = wl_read_prof(wl, WL_PROF_BSSID);
-	if (likely(act)) {
+	act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT);
+	curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID);
+	if (act) {
 		/*
 		* Cancel ongoing scan to sync up with sme state machine of cfg80211.
 		*/
 		if (wl->scan_request) {
 			wl_cfg80211_scan_abort(wl, dev);
 		}
-		wl_set_drv_status(wl, DISCONNECTING);
+		wl_set_drv_status(wl, DISCONNECTING, dev);
 		scbval.val = reason_code;
 		memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
 		scbval.val = htod32(scbval.val);
 		err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
 			sizeof(scb_val_t), true);
 		if (unlikely(err)) {
-			wl_clr_drv_status(wl, DISCONNECTING);
+			wl_clr_drv_status(wl, DISCONNECTING, dev);
 			WL_ERR(("error (%d)\n", err));
 			return err;
 		}
@@ -2409,7 +2441,7 @@
 		txpwrmw = 0xffff;
 	else
 		txpwrmw = (u16) dbm;
-	err = wl_dev_intvar_set(ndev, "qtxpower",
+	err = wldev_iovar_setint(ndev, "qtxpower",
 		(s32) (bcm_mw_to_qdbm(txpwrmw)));
 	if (unlikely(err)) {
 		WL_ERR(("qtxpower error (%d)\n", err));
@@ -2429,7 +2461,7 @@
 	s32 err = 0;
 
 	CHECK_SYS_UP(wl);
-	err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
+	err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm);
 	if (unlikely(err)) {
 		WL_ERR(("error (%d)\n", err));
 		return err;
@@ -2478,7 +2510,7 @@
 	struct wl_wsec_key key;
 	s32 err = 0;
 	s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
-	s32 mode = get_mode_by_netdev(wl, dev);
+	s32 mode = wl_get_mode_by_netdev(wl, dev);
 	memset(&key, 0, sizeof(key));
 	key.index = (u32) key_idx;
 
@@ -2490,8 +2522,8 @@
 	if (key.len == 0) {
 		/* key delete */
 		swap_key_from_BE(&key);
-		wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-			sizeof(ioctlbuf), bssidx);
+		wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+			wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 		if (unlikely(err)) {
 			WL_ERR(("key delete error (%d)\n", err));
 			return err;
@@ -2549,11 +2581,11 @@
 			return -EINVAL;
 		}
 		swap_key_from_BE(&key);
-#ifdef CONFIG_WIRELESS_EXT
+#if defined(CONFIG_WIRELESS_EXT)
 		dhd_wait_pend8021x(dev);
 #endif
-		wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-			sizeof(ioctlbuf), bssidx);
+		wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+			wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 		if (unlikely(err)) {
 			WL_ERR(("WLC_SET_KEY error (%d)\n", err));
 			return err;
@@ -2574,7 +2606,7 @@
 	u8 keybuf[8];
 	s32 bssidx = 0;
 	struct wl_priv *wl = wiphy_priv(wiphy);
-	s32 mode = get_mode_by_netdev(wl, dev);
+	s32 mode = wl_get_mode_by_netdev(wl, dev);
 	WL_DBG(("key index (%d)\n", key_idx));
 	CHECK_SYS_UP(wl);
 
@@ -2635,8 +2667,8 @@
 
 	/* Set the new key/index */
 	swap_key_from_BE(&key);
-	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-		sizeof(ioctlbuf), bssidx);
+	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+		WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 	if (unlikely(err)) {
 		WL_ERR(("WLC_SET_KEY error (%d)\n", err));
 		return err;
@@ -2672,15 +2704,15 @@
 	CHECK_SYS_UP(wl);
 	memset(&key, 0, sizeof(key));
 
-	key.index = (u32) key_idx;
 	key.flags = WL_PRIMARY_KEY;
 	key.algo = CRYPTO_ALGO_OFF;
+	key.index = (u32) key_idx;
 
 	WL_DBG(("key index (%d)\n", key_idx));
 	/* Set the new key/index */
 	swap_key_from_BE(&key);
-	wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-		sizeof(ioctlbuf), bssidx);
+	wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+		WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 	if (unlikely(err)) {
 		if (err == -EINVAL) {
 			if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
@@ -2724,7 +2756,7 @@
 	}
 	switch (wsec & ~SES_OW_ENABLED) {
 		case WEP_ENABLED:
-			sec = wl_read_prof(wl, WL_PROF_SEC);
+			sec = wl_read_prof(wl, dev, WL_PROF_SEC);
 			if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
 				params.cipher = WLAN_CIPHER_SUITE_WEP40;
 				WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
@@ -2774,15 +2806,15 @@
 	dhd_pub_t *dhd =  (dhd_pub_t *)(wl->pub);
 
 	CHECK_SYS_UP(wl);
-	if (get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
+	if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
 		err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
-			ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf));
+			ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 		if (err < 0) {
 			WL_ERR(("GET STA INFO failed, %d\n", err));
 			return err;
 		}
 		sinfo->filled = STATION_INFO_INACTIVE_TIME;
-		sta = (sta_info_t *)ioctlbuf;
+		sta = (sta_info_t *)wl->ioctl_buf;
 		sta->len = dtoh16(sta->len);
 		sta->cap = dtoh16(sta->cap);
 		sta->flags = dtoh32(sta->flags);
@@ -2798,10 +2830,9 @@
 			bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
 			sta->idle * 1000));
 #endif
-	} else if (get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
-			u8 *curmacp = wl_read_prof(wl, WL_PROF_BSSID);
-
-			if (!wl_get_drv_status(wl, CONNECTED) ||
+	} else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
+			u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
+			if (!wl_get_drv_status(wl, CONNECTED, dev) ||
 			    (dhd_is_associated(dhd, NULL) == FALSE)) {
 				WL_ERR(("NOT assoc\n"));
 				err = -ENODEV;
@@ -2841,7 +2872,7 @@
 		if (err) {
 			/* Disconnect due to zero BSSID or error to get RSSI */
 			WL_ERR(("force cfg80211_disconnected\n"));
-			wl_clr_drv_status(wl, CONNECTED);
+			wl_clr_drv_status(wl, CONNECTED, dev);
 			cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL);
 			wl_link_down(wl);
 		}
@@ -2859,6 +2890,11 @@
 	struct wl_priv *wl = wiphy_priv(wiphy);
 
 	CHECK_SYS_UP(wl);
+
+	if (wl->p2p_net == dev) {
+		return err;
+	}
+
 	pm = enabled ? PM_FAST : PM_OFF;
 	/* Do not enable the power save after assoc if it is p2p interface */
 	if (wl->p2p && wl->p2p->vif_created) {
@@ -2908,11 +2944,11 @@
 static s32 wl_cfg80211_resume(struct wiphy *wiphy)
 {
 	struct wl_priv *wl = wiphy_priv(wiphy);
+	struct net_device *ndev = wl_to_prmry_ndev(wl);
 	s32 err = 0;
 
-	if (unlikely(!wl_get_drv_status(wl, READY))) {
-		WL_INFO(("device is not ready : status (%d)\n",
-			(int)wl->status));
+	if (unlikely(!wl_get_drv_status(wl, READY, ndev))) {
+		WL_INFO(("device is not ready\n"));
 		return 0;
 	}
 
@@ -2929,33 +2965,38 @@
 {
 #ifdef DHD_CLEAR_ON_SUSPEND
 	struct wl_priv *wl = wiphy_priv(wiphy);
+	struct net_info *iter, *next;
 	struct net_device *ndev = wl_to_prmry_ndev(wl);
 	unsigned long flags;
 
-	if (unlikely(!wl_get_drv_status(wl, READY))) {
+	if (unlikely(!wl_get_drv_status(wl, READY, ndev))) {
 		WL_INFO(("device is not ready : status (%d)\n",
 			(int)wl->status));
 		return 0;
 	}
-
-	wl_set_drv_status(wl, SCAN_ABORTING);
+	for_each_ndev(wl, iter, next)
+		wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
 	wl_term_iscan(wl);
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 	if (wl->scan_request) {
 		cfg80211_scan_done(wl->scan_request, true);
 		wl->scan_request = NULL;
 	}
-	wl_clr_drv_status(wl, SCANNING);
-	wl_clr_drv_status(wl, SCAN_ABORTING);
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
-	if (wl_get_drv_status(wl, CONNECTING)) {
-		wl_bss_connect_done(wl, ndev, NULL, NULL, false);
+	for_each_ndev(wl, iter, next) {
+		wl_clr_drv_status(wl, SCANNING, iter->ndev);
+		wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev);
 	}
-#endif
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+	for_each_ndev(wl, iter, next) {
+		if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) {
+			wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false);
+		}
+	}
+#endif /* DHD_CLEAR_ON_SUSPEND */
 	return 0;
 }
 
-static __used s32
+static s32
 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
 	s32 err)
 {
@@ -2963,9 +3004,12 @@
 	struct wl_priv *wl = wlcfg_drv_priv;
 	struct net_device *primary_dev = wl_to_prmry_ndev(wl);
 
-	/* Firmware is supporting pmk list only for STA interface i.e. primary interface
+	if (!pmk_list) {
+		printk("pmk_list is NULL\n");
+		return -EINVAL;
+	}
+	/* pmk list is supported only for STA interface i.e. primary interface
 	  * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
-	  * Do we really need to support PMK cache in P2P in firmware?
 	*/
 	if (primary_dev != dev) {
 		WL_INFO(("Not supporting Flushing pmklist on virtual"
@@ -2982,8 +3026,8 @@
 		}
 	}
 	if (likely(!err)) {
-		err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
-			sizeof(*pmk_list));
+		err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
+			sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
 	}
 
 	return err;
@@ -3084,7 +3128,7 @@
 
 }
 
-wl_scan_params_t *
+static wl_scan_params_t *
 wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
 {
 	wl_scan_params_t *params;
@@ -3145,13 +3189,13 @@
 		}
 	}
 	del_timer_sync(&wl->scan_timeout);
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 	if (wl->scan_request) {
 		cfg80211_scan_done(wl->scan_request, true);
 		wl->scan_request = NULL;
 	}
-	wl_clr_drv_status(wl, SCANNING);
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	wl_clr_drv_status(wl, SCANNING, ndev);
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 	if (params)
 		kfree(params);
 	return err;
@@ -3164,36 +3208,49 @@
 	unsigned int duration, u64 *cookie)
 {
 	s32 target_channel;
+	u32 id;
+	struct ether_addr primary_mac;
+	struct net_device *ndev = NULL;
 
 	s32 err = BCME_OK;
 	struct wl_priv *wl = wiphy_priv(wiphy);
-	dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
 	WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
-	if (likely(wl_get_drv_status(wl, SCANNING))) {
-		wl_cfg80211_scan_abort(wl, dev);
+
+	if (wl->p2p_net == dev) {
+		ndev = wl_to_prmry_ndev(wl);
+	} else {
+		ndev = dev;
+	}
+
+	if (wl_get_drv_status(wl, SCANNING, ndev)) {
+		wl_cfg80211_scan_abort(wl, ndev);
 	}
 
 	target_channel = ieee80211_frequency_to_channel(channel->center_freq);
 	memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel));
 	wl->remain_on_chan_type = channel_type;
-	wl->cache_cookie = *cookie;
+	id = ++wl->last_roc_id;
+	if (id == 0)
+		id = ++wl->last_roc_id;
+	*cookie = id;
 	cfg80211_ready_on_channel(dev, *cookie, channel,
 		channel_type, duration, GFP_KERNEL);
-	if (!p2p_on(wl)) {
-		wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+	if (!p2p_is_on(wl)) {
+		get_primary_mac(wl, &primary_mac);
+		wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
 
 		/* In case of p2p_listen command, supplicant send remain_on_channel
 		 * without turning on P2P
 		 */
 
 		p2p_on(wl) = true;
-		err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
+		err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0);
 
 		if (unlikely(err)) {
 			goto exit;
 		}
 	}
-	if (p2p_on(wl))
+	if (p2p_is_on(wl))
 		wl_cfgp2p_discover_listen(wl, target_channel, duration);
 
 
@@ -3211,7 +3268,94 @@
 }
 
 static s32
-wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl)
+{
+	wl_af_params_t *tx_act_frm;
+	struct net_device *dev = wl->afx_hdl->dev;
+	if (!p2p_is_on(wl))
+		return -1;
+
+	if (dev == wl->p2p_net) {
+		dev = wl_to_prmry_ndev(wl);
+	}
+
+	tx_act_frm = wl->afx_hdl->pending_tx_act_frm;
+	WL_DBG(("Sending the action frame\n"));
+	wl->afx_hdl->pending_tx_act_frm = NULL;
+	if (tx_act_frm != NULL) {
+		/* Suspend P2P discovery's search-listen to prevent it from
+		 * starting a scan or changing the channel.
+		 */
+		wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev);
+		wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+		wl_cfg80211_scan_abort(wl, dev);
+		wl_cfgp2p_discover_enable_search(wl, false);
+		tx_act_frm->channel = wl->afx_hdl->peer_chan;
+		wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev,
+			tx_act_frm, wl->afx_hdl->bssidx)) ? false : true;
+	}
+	return 0;
+}
+static void
+wl_cfg80211_afx_handler(struct work_struct *work)
+{
+
+	struct afx_hdl *afx_instance;
+	struct wl_priv *wl = wlcfg_drv_priv;
+	afx_instance = container_of(work, struct afx_hdl, work);
+	if (afx_instance != NULL) {
+		wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev,
+			wl->afx_hdl->bssidx, 0);
+	}
+}
+
+static bool
+wl_cfg80211_send_at_common_channel(struct wl_priv *wl,
+	struct net_device *dev,
+	wl_af_params_t *af_params)
+{
+	WL_DBG((" enter ) \n"));
+	/* initialize afx_hdl */
+	wl->afx_hdl->pending_tx_act_frm = af_params;
+	wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev);
+	wl->afx_hdl->dev = dev;
+	wl->afx_hdl->retry = 0;
+	wl->afx_hdl->peer_chan = WL_INVALID;
+	wl->afx_hdl->ack_recv = false;
+	memcpy(wl->afx_hdl->pending_tx_dst_addr.octet,
+		af_params->action_frame.da.octet,
+		sizeof(wl->afx_hdl->pending_tx_dst_addr.octet));
+	/* Loop to wait until we have sent the pending tx action frame or the
+	 * pending action frame tx is cancelled.
+	 */
+	while ((wl->afx_hdl->retry < WL_CHANNEL_SYNC_RETRY) &&
+		(wl->afx_hdl->peer_chan == WL_INVALID)) {
+		wl_set_drv_status(wl, SENDING_ACT_FRM, dev);
+		wl_set_drv_status(wl, SCANNING, dev);
+		WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
+			wl->afx_hdl->retry));
+		/* Do find_peer_for_action */
+		schedule_work(&wl->afx_hdl->work);
+		wait_for_completion(&wl->act_frm_scan);
+		wl->afx_hdl->retry++;
+	}
+	if (wl->afx_hdl->peer_chan != WL_INVALID)
+		wl_cfg80211_send_pending_tx_act_frm(wl);
+	else {
+		WL_ERR(("Couldn't find the peer after %d retries\n",
+			wl->afx_hdl->retry));
+	}
+	wl->afx_hdl->dev = NULL;
+	wl->afx_hdl->bssidx = WL_INVALID;
+	wl_clr_drv_status(wl, SENDING_ACT_FRM, dev);
+	if (wl->afx_hdl->ack_recv)
+		return true; /* ACK */
+	else
+		return false; /* NO ACK */
+}
+
+static s32
+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
 	struct ieee80211_channel *channel, bool offchan,
 	enum nl80211_channel_type channel_type,
 	bool channel_type_valid, unsigned int wait,
@@ -3221,29 +3365,39 @@
 	wl_af_params_t *af_params;
 	wifi_p2p_ie_t *p2p_ie;
 	wpa_ie_fixed_t *wps_ie;
+	scb_val_t scb_val;
 	const struct ieee80211_mgmt *mgmt;
 	struct wl_priv *wl = wiphy_priv(wiphy);
-	dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+	struct net_device *dev = NULL;
 	s32 err = BCME_OK;
 	s32 bssidx = 0;
 	u32 p2pie_len = 0;
 	u32 wpsie_len = 0;
-	u16 fc;
+	u32 id;
+	u32 retry = 0;
 	bool ack = false;
-	wifi_p2p_pub_act_frame_t *act_frm;
+	wifi_p2p_pub_act_frame_t *act_frm = NULL;
+	wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+	wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
+	s8 eabuf[ETHER_ADDR_STR_LEN];
+
 	WL_DBG(("Enter \n"));
+
+	if (ndev == wl->p2p_net) {
+		dev = wl_to_prmry_ndev(wl);
+	} else {
+		/* If TX req is for any valid ifidx. Use as is */
+		dev = ndev;
+	}
+
 	/* find bssidx based on ndev */
 	bssidx = wl_cfgp2p_find_idx(wl, dev);
-	/* cookie generation */
-	*cookie = (unsigned long) buf;
-
 	if (bssidx == -1) {
 
 		WL_ERR(("Can not find the bssidx for dev( %p )\n", dev));
 		return -ENODEV;
 	}
-	if (wl->p2p_supported && p2p_on(wl)) {
-		wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+	if (p2p_is_on(wl)) {
 		/* Suspend P2P discovery search-listen to prevent it from changing the
 		 * channel.
 		 */
@@ -3252,31 +3406,27 @@
 			return -EFAULT;
 		}
 	}
-
-	mgmt = (const struct ieee80211_mgmt *) buf;
-	fc = mgmt->frame_control;
-	if (fc != IEEE80211_STYPE_ACTION) {
-		if (fc == IEEE80211_STYPE_PROBE_RESP) {
+	*cookie = 0;
+	id = wl->send_action_id++;
+	if (id == 0)
+		id = wl->send_action_id++;
+	*cookie = id;
+	mgmt = (const struct ieee80211_mgmt *)buf;
+	if (ieee80211_is_mgmt(mgmt->frame_control)) {
+		if (ieee80211_is_probe_resp(mgmt->frame_control)) {
 			s32 ie_offset =  DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
 			s32 ie_len = len - ie_offset;
 			if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len))
 				!= NULL) {
 				/* Total length of P2P Information Element */
 				p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
-				/* Have to change p2p device address in dev_info attribute
-				 * because Supplicant use primary eth0 address
-				 */
-			#ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
-				wl_cfg80211_change_ifaddr((u8 *)p2p_ie,
-					&wl->p2p_dev_addr, P2P_SEID_DEV_INFO);
-			#endif
 			}
 			if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len))
 				!= NULL) {
 				/* Order of Vendor IE is 1) WPS IE +
 				 * 2) P2P IE created by supplicant
 				 *  So, it is ok to find start address of WPS IE
-				 *  to save IEs to firmware
+				 *  to save IEs
 				 */
 				wpsie_len = wps_ie->length + sizeof(wps_ie->length) +
 					sizeof(wps_ie->tag);
@@ -3284,18 +3434,36 @@
 					VNDR_IE_PRBRSP_FLAG,
 					(u8 *)wps_ie, wpsie_len + p2pie_len);
 			}
+			cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+			goto exit;
+		} else if (ieee80211_is_disassoc(mgmt->frame_control) ||
+			ieee80211_is_deauth(mgmt->frame_control)) {
+			memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
+			scb_val.val = mgmt->u.disassoc.reason_code;
+			wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+				sizeof(scb_val_t), true);
+			WL_DBG(("Disconnect STA : %s\n",
+				bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf)));
+			cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+			goto exit;
+
+		} else if (ieee80211_is_action(mgmt->frame_control)) {
+			/* Abort the dwell time of any previous off-channel
+			* action frame that may be still in effect.  Sending
+			* off-channel action frames relies on the driver's
+			* scan engine.  If a previous off-channel action frame
+			* tx is still in progress (including the dwell time),
+			* then this new action frame will not be sent out.
+			*/
+			wl_cfg80211_scan_abort(wl, dev);
+
 		}
-		cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
-		goto exit;
+
 	} else {
-	    /* Abort the dwell time of any previous off-channel action frame that may
-	     * be still in effect.  Sending off-channel action frames relies on the
-	     * driver's scan engine.  If a previous off-channel action frame tx is
-	     * still in progress (including the dwell time), then this new action
-	     * frame will not be sent out.
-	     */
-		wl_cfg80211_scan_abort(wl, dev);
+		WL_ERR(("Driver only allows MGMT packet type\n"));
+		goto exit;
 	}
+
 	af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
 
 	if (af_params == NULL)
@@ -3307,7 +3475,7 @@
 	action_frame = &af_params->action_frame;
 
 	/* Add the packet Id */
-	action_frame->packetId = (u32) action_frame;
+	action_frame->packetId = *cookie;
 	WL_DBG(("action frame %d\n", action_frame->packetId));
 	/* Add BSSID */
 	memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
@@ -3321,6 +3489,14 @@
 	af_params->channel =
 		ieee80211_frequency_to_channel(channel->center_freq);
 
+	if (channel->band == IEEE80211_BAND_5GHZ) {
+		err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+			&af_params->channel, sizeof(af_params->channel), true);
+		if (err < 0) {
+			WL_ERR(("WLC_SET_CHANNEL error %d\n", err));
+		}
+	}
+
 	/* Add the dwell time
 	 * Dwell time to stay off-channel to wait for a response action frame
 	 * after transmitting an GO Negotiation action frame
@@ -3328,28 +3504,82 @@
 	af_params->dwell_time = WL_DWELL_TIME;
 
 	memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
+	if (wl_cfgp2p_is_pub_action(action_frame->data, action_frame->len)) {
+		act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
+		WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n",
+			action_frame->len, af_params->channel,
+			act_frm->category, act_frm->subtype));
+	} else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) {
+		p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data);
+		WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n",
+			action_frame->len, af_params->channel,
+			p2p_act_frm->category, p2p_act_frm->subtype));
+	} else if (wl_cfgp2p_is_gas_action(action_frame->data, action_frame->len)) {
+		sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (action_frame->data);
+		WL_DBG(("Service Discovery action_frame->len: %d chan %d category %d action %d\n",
+			action_frame->len, af_params->channel,
+			sd_act_frm->category, sd_act_frm->action));
 
-	act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
-	WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n",
-		action_frame->len, af_params->channel,
-		act_frm->category, act_frm->subtype));
-	if (wl->p2p->vif_created) {
+	}
+	wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len);
 		/*
 		 * To make sure to send successfully action frame, we have to turn off mpc
 		 */
-		if ((act_frm->subtype == P2P_PAF_GON_REQ)||
-		  (act_frm->subtype == P2P_PAF_GON_RSP)) {
-			wldev_iovar_setint(dev, "mpc", 0);
-		} else if (act_frm->subtype == P2P_PAF_GON_CONF) {
-			wldev_iovar_setint(dev, "mpc", 1);
-		} else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
-			af_params->dwell_time = WL_LONG_DWELL_TIME;
-		}
+
+	if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) ||
+	  (act_frm->subtype == P2P_PAF_GON_RSP) ||
+	  (act_frm->subtype == P2P_PAF_GON_CONF) ||
+	  (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
+		wldev_iovar_setint(dev, "mpc", 0);
 	}
 
-	ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
-	cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL);
+	if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
+		af_params->dwell_time = WL_LONG_DWELL_TIME;
+	} else if (act_frm &&
+		(act_frm->subtype == P2P_PAF_PROVDIS_REQ ||
+		act_frm->subtype == P2P_PAF_PROVDIS_RSP ||
+		act_frm->subtype == P2P_PAF_GON_RSP)) {
+		af_params->dwell_time = WL_MED_DWELL_TIME;
+	}
 
+	if (IS_P2P_SOCIAL(af_params->channel) &&
+		(IS_P2P_PUB_ACT_REQ(act_frm, action_frame->len) ||
+		IS_GAS_REQ(sd_act_frm, action_frame->len)) &&
+		wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) {
+		/* channel offload require P2P IE for Probe request
+		 * otherwise, we will use wl_cfgp2p_tx_action_frame directly.
+		 * channel offload for action request frame
+		 */
+
+		/* channel offload for action request frame */
+		ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params);
+	} else {
+		ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
+		if (!ack) {
+			if (wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) {
+				/* if the NO ACK occurs, the peer device will be on
+				* listen channel of the peer
+				* So, we have to find the peer and send action frame on
+				* that channel.
+				*/
+				ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params);
+			} else {
+				for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) {
+					ack = (wl_cfgp2p_tx_action_frame(wl, dev,
+						af_params, bssidx)) ? false : true;
+					if (ack)
+						break;
+				}
+
+			}
+
+		}
+
+	}
+	cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL);
+	if (act_frm && act_frm->subtype == P2P_PAF_GON_CONF) {
+		wldev_iovar_setint(dev, "mpc", 1);
+	}
 	kfree(af_params);
 exit:
 	return err;
@@ -3403,7 +3633,11 @@
 {
 	s32 channel;
 	s32 err = BCME_OK;
+	struct wl_priv *wl = wiphy_priv(wiphy);
 
+	if (wl->p2p_net == dev) {
+		dev = wl_to_prmry_ndev(wl);
+	}
 	channel = ieee80211_frequency_to_channel(chan->center_freq);
 	WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
 		dev->ifindex, channel_type, channel));
@@ -3420,7 +3654,6 @@
 	s32 len = 0;
 	s32 err = BCME_OK;
 	u16 auth = 0; /* d11 open authentication */
-	u16 count;
 	u32 wsec;
 	u32 pval = 0;
 	u32 gval = 0;
@@ -3458,7 +3691,7 @@
 	len -= WPA_SUITE_LEN;
 	/* check the unicast cipher */
 	ucast = (wpa_suite_ucast_t *)&mcast[1];
-	count = ltoh16_ua(&ucast->count);
+	ltoh16_ua(&ucast->count);
 	tmp = ucast->list[0].oui;
 	switch (tmp[DOT11_OUI_LEN]) {
 		case WPA_CIPHER_NONE:
@@ -3481,7 +3714,7 @@
 	wsec = (pval | gval | SES_OW_ENABLED);
 	/* check the AKM */
 	mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1];
-	count = ltoh16_ua(&mgmt->count);
+	ltoh16_ua(&mgmt->count);
 	tmp = (u8 *)&mgmt->list[0];
 	switch (tmp[DOT11_OUI_LEN]) {
 		case RSN_AKM_NONE:
@@ -3684,13 +3917,19 @@
 	u16 p2pie_len = 0;
 	u8 beacon_ie[IE_MAX_LEN];
 	s32 ie_offset = 0;
-	s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
+	s32 bssidx = 0;
 	s32 infra = 1;
 	s32 join_params_size = 0;
 	s32 ap = 0;
 	WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
 		info->interval, info->dtim_period, info->head_len, info->tail_len));
-	if (wl->p2p_supported && p2p_on(wl) &&
+
+	if (wl->p2p_net == dev) {
+		dev = wl_to_prmry_ndev(wl);
+	}
+
+	bssidx = wl_cfgp2p_find_idx(wl, dev);
+	if (p2p_is_on(wl) &&
 		(bssidx == wl_to_p2p_bss_bssidx(wl,
 		P2PAPI_BSSCFG_CONNECTION))) {
 		memset(beacon_ie, 0, sizeof(beacon_ie));
@@ -3728,19 +3967,13 @@
 		if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) {
 			/* Total length of P2P Information Element */
 			p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
-		#ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
-			/* Have to change device address in dev_id attribute because Supplicant
-			 * use primary eth0 address
-			 */
-			wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID);
-		#endif
 			memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len);
 
 		} else {
 			WL_ERR(("No P2PIE in beacon \n"));
 		}
 		/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-		wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+		wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
 		wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
 			beacon_ie, wpsie_len + p2pie_len);
 
@@ -3763,17 +3996,18 @@
 				goto exit;
 			}
 			err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
-				sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
+				sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+				bssidx, &wl->ioctl_buf_sync);
 			if (err < 0) {
 				WL_ERR(("GO SSID setting error %d\n", err));
 				goto exit;
 			}
-			if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
+			if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) {
 				WL_ERR(("GO Bring up error %d\n", err));
 				goto exit;
 			}
 		}
-	} else if (wl_get_drv_status(wl, AP_CREATING)) {
+	} else if (wl_get_drv_status(wl, AP_CREATING, dev)) {
 		ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
 		ap = 1;
 		/* find the SSID */
@@ -3848,7 +4082,7 @@
 				beacon_ie, wpsie_len);
 				wl->ap_info->wps_ie = kmemdup(wps_ie, 	wpsie_len, GFP_KERNEL);
 				/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-				wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+				wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
 			} else {
 				WL_DBG(("No WPSIE in beacon \n"));
 			}
@@ -3879,11 +4113,11 @@
 			/* create softap */
 			if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
 				join_params_size, true)) == 0) {
-				wl_clr_drv_status(wl, AP_CREATING);
-				wl_set_drv_status(wl, AP_CREATED);
+				wl_clr_drv_status(wl, AP_CREATING, dev);
+				wl_set_drv_status(wl, AP_CREATED, dev);
 			}
 		}
-	} else if (wl_get_drv_status(wl, AP_CREATED)) {
+	} else if (wl_get_drv_status(wl, AP_CREATED, dev)) {
 		ap = 1;
 		/* find the WPSIE */
 		if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
@@ -3901,12 +4135,12 @@
 				kfree(wl->ap_info->wps_ie);
 				wl->ap_info->wps_ie = kmemdup(wps_ie, 	wpsie_len, GFP_KERNEL);
 				/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-				wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+				wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
 			} else if (wl->ap_info->wps_ie == NULL) {
 				WL_DBG((" WPS IE is added\n"));
 				wl->ap_info->wps_ie = kmemdup(wps_ie, 	wpsie_len, GFP_KERNEL);
 				/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-				wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+				wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
 			}
 			/* find the RSN_IE */
 			if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -3972,12 +4206,12 @@
 				}
 				if (update_bss) {
 					wl->ap_info->security_mode = true;
-					wl_cfgp2p_bss(dev, bssidx, 0);
+					wl_cfgp2p_bss(wl, dev, bssidx, 0);
 					if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx)  < 0 ||
 						wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
 						return BCME_ERROR;
 					}
-					wl_cfgp2p_bss(dev, bssidx, 1);
+					wl_cfgp2p_bss(wl, dev, bssidx, 1);
 				}
 			}
 		} else {
@@ -4024,7 +4258,7 @@
 	.add_beacon = wl_cfg80211_add_set_beacon,
 };
 
-static s32 wl_mode_to_nl80211_iftype(s32 mode)
+s32 wl_mode_to_nl80211_iftype(s32 mode)
 {
 	s32 err = 0;
 
@@ -4042,21 +4276,15 @@
 	return err;
 }
 
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev)
 {
-	struct wireless_dev *wdev;
 	s32 err = 0;
-	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
-	if (unlikely(!wdev)) {
-		WL_ERR(("Could not allocate wireless device\n"));
-		return ERR_PTR(-ENOMEM);
-	}
 	wdev->wiphy =
 	    wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv));
 	if (unlikely(!wdev->wiphy)) {
 		WL_ERR(("Couldn not allocate wiphy device\n"));
 		err = -ENOMEM;
-		goto wiphy_new_out;
+		return err;
 	}
 	set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
 	wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
@@ -4064,8 +4292,8 @@
 	wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
 	wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
 	wdev->wiphy->interface_modes =
-	    BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
-	    | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
+		BIT(NL80211_IFTYPE_STATION)
+		| BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
 
 	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
 	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
@@ -4085,7 +4313,9 @@
 		WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
 #endif
 		WIPHY_FLAG_4ADDR_STATION;
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+       wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+#endif
 	WL_DBG(("Registering custom regulatory)\n"));
 	wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 	wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
@@ -4093,39 +4323,28 @@
 	err = wiphy_register(wdev->wiphy);
 	if (unlikely(err < 0)) {
 		WL_ERR(("Couldn not register wiphy device (%d)\n", err));
-		goto wiphy_register_out;
+		wiphy_free(wdev->wiphy);
 	}
-	return wdev;
-
-wiphy_register_out:
-	wiphy_free(wdev->wiphy);
-
-wiphy_new_out:
-	kfree(wdev);
-
-	return ERR_PTR(err);
+	return err;
 }
 
 static void wl_free_wdev(struct wl_priv *wl)
 {
-	int i;
 	struct wireless_dev *wdev = wl->wdev;
-
-	if (unlikely(!wdev)) {
+	struct wiphy *wiphy;
+	if (!wdev) {
 		WL_ERR(("wdev is invalid\n"));
 		return;
 	}
-
-	for (i = 0; i < VWDEV_CNT; i++) {
-		if ((wl->vwdev[i] != NULL)) {
-			kfree(wl->vwdev[i]);
-			wl->vwdev[i] = NULL;
-		}
-	}
+	wiphy = wdev->wiphy;
 	wiphy_unregister(wdev->wiphy);
 	wdev->wiphy->dev.parent = NULL;
-	wiphy_free(wdev->wiphy);
-	kfree(wdev);
+
+	wl_delete_all_netinfo(wl);
+	wiphy_free(wiphy);
+	/* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl",
+	 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
+	 */
 }
 
 static s32 wl_inform_bss(struct wl_priv *wl)
@@ -4155,6 +4374,7 @@
 	struct wl_cfg80211_bss_info *notif_bss_info;
 	struct wl_scan_req *sr = wl_to_sr(wl);
 	struct beacon_proberesp *beacon_proberesp;
+	struct cfg80211_bss *cbss = NULL;
 	s32 mgmt_type;
 	s32 signal;
 	u32 freq;
@@ -4213,13 +4433,31 @@
 
 	signal = notif_bss_info->rssi * 100;
 
-	if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
-		le16_to_cpu(notif_bss_info->frame_len),
-		signal, GFP_KERNEL))) {
+#if defined(WLP2P) && ENABLE_P2P_INTERFACE
+	if (wl->p2p_net && wl->scan_request &&
+		wl->scan_request->dev == wl->p2p_net) {
+#else
+	if (p2p_is_on(wl) && p2p_scan(wl)) {
+#endif
+		/* find the P2PIE, if we do not find it, we will discard this frame */
+		wifi_p2p_ie_t * p2p_ie;
+		if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)beacon_proberesp->variable,
+			wl_get_ielen(wl))) == NULL) {
+			WL_ERR(("Couldn't find P2PIE in probe response/beacon\n"));
+			kfree(notif_bss_info);
+			return err;
+		}
+	}
+
+	cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+		le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL);
+	if (unlikely(!cbss)) {
 		WL_ERR(("cfg80211_inform_bss_frame error\n"));
 		kfree(notif_bss_info);
 		return -EINVAL;
 	}
+
+	cfg80211_put_bss(cbss);
 	kfree(notif_bss_info);
 
 	return err;
@@ -4277,108 +4515,156 @@
 	return false;
 }
 
+/* The mainline kernel >= 3.2.0 has support for indicating new/del station
+ * to AP/P2P GO via events. If this change is backported to kernel for which
+ * this driver is being built, set CFG80211_STA_EVENT_AVAILABLE to 1. You
+ * should use this new/del sta event mechanism for BRCM supplicant from BRANCH
+ * HOSTAP_BRANCH_0_15 (ver >= 15_1).
+ */
+#define CFG80211_STA_EVENT_AVAILABLE	0
 static s32
-wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
 	const wl_event_msg_t *e, void *data)
 {
-	bool act;
-	bool isfree = false;
 	s32 err = 0;
-	s32 freq;
-	s32 channel;
-	u8 body[200];
 	u32 event = ntoh32(e->event_type);
 	u32 reason = ntoh32(e->reason);
 	u32 len = ntoh32(e->datalen);
-	u16 fc = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE
+	bool isfree = false;
 	u8 *mgmt_frame;
 	u8 bsscfgidx = e->bsscfgidx;
+	s32 freq;
+	s32 channel;
+	u8 body[200];
+	u16 fc = 0;
 	struct ieee80211_supported_band *band;
 	struct ether_addr da;
 	struct ether_addr bssid;
 	struct wiphy *wiphy = wl_to_wiphy(wl);
 	channel_info_t ci;
+#else
+	struct station_info sinfo;
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE */
 
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE
 	memset(body, 0, sizeof(body));
 	memset(&bssid, 0, ETHER_ADDR_LEN);
 	WL_DBG(("Enter \n"));
+	if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID)
+		return WL_INVALID;
 
-	if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
-		memcpy(body, data, len);
-		wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
-		NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
-		memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
-		err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
-		switch (event) {
-			case WLC_E_ASSOC_IND:
-				fc = FC_ASSOC_REQ;
-				break;
-			case WLC_E_REASSOC_IND:
-				fc = FC_REASSOC_REQ;
-				break;
-			case WLC_E_DISASSOC_IND:
-				fc = FC_DISASSOC;
-				break;
-			case WLC_E_DEAUTH_IND:
-				fc = FC_DISASSOC;
-				break;
-			case WLC_E_DEAUTH:
-				fc = FC_DISASSOC;
-				break;
-			default:
-				fc = 0;
-				goto exit;
-		}
-		if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
-			return err;
+	memcpy(body, data, len);
+	wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+		NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
+	memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
+	err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+	switch (event) {
+		case WLC_E_ASSOC_IND:
+			fc = FC_ASSOC_REQ;
+			break;
+		case WLC_E_REASSOC_IND:
+			fc = FC_REASSOC_REQ;
+			break;
+		case WLC_E_DISASSOC_IND:
+			fc = FC_DISASSOC;
+			break;
+		case WLC_E_DEAUTH_IND:
+			fc = FC_DISASSOC;
+			break;
+		case WLC_E_DEAUTH:
+			fc = FC_DISASSOC;
+			break;
+		default:
+			fc = 0;
+			goto exit;
+	}
+	if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
+		return err;
 
-		channel = dtoh32(ci.hw_channel);
-		if (channel <= CH_MAX_2G_CHANNEL)
-			band = wiphy->bands[IEEE80211_BAND_2GHZ];
-		else
-			band = wiphy->bands[IEEE80211_BAND_5GHZ];
+	channel = dtoh32(ci.hw_channel);
+	if (channel <= CH_MAX_2G_CHANNEL)
+		band = wiphy->bands[IEEE80211_BAND_2GHZ];
+	else
+		band = wiphy->bands[IEEE80211_BAND_5GHZ];
 
 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
-		freq = ieee80211_channel_to_frequency(channel);
+	freq = ieee80211_channel_to_frequency(channel);
 #else
-		freq = ieee80211_channel_to_frequency(channel, band->band);
+	freq = ieee80211_channel_to_frequency(channel, band->band);
 #endif
 
-		err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
+	err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
 		&mgmt_frame, &len, body);
-		if (err < 0)
-				goto exit;
-		isfree = true;
+	if (err < 0)
+		goto exit;
+	isfree = true;
 
-		if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
-			cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
-		} else if (event == WLC_E_DISASSOC_IND) {
-			cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
-		} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
-			cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+	if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
+		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+	} else if (event == WLC_E_DISASSOC_IND) {
+		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+	} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+	}
+
+exit:
+	if (isfree)
+		kfree(mgmt_frame);
+	return err;
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */
+	sinfo.filled = 0;
+	if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
+		reason == DOT11_SC_SUCCESS) {
+		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+		if (!data) {
+			WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
+			return -EINVAL;
 		}
+		sinfo.assoc_req_ies = data;
+		sinfo.assoc_req_ies_len = len;
+		cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
+	} else if (event == WLC_E_DISASSOC_IND) {
+		cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+	} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+		cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+	}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */
+	return err;
+}
 
+static s32
+wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+	const wl_event_msg_t *e, void *data)
+{
+	bool act;
+	s32 err = 0;
+	u32 event = ntoh32(e->event_type);
+
+	if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
+		wl_notify_connect_status_ap(wl, ndev, e, data);
 	} else {
 		WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
 		ntoh32(e->event_type), ntoh32(e->status)));
 		if (wl_is_linkup(wl, e, ndev)) {
 			wl_link_up(wl);
 			act = true;
-			wl_update_prof(wl, e, &act, WL_PROF_ACT);
-			wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+			wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
+			wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
 			if (wl_is_ibssmode(wl, ndev)) {
 				printk("cfg80211_ibss_joined\n");
 				cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
 					GFP_KERNEL);
 				WL_DBG(("joined in IBSS network\n"));
 			} else {
-				if (!wl_get_drv_status(wl, DISCONNECTING)) {
-					printk("wl_bss_connect_done succeeded status=(0x%x)\n",
-						(int)wl->status);
+				if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) {
+					printk("wl_bss_connect_done succeeded\n");
 					wl_bss_connect_done(wl, ndev, e, data, true);
 					WL_DBG(("joined in BSS network \"%s\"\n",
 					((struct wlc_ssid *)
-					 wl_read_prof(wl, WL_PROF_SSID))->SSID));
+					 wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID));
 				}
 			}
 
@@ -4386,15 +4672,15 @@
 			if (wl->scan_request) {
 				del_timer_sync(&wl->scan_timeout);
 				if (wl->escan_on) {
-					wl_notify_escan_complete(wl, true);
+					wl_notify_escan_complete(wl, ndev, true);
 				} else
 					wl_iscan_aborted(wl);
 			}
-			if (wl_get_drv_status(wl, CONNECTED)) {
+			if (wl_get_drv_status(wl, CONNECTED, ndev)) {
 				scb_val_t scbval;
-				u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+				u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
 				printk("link down, call cfg80211_disconnected\n");
-				wl_clr_drv_status(wl, CONNECTED);
+				wl_clr_drv_status(wl, CONNECTED, ndev);
 				/* To make sure disconnect, explictly send dissassoc
 				*  for BSSID 00:00:00:00:00:00 issue
 				*/
@@ -4406,12 +4692,12 @@
 					sizeof(scb_val_t), true);
 				cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
 				wl_link_down(wl);
-				wl_init_prof(wl);
-			} else if (wl_get_drv_status(wl, CONNECTING)) {
+				wl_init_prof(wl, ndev);
+			} else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
 				printk("link down, during connecting\n");
 				wl_bss_connect_done(wl, ndev, e, data, false);
 			}
-			wl_clr_drv_status(wl, DISCONNECTING);
+			wl_clr_drv_status(wl, DISCONNECTING, ndev);
 
 		} else if (wl_is_nonetwork(wl, e)) {
 			printk("connect failed event=%d e->status 0x%x\n",
@@ -4420,19 +4706,16 @@
 			if (wl->scan_request) {
 				del_timer_sync(&wl->scan_timeout);
 				if (wl->escan_on) {
-					wl_notify_escan_complete(wl, true);
+					wl_notify_escan_complete(wl, ndev, true);
 				} else
 					wl_iscan_aborted(wl);
 			}
-			if (wl_get_drv_status(wl, CONNECTING))
+			if (wl_get_drv_status(wl, CONNECTING, ndev))
 				wl_bss_connect_done(wl, ndev, e, data, false);
 		} else {
 			printk("%s nothing\n", __FUNCTION__);
 		}
 	}
-exit:
-	if (isfree)
-		kfree(mgmt_frame);
 	return err;
 }
 
@@ -4446,50 +4729,17 @@
 	u32 status = be32_to_cpu(e->status);
 	WL_DBG(("Enter \n"));
 	if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
-		if (wl_get_drv_status(wl, CONNECTED))
+		if (wl_get_drv_status(wl, CONNECTED, ndev))
 			wl_bss_roaming_done(wl, ndev, e, data);
 		else
 			wl_bss_connect_done(wl, ndev, e, data, true);
 		act = true;
-		wl_update_prof(wl, e, &act, WL_PROF_ACT);
-		wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+		wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
+		wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
 	}
 	return err;
 }
 
-static __used s32
-wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
-{
-	struct wl_priv *wl = wlcfg_drv_priv;
-	u32 buflen;
-
-	buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
-	BUG_ON(unlikely(!buflen));
-
-	return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true);
-}
-
-static s32
-wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
-	s32 buf_len)
-{
-	struct wl_priv *wl = wlcfg_drv_priv;
-	u32 len;
-	s32 err = 0;
-
-	len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
-	BUG_ON(unlikely(!len));
-	err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
-		WL_IOCTL_LEN_MAX, false);
-	if (unlikely(err)) {
-		WL_ERR(("error (%d)\n", err));
-		return err;
-	}
-	memcpy(buf, wl->ioctl_buf, buf_len);
-
-	return err;
-}
-
 static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
 {
 	wl_assoc_info_t assoc_info;
@@ -4497,8 +4747,8 @@
 	s32 err = 0;
 
 	WL_DBG(("Enter \n"));
-	err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
-		WL_ASSOC_INFO_MAX);
+	err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf,
+		WL_ASSOC_INFO_MAX, NULL);
 	if (unlikely(err)) {
 		WL_ERR(("could not get assoc info (%d)\n", err));
 		return err;
@@ -4516,8 +4766,8 @@
 		bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
 	}
 	if (assoc_info.req_len) {
-		err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
-			WL_ASSOC_INFO_MAX);
+		err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf,
+			WL_ASSOC_INFO_MAX, NULL);
 		if (unlikely(err)) {
 			WL_ERR(("could not get assoc req (%d)\n", err));
 			return err;
@@ -4537,8 +4787,8 @@
 		conn_info->req_ie_len = 0;
 	}
 	if (assoc_info.resp_len) {
-		err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
-			WL_ASSOC_INFO_MAX);
+		err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf,
+			WL_ASSOC_INFO_MAX, NULL);
 		if (unlikely(err)) {
 			WL_ERR(("could not get assoc resp (%d)\n", err));
 			return err;
@@ -4600,8 +4850,8 @@
 	struct wl_bss_info *bi;
 	struct wlc_ssid *ssid;
 	struct bcm_tlv *tim;
-	u16 beacon_interval;
-	u8 dtim_period;
+	s32 beacon_interval;
+	s32 dtim_period;
 	size_t ie_len;
 	u8 *ie;
 	u8 *curbssid;
@@ -4612,14 +4862,14 @@
 	if (wl_is_ibssmode(wl, ndev))
 		return err;
 
-	ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
-	curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+	ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID);
+	curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
 	bss = cfg80211_get_bss(wiphy, NULL, curbssid,
 		ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
 		WLAN_CAPABILITY_ESS);
 
 	mutex_lock(&wl->usr_sync);
-	if (unlikely(!bss)) {
+	if (!bss) {
 		WL_DBG(("Could not find the AP\n"));
 		*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
 		err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
@@ -4655,7 +4905,7 @@
 		/*
 		* active scan was done so we could not get dtim
 		* information out of probe response.
-		* so we speficially query dtim information to dongle.
+		* so we speficially query dtim information.
 		*/
 		err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
 			&dtim_period, sizeof(dtim_period), false);
@@ -4665,8 +4915,8 @@
 		}
 	}
 
-	wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
-	wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
+	wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
+	wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
 
 update_bss_info_out:
 	mutex_unlock(&wl->usr_sync);
@@ -4682,8 +4932,8 @@
 	u8 *curbssid;
 
 	wl_get_assoc_ies(wl, ndev);
-	wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
-	curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+	wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+	curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
 	wl_update_bss_info(wl, ndev);
 	wl_update_pmklist(ndev, wl->pmk_list, err);
 	cfg80211_roamed(ndev,
@@ -4695,7 +4945,7 @@
 		conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
 	WL_DBG(("Report roaming result\n"));
 
-	wl_set_drv_status(wl, CONNECTED);
+	wl_set_drv_status(wl, CONNECTED, ndev);
 
 	return err;
 }
@@ -4706,20 +4956,21 @@
 {
 	struct wl_connect_info *conn_info = wl_to_conn(wl);
 	s32 err = 0;
-	u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+	u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
+
 	WL_DBG((" enter\n"));
 	if (wl->scan_request) {
 		wl_cfg80211_scan_abort(wl, ndev);
 	}
-	if (wl_get_drv_status(wl, CONNECTING)) {
-		wl_clr_drv_status(wl, CONNECTING);
+	if (wl_get_drv_status(wl, CONNECTING, ndev)) {
+		wl_clr_drv_status(wl, CONNECTING, ndev);
 		if (completed) {
 			wl_get_assoc_ies(wl, ndev);
-			wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
-			curbssid = wl_read_prof(wl, WL_PROF_BSSID);
+			wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+			curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
 			wl_update_bss_info(wl, ndev);
 			wl_update_pmklist(ndev, wl->pmk_list, err);
-			wl_set_drv_status(wl, CONNECTED);
+			wl_set_drv_status(wl, CONNECTED, ndev);
 		}
 		cfg80211_connect_result(ndev,
 			curbssid,
@@ -4758,6 +5009,19 @@
 }
 
 static s32
+wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
+	const wl_event_msg_t *e, void *data)
+{
+	WL_ERR((" PNO Event\n"));
+
+	mutex_lock(&wl->usr_sync);
+	/* TODO: Use cfg80211_sched_scan_results(wiphy); */
+	cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+	mutex_unlock(&wl->usr_sync);
+	return 0;
+}
+
+static s32
 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
 	const wl_event_msg_t *e, void *data)
 {
@@ -4768,11 +5032,15 @@
 	unsigned long flags;
 
 	WL_DBG(("Enter \n"));
+	if (!wl_get_drv_status(wl, SCANNING, ndev)) {
+		WL_ERR(("scan is not ready \n"));
+		return err;
+	}
 	if (wl->iscan_on && wl->iscan_kickstart)
 		return wl_wakeup_iscan(wl_to_iscan(wl));
 
 	mutex_lock(&wl->usr_sync);
-	wl_clr_drv_status(wl, SCANNING);
+	wl_clr_drv_status(wl, SCANNING, ndev);
 	err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
 		sizeof(channel_inform), false);
 	if (unlikely(err)) {
@@ -4803,13 +5071,13 @@
 
 scan_done_out:
 	del_timer_sync(&wl->scan_timeout);
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 	if (wl->scan_request) {
 		WL_DBG(("cfg80211_scan_done\n"));
 		cfg80211_scan_done(wl->scan_request, false);
 		wl->scan_request = NULL;
 	}
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 	mutex_unlock(&wl->usr_sync);
 	return err;
 }
@@ -4865,7 +5133,10 @@
 	bool isfree = false;
 	s32 err = 0;
 	s32 freq;
-	wifi_p2p_pub_act_frame_t *act_frm;
+	struct net_device *dev = NULL;
+	wifi_p2p_pub_act_frame_t *act_frm = NULL;
+	wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+	wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
 	wl_event_rx_frame_data_t *rxframe =
 		(wl_event_rx_frame_data_t*)data;
 	u32 event = ntoh32(e->event_type);
@@ -4875,6 +5146,13 @@
 	u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
 
 	memset(&bssid, 0, ETHER_ADDR_LEN);
+
+	if (wl->p2p_net == ndev) {
+		dev = wl_to_prmry_ndev(wl);
+	} else {
+		dev = ndev;
+	}
+
 	if (channel <= CH_MAX_2G_CHANNEL)
 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
 	else
@@ -4886,11 +5164,11 @@
 	freq = ieee80211_channel_to_frequency(channel, band->band);
 #endif
 	if (event == WLC_E_ACTION_FRAME_RX) {
-		wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
-		NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
+		wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr",
+			NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
 
-		wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
-		memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
+		wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+		memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
 		err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
 			&mgmt_frame, &mgmt_frame_len,
 			(u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
@@ -4900,13 +5178,29 @@
 			goto exit;
 		}
 		isfree = true;
-		act_frm =
-			(wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+		if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+			act_frm = (wifi_p2p_pub_act_frame_t *)
+					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+		} else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+			p2p_act_frm = (wifi_p2p_action_frame_t *)
+					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+			(void) p2p_act_frm;
+		} else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+			sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
+					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+			(void) sd_act_frm;
+		}
+		wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
+			mgmt_frame_len - DOT11_MGMT_HDR_LEN);
 		/*
 		 * After complete GO Negotiation, roll back to mpc mode
 		 */
-		 if (act_frm->subtype == P2P_PAF_GON_CONF) {
-			wldev_iovar_setint(ndev, "mpc", 1);
+		if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
+		(act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
+			wldev_iovar_setint(dev, "mpc", 1);
 		}
 	} else {
 		mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
@@ -4925,12 +5219,7 @@
 
 static void wl_init_conf(struct wl_conf *conf)
 {
-	s32 i = 0;
 	WL_DBG(("Enter \n"));
-	for (i = 0; i <= VWDEV_CNT; i++) {
-		conf->mode[i].type = -1;
-		conf->mode[i].ndev = NULL;
-	}
 	conf->frag_threshold = (u32)-1;
 	conf->rts_threshold = (u32)-1;
 	conf->retry_short = (u32)-1;
@@ -4938,13 +5227,14 @@
 	conf->tx_power = -1;
 }
 
-static void wl_init_prof(struct wl_priv *wl)
+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev)
 {
 	unsigned long flags;
+	struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
 
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
-	memset(wl->profile, 0, sizeof(struct wl_profile));
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+	memset(profile, 0, sizeof(struct wl_profile));
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 }
 
 static void wl_init_event_handler(struct wl_priv *wl)
@@ -4967,7 +5257,7 @@
 	wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
 	wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
 	wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
-
+	wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
 }
 
 static s32 wl_init_priv_mem(struct wl_priv *wl)
@@ -4983,23 +5273,13 @@
 		WL_ERR(("wl_conf alloc failed\n"));
 		goto init_priv_mem_out;
 	}
-	wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
-	if (unlikely(!wl->profile)) {
-		WL_ERR(("wl_profile alloc failed\n"));
-		goto init_priv_mem_out;
-	}
-	wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
-	if (unlikely(!wl->bss_info)) {
-		WL_ERR(("Bss information alloc failed\n"));
-		goto init_priv_mem_out;
-	}
 	wl->scan_req_int =
 	    (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
 	if (unlikely(!wl->scan_req_int)) {
 		WL_ERR(("Scan req alloc failed\n"));
 		goto init_priv_mem_out;
 	}
-	wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+	wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
 	if (unlikely(!wl->ioctl_buf)) {
 		WL_ERR(("Ioctl buf alloc failed\n"));
 		goto init_priv_mem_out;
@@ -5019,11 +5299,6 @@
 		WL_ERR(("Iscan buf alloc failed\n"));
 		goto init_priv_mem_out;
 	}
-	wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
-	if (unlikely(!wl->fw)) {
-		WL_ERR(("fw object alloc failed\n"));
-		goto init_priv_mem_out;
-	}
 	wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
 	if (unlikely(!wl->pmk_list)) {
 		WL_ERR(("pmk list alloc failed\n"));
@@ -5034,6 +5309,14 @@
 		WL_ERR(("sta info  alloc failed\n"));
 		goto init_priv_mem_out;
 	}
+	wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL);
+	if (unlikely(!wl->afx_hdl)) {
+		WL_ERR(("afx hdl  alloc failed\n"));
+		goto init_priv_mem_out;
+	} else {
+		init_completion(&wl->act_frm_scan);
+		INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler);
+	}
 	return 0;
 
 init_priv_mem_out:
@@ -5046,12 +5329,8 @@
 {
 	kfree(wl->scan_results);
 	wl->scan_results = NULL;
-	kfree(wl->bss_info);
-	wl->bss_info = NULL;
 	kfree(wl->conf);
 	wl->conf = NULL;
-	kfree(wl->profile);
-	wl->profile = NULL;
 	kfree(wl->scan_req_int);
 	wl->scan_req_int = NULL;
 	kfree(wl->ioctl_buf);
@@ -5062,12 +5341,16 @@
 	wl->extra_buf = NULL;
 	kfree(wl->iscan);
 	wl->iscan = NULL;
-	kfree(wl->fw);
-	wl->fw = NULL;
 	kfree(wl->pmk_list);
 	wl->pmk_list = NULL;
 	kfree(wl->sta_info);
 	wl->sta_info = NULL;
+	if (wl->afx_hdl) {
+		cancel_work_sync(&wl->afx_hdl->work);
+		kfree(wl->afx_hdl);
+		wl->afx_hdl = NULL;
+	}
+
 	if (wl->ap_info) {
 		kfree(wl->ap_info->wpa_ie);
 		kfree(wl->ap_info->rsn_ie);
@@ -5082,7 +5365,8 @@
 	int ret = 0;
 	WL_DBG(("Enter \n"));
 
-	wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
+	/* Do not use DHD in cfg driver */
+	wl->event_tsk.thr_pid = -1;
 	PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
 	if (wl->event_tsk.thr_pid < 0)
 		ret = -ENOMEM;
@@ -5112,21 +5396,22 @@
 static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
 {
 	struct wl_priv *wl = iscan_to_wl(iscan);
+	struct net_device *ndev = wl_to_prmry_ndev(wl);
 	unsigned long flags;
 
 	WL_DBG(("Enter \n"));
-	if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
-		wl_clr_drv_status(wl, SCANNING);
+	if (!wl_get_drv_status(wl, SCANNING, ndev)) {
+		wl_clr_drv_status(wl, SCANNING, ndev);
 		WL_ERR(("Scan complete while device not scanning\n"));
 		return;
 	}
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
-	wl_clr_drv_status(wl, SCANNING);
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+	wl_clr_drv_status(wl, SCANNING, ndev);
 	if (likely(wl->scan_request)) {
 		cfg80211_scan_done(wl->scan_request, aborted);
 		wl->scan_request = NULL;
 	}
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 	wl->iscan_kickstart = false;
 }
 
@@ -5162,7 +5447,7 @@
 	list.results.buflen = htod32(WL_ISCAN_BUF_MAX);
 	err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list,
 		WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
-		WL_ISCAN_BUF_MAX);
+		WL_ISCAN_BUF_MAX, NULL);
 	if (unlikely(err)) {
 		WL_ERR(("error (%d)\n", err));
 		return err;
@@ -5235,13 +5520,11 @@
 
 static s32 wl_iscan_thread(void *data)
 {
-	struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
 	struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
 	struct wl_priv *wl = iscan_to_wl(iscan);
 	u32 status;
 	int err = 0;
 
-	sched_setscheduler(current, SCHED_FIFO, &param);
 	allow_signal(SIGTERM);
 	status = WL_SCAN_RESULTS_PARTIAL;
 	while (likely(!down_interruptible(&iscan->sync))) {
@@ -5276,7 +5559,7 @@
 	if (wl->scan_request) {
 		WL_ERR(("timer expired\n"));
 		if (wl->escan_on)
-			wl_notify_escan_complete(wl, true);
+			wl_notify_escan_complete(wl, wl->escan_info.ndev, true);
 		else
 			wl_notify_iscan_complete(wl_to_iscan(wl), true);
 	}
@@ -5322,21 +5605,47 @@
 	iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted;
 }
 
-static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
+static s32
+wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
+	unsigned long state,
+	void *ndev)
+{
+	struct net_device *dev = ndev;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wl_priv *wl = wlcfg_drv_priv;
+
+	WL_DBG(("Enter \n"));
+	if (!wdev || dev == wl_to_prmry_ndev(wl))
+		return NOTIFY_DONE;
+	switch (state) {
+		case NETDEV_UNREGISTER:
+				/* after calling list_del_rcu(&wdev->list) */
+				wl_dealloc_netinfo(wl, ndev);
+				break;
+	}
+	return NOTIFY_DONE;
+}
+static struct notifier_block wl_cfg80211_netdev_notifier = {
+	.notifier_call = wl_cfg80211_netdev_notifier_call,
+};
+
+static void wl_notify_escan_complete(struct wl_priv *wl,
+	struct net_device *ndev,
+	bool aborted)
 {
 	unsigned long flags;
 
 	WL_DBG(("Enter \n"));
-	wl_clr_drv_status(wl, SCANNING);
-	if (wl->p2p_supported && p2p_on(wl))
+	wl_clr_drv_status(wl, SCANNING, ndev);
+	if (p2p_is_on(wl))
 		wl_clr_p2p_status(wl, SCANNING);
 
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 	if (likely(wl->scan_request)) {
 		cfg80211_scan_done(wl->scan_request, aborted);
 		wl->scan_request = NULL;
 	}
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 }
 
 static s32 wl_escan_handler(struct wl_priv *wl,
@@ -5351,11 +5660,22 @@
 	wl_scan_results_t *list;
 	u32 bi_length;
 	u32 i;
+	u8 *p2p_dev_addr = NULL;
+
 	WL_DBG((" enter event type : %d, status : %d \n",
 		ntoh32(e->event_type), ntoh32(e->status)));
-	if (!wl->escan_on &&
-		!wl_get_drv_status(wl, SCANNING)) {
-		WL_ERR(("escan is not ready \n"));
+	/* P2P SCAN is coming from primary interface */
+	if (wl_get_p2p_status(wl, SCANNING)) {
+		if (wl_get_drv_status_all(wl, SENDING_ACT_FRM))
+			ndev = wl->afx_hdl->dev;
+		else
+			ndev = wl->escan_info.ndev;
+
+	}
+	if (!ndev || !wl->escan_on ||
+		!wl_get_drv_status(wl, SCANNING, ndev)) {
+		WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n",
+			ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev)));
 		return err;
 	}
 
@@ -5380,77 +5700,118 @@
 			WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
 			goto exit;
 		}
-		list = (wl_scan_results_t *)wl->escan_info.escan_buf;
-		if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
-			WL_ERR(("Buffer is too small: ignoring\n"));
-			goto exit;
-		}
-#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
-		for (i = 0; i < list->count; i++) {
-			bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
-				: list->bss_info;
 
-			if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
-				CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
-				bi->SSID_len == bss->SSID_len &&
-				!bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
-				if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
-					(bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
-					/* preserve max RSSI if the measurements are
-					 * both on-channel or both off-channel
-					 */
-					bss->RSSI = MAX(bss->RSSI, bi->RSSI);
-				} else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
-					(bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
-					/* preserve the on-channel rssi measurement
-					 * if the new measurement is off channel
-					 */
-					bss->RSSI = bi->RSSI;
-					bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
-				}
-
+		if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
+			if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
+				WL_ERR(("Ignoring IBSS result\n"));
 				goto exit;
 			}
 		}
-		memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
-		list->version = dtoh32(bi->version);
-		list->buflen += bi_length;
-		list->count++;
+
+		if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+			p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
+			if (p2p_dev_addr && !memcmp(p2p_dev_addr,
+				wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) {
+				s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
+				WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel));
+				wl_clr_p2p_status(wl, SCANNING);
+				wl->afx_hdl->peer_chan = channel;
+				complete(&wl->act_frm_scan);
+				goto exit;
+			}
+
+		} else {
+			list = (wl_scan_results_t *)wl->escan_info.escan_buf;
+			if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+				WL_ERR(("Buffer is too small: ignoring\n"));
+				goto exit;
+			}
+#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
+			for (i = 0; i < list->count; i++) {
+				bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
+					: list->bss_info;
+
+				if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+					CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
+					bi->SSID_len == bss->SSID_len &&
+					!bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
+					if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
+						(bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
+						/* preserve max RSSI if the measurements are
+						* both on-channel or both off-channel
+						*/
+						bss->RSSI = MAX(bss->RSSI, bi->RSSI);
+					} else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
+						(bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
+						/* preserve the on-channel rssi measurement
+						* if the new measurement is off channel
+						*/
+						bss->RSSI = bi->RSSI;
+						bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
+					}
+
+					goto exit;
+				}
+			}
+			memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
+			list->version = dtoh32(bi->version);
+			list->buflen += bi_length;
+			list->count++;
+
+		}
 
 	}
 	else if (status == WLC_E_STATUS_SUCCESS) {
 		wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-		if (likely(wl->scan_request)) {
+		if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+			WL_INFO(("ACTION FRAME SCAN DONE\n"));
+			wl_clr_p2p_status(wl, SCANNING);
+			wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+			if (wl->afx_hdl->peer_chan == WL_INVALID)
+				complete(&wl->act_frm_scan);
+		} else if (likely(wl->scan_request)) {
 			mutex_lock(&wl->usr_sync);
 			del_timer_sync(&wl->scan_timeout);
 			WL_INFO(("ESCAN COMPLETED\n"));
 			wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
 			wl_inform_bss(wl);
-			wl_notify_escan_complete(wl, false);
+			wl_notify_escan_complete(wl, ndev, false);
 			mutex_unlock(&wl->usr_sync);
 		}
 	}
 	else if (status == WLC_E_STATUS_ABORT) {
 		wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-		if (likely(wl->scan_request)) {
+		if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+			WL_INFO(("ACTION FRAME SCAN DONE\n"));
+			wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+			wl_clr_p2p_status(wl, SCANNING);
+			if (wl->afx_hdl->peer_chan == WL_INVALID)
+				complete(&wl->act_frm_scan);
+		} else if (likely(wl->scan_request)) {
 			mutex_lock(&wl->usr_sync);
 			del_timer_sync(&wl->scan_timeout);
 			WL_INFO(("ESCAN ABORTED\n"));
 			wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
 			wl_inform_bss(wl);
-			wl_notify_escan_complete(wl, true);
+			wl_notify_escan_complete(wl, ndev, true);
 			mutex_unlock(&wl->usr_sync);
 		}
 	}
 	else {
 		WL_ERR(("unexpected Escan Event %d : abort\n", status));
 		wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-		if (likely(wl->scan_request)) {
+		if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+			WL_INFO(("ACTION FRAME SCAN DONE\n"));
+			wl_clr_p2p_status(wl, SCANNING);
+			wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+			if (wl->afx_hdl->peer_chan == WL_INVALID)
+				complete(&wl->act_frm_scan);
+		} else if (likely(wl->scan_request)) {
 			mutex_lock(&wl->usr_sync);
 			del_timer_sync(&wl->scan_timeout);
 			wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
 			wl_inform_bss(wl);
-			wl_notify_escan_complete(wl, true);
+			wl_notify_escan_complete(wl, ndev, true);
 			mutex_unlock(&wl->usr_sync);
 		}
 	}
@@ -5491,16 +5852,11 @@
 	return err;
 }
 
-static void wl_init_fw(struct wl_fw_ctrl *fw)
-{
-	fw->status = 0;
-}
-
 static s32 wl_init_priv(struct wl_priv *wl)
 {
 	struct wiphy *wiphy = wl_to_wiphy(wl);
+	struct net_device *ndev = wl_to_prmry_ndev(wl);
 	s32 err = 0;
-	s32 i = 0;
 
 	wl->scan_request = NULL;
 	wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
@@ -5509,60 +5865,77 @@
 	wl->roam_on = false;
 	wl->iscan_kickstart = false;
 	wl->active_scan = true;
-	wl->dongle_up = false;
 	wl->rf_blocked = false;
-
-	for (i = 0; i < VWDEV_CNT; i++)
-		wl->vwdev[i] = NULL;
-
-	init_waitqueue_head(&wl->dongle_event_wait);
+	spin_lock_init(&wl->cfgdrv_lock);
+	mutex_init(&wl->ioctl_buf_sync);
+	init_waitqueue_head(&wl->netif_change_event);
 	wl_init_eq(wl);
 	err = wl_init_priv_mem(wl);
-	if (unlikely(err))
+	if (err)
 		return err;
-	if (unlikely(wl_create_event_handler(wl)))
+	if (wl_create_event_handler(wl))
 		return -ENOMEM;
 	wl_init_event_handler(wl);
 	mutex_init(&wl->usr_sync);
 	err = wl_init_scan(wl);
-	if (unlikely(err))
+	if (err)
 		return err;
-	wl_init_fw(wl->fw);
 	wl_init_conf(wl->conf);
-	wl_init_prof(wl);
+	wl_init_prof(wl, ndev);
 	wl_link_down(wl);
+	DNGL_FUNC(dhd_cfg80211_init, (wl));
 
 	return err;
 }
 
 static void wl_deinit_priv(struct wl_priv *wl)
 {
+	DNGL_FUNC(dhd_cfg80211_deinit, (wl));
 	wl_destroy_event_handler(wl);
-	wl->dongle_up = false;	/* dongle down */
 	wl_flush_eq(wl);
 	wl_link_down(wl);
 	del_timer_sync(&wl->scan_timeout);
 	wl_term_iscan(wl);
 	wl_deinit_priv_mem(wl);
+	unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
 }
 
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-s32 wl_cfg80211_sysctl_export_devaddr(void *data)
+#if defined(WLP2P) && ENABLE_P2P_INTERFACE
+static s32 wl_cfg80211_attach_p2p(void)
 {
-	/* Export the p2p_dev_addr via sysctl interface
-	 * so that wpa_supplicant can access it
-	 */
-	dhd_pub_t *dhd = (dhd_pub_t *)data;
 	struct wl_priv *wl = wlcfg_drv_priv;
 
-	wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+	WL_TRACE(("Enter \n"));
 
-	sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p->dev_addr.octet));
-	sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p->int_addr.octet));
+	if (wl_cfgp2p_register_ndev(wl) < 0) {
+		WL_ERR(("%s: P2P attach failed. \n", __func__));
+		return -ENODEV;
+	}
 
 	return 0;
 }
-#endif /* CONFIG_SYSCTL */
+
+static s32  wl_cfg80211_detach_p2p(void)
+{
+	struct wl_priv *wl = wlcfg_drv_priv;
+	struct wireless_dev *wdev = wl->p2p_wdev;
+
+	WL_DBG(("Enter \n"));
+	if (!wdev || !wl) {
+		WL_ERR(("Invalid Ptr\n"));
+		return -EINVAL;
+	}
+
+	wl_cfgp2p_unregister_ndev(wl);
+
+	wl->p2p_wdev = NULL;
+	wl->p2p_net = NULL;
+	WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev));
+	kfree(wdev);
+
+	return 0;
+}
+#endif /* defined(WLP2P) && (ENABLE_P2P_INTERFACE) */
 
 s32 wl_cfg80211_attach_post(struct net_device *ndev)
 {
@@ -5574,75 +5947,107 @@
 		return -ENODEV;
 	}
 	wl = wlcfg_drv_priv;
-	if (wl && !wl_get_drv_status(wl, READY)) {
+	if (wl && !wl_get_drv_status(wl, READY, ndev)) {
 			if (wl->wdev &&
 				wl_cfgp2p_supported(wl, ndev)) {
+#if !ENABLE_P2P_INTERFACE
 				wl->wdev->wiphy->interface_modes |=
 					(BIT(NL80211_IFTYPE_P2P_CLIENT)|
 					BIT(NL80211_IFTYPE_P2P_GO));
+#endif
 				if ((err = wl_cfgp2p_init_priv(wl)) != 0)
 					goto fail;
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-				wl_cfg80211_sysctl_export_devaddr(wl->pub);
-#endif
+
+#if defined(WLP2P) && ENABLE_P2P_INTERFACE
+				if (wl->p2p_net) {
+					/* Update MAC addr for p2p0 interface here. */
+					memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
+					wl->p2p_net->dev_addr[0] |= 0x02;
+					printk("%s: p2p_dev_addr="MACSTR "\n",
+						wl->p2p_net->name, MAC2STR(wl->p2p_net->dev_addr));
+				} else {
+					WL_ERR(("p2p_net not yet populated."
+					" Couldn't update the MAC Address for p2p0 \n"));
+					return -ENODEV;
+				}
+#endif /* defined(WLP2P) && (ENABLE_P2P_INTERFACE) */
+
 				wl->p2p_supported = true;
 			}
 	} else
 		return -ENODEV;
-
-	wl_set_drv_status(wl, READY);
+	wl_set_drv_status(wl, READY, ndev);
 fail:
 	return err;
 }
+
 s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
 {
 	struct wireless_dev *wdev;
 	struct wl_priv *wl;
 	s32 err = 0;
+	struct device *dev;
 
 	WL_TRACE(("In\n"));
-	if (unlikely(!ndev)) {
+	if (!ndev) {
 		WL_ERR(("ndev is invaild\n"));
 		return -ENODEV;
 	}
-	WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func()));
-	wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev);
-	if (unlikely(IS_ERR(wdev)))
-		return -ENOMEM;
+	WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
+	dev = wl_cfg80211_get_parent_dev();
 
+	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+	if (unlikely(!wdev)) {
+		WL_ERR(("Could not allocate wireless device\n"));
+		return -ENOMEM;
+	}
+	err = wl_setup_wiphy(wdev, dev);
+	if (unlikely(err)) {
+		kfree(wdev);
+		return -ENOMEM;
+	}
 	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
 	wl = (struct wl_priv *)wiphy_priv(wdev->wiphy);
 	wl->wdev = wdev;
 	wl->pub = data;
-
+	INIT_LIST_HEAD(&wl->net_list);
 	ndev->ieee80211_ptr = wdev;
 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
 	wdev->netdev = ndev;
-
+	err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS);
+	if (err) {
+		WL_ERR(("Failed to alloc net_info (%d)\n", err));
+		goto cfg80211_attach_out;
+	}
 	err = wl_init_priv(wl);
-	if (unlikely(err)) {
+	if (err) {
 		WL_ERR(("Failed to init iwm_priv (%d)\n", err));
 		goto cfg80211_attach_out;
 	}
 
 	err = wl_setup_rfkill(wl, TRUE);
-	if (unlikely(err)) {
+	if (err) {
 		WL_ERR(("Failed to setup rfkill %d\n", err));
 		goto cfg80211_attach_out;
 	}
-
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-	if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) {
-		WL_ERR(("%s: sysctl register failed!! \n", __func__));
+	err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
+	if (err) {
+		WL_ERR(("Failed to register notifierl %d\n", err));
 		goto cfg80211_attach_out;
 	}
-#endif
 #if defined(COEX_DHCP)
 	if (wl_cfg80211_btcoex_init(wl))
 		goto cfg80211_attach_out;
-#endif /* COEX_DHCP */
+#endif 
 
 	wlcfg_drv_priv = wl;
+
+#if defined(WLP2P) && ENABLE_P2P_INTERFACE
+	err = wl_cfg80211_attach_p2p();
+	if (err)
+		goto cfg80211_attach_out;
+#endif
+
 	return err;
 
 cfg80211_attach_out:
@@ -5651,7 +6056,7 @@
 	return err;
 }
 
-void wl_cfg80211_detach(void)
+void wl_cfg80211_detach(void *para)
 {
 	struct wl_priv *wl;
 
@@ -5661,19 +6066,21 @@
 
 #if defined(COEX_DHCP)
 	wl_cfg80211_btcoex_deinit(wl);
-#endif /* COEX_DHCP */
+#endif 
 
-#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
-	if (wl_sysctl_hdr)
-		unregister_sysctl_table(wl_sysctl_hdr);
+#if defined(WLP2P) && ENABLE_P2P_INTERFACE
+	wl_cfg80211_detach_p2p();
 #endif
 	wl_setup_rfkill(wl, FALSE);
 	if (wl->p2p_supported)
 		wl_cfgp2p_deinit_priv(wl);
 	wl_deinit_priv(wl);
 	wlcfg_drv_priv = NULL;
-	wl_clear_sdio_func();
+	wl_cfg80211_clear_parent_dev();
 	wl_free_wdev(wl);
+	 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl",
+	  * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!!
+	  */
 }
 
 static void wl_wakeup_event(struct wl_priv *wl)
@@ -5684,6 +6091,42 @@
 	}
 }
 
+static int wl_is_p2p_event(struct wl_event_q *e)
+{
+	switch (e->etype) {
+	/* We have to seperate out the P2P events received
+	 * on primary interface so that it can be send up
+	 * via p2p0 interface.
+	*/
+	case WLC_E_P2P_PROBREQ_MSG:
+	case WLC_E_P2P_DISC_LISTEN_COMPLETE:
+	case WLC_E_ACTION_FRAME_RX:
+	case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE:
+	case WLC_E_ACTION_FRAME_COMPLETE:
+
+		if (e->emsg.ifidx != 0) {
+			WL_TRACE(("P2P Event on Virtual I/F (ifidx:%d) \n",
+			e->emsg.ifidx));
+			/* We are only bothered about the P2P events received
+			 * on primary interface. For rest of them return false
+			 * so that it is sent over the interface corresponding
+			 * to the ifidx.
+			 */
+			return FALSE;
+		} else {
+			WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)."
+				" Sent it to p2p0 \n", e->emsg.ifidx));
+			return TRUE;
+		}
+		break;
+
+	default:
+		WL_TRACE(("NON-P2P Event %d on ifidx (ifidx:%d) \n",
+			e->etype, e->emsg.ifidx));
+		return FALSE;
+	}
+}
+
 static s32 wl_event_handler(void *data)
 {
 	struct net_device *netdev;
@@ -5692,6 +6135,9 @@
 	tsk_ctl_t *tsk = (tsk_ctl_t *)data;
 
 	wl = (struct wl_priv *)tsk->parent;
+
+	DAEMONIZE("wl_event_handler");
+
 	complete(&tsk->completed);
 
 	while (down_interruptible (&tsk->sema) == 0) {
@@ -5700,7 +6146,15 @@
 			break;
 		while ((e = wl_deq_event(wl))) {
 			WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
-			netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
+			/* All P2P device address related events comes on primary interface since
+			 * there is no corresponding bsscfg for P2P interface. Map it to p2p0
+			 * interface.
+			 */
+			if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) {
+				netdev = wl->p2p_net;
+			} else {
+				netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
+			}
 			if (!netdev)
 				netdev = wl_to_prmry_ndev(wl);
 			if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
@@ -5729,9 +6183,6 @@
 	WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
 #endif /* (WL_DBG_LEVEL > 0) */
 
-	if (event_type == WLC_E_PFN_NET_FOUND)
-		WL_ERR((" PNO Event\n"));
-
 	if (likely(!wl_enq_event(wl, ndev, event_type, e, data)))
 		wl_wakeup_event(wl);
 }
@@ -5816,22 +6267,7 @@
 	kfree(e);
 }
 
-void wl_cfg80211_set_sdio_func(void *func)
-{
-	cfg80211_sdio_func = (struct sdio_func *)func;
-}
-
-static void wl_clear_sdio_func(void)
-{
-	cfg80211_sdio_func = NULL;
-}
-
-struct sdio_func *wl_cfg80211_get_sdio_func(void)
-{
-	return cfg80211_sdio_func;
-}
-
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
 {
 	s32 infra = 0;
 	s32 err = 0;
@@ -5868,11 +6304,12 @@
 		return err;
 	}
 
-	set_mode_by_netdev(wl, ndev, mode);
+	wl_set_mode_by_netdev(wl, ndev, mode);
 
 	return 0;
 }
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
 {
 	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
 
@@ -5885,7 +6322,7 @@
 	err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
 	if (unlikely(err)) {
 		WL_ERR(("Get event_msgs error (%d)\n", err));
-		goto dongle_eventmsg_out;
+		goto eventmsg_out;
 	}
 	memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
 	if (add) {
@@ -5898,353 +6335,15 @@
 	err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
 	if (unlikely(err)) {
 		WL_ERR(("Set event_msgs error (%d)\n", err));
-		goto dongle_eventmsg_out;
+		goto eventmsg_out;
 	}
 
-dongle_eventmsg_out:
+eventmsg_out:
 	return err;
 
 }
 
-
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
-{
-
-	s32 err = 0;
-
-	return err;
-}
-
-static s32 wl_dongle_up(struct net_device *ndev, u32 up)
-{
-	s32 err = 0;
-
-	err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
-	if (unlikely(err)) {
-		WL_ERR(("WLC_UP error (%d)\n", err));
-	}
-	return err;
-}
-
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
-{
-	s32 err = 0;
-
-	WL_TRACE(("In\n"));
-	err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
-	if (unlikely(err)) {
-		WL_ERR(("WLC_SET_PM error (%d)\n", err));
-	}
-	return err;
-}
-
-static s32
-wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
-{
-	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-	s32 err = 0;
-
-	/* Match Host and Dongle rx alignment */
-	bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
-		sizeof(iovbuf));
-	err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-	if (unlikely(err)) {
-		WL_ERR(("txglomalign error (%d)\n", err));
-		goto dongle_glom_out;
-	}
-	/* disable glom option per default */
-	bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
-	err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-	if (unlikely(err)) {
-		WL_ERR(("txglom error (%d)\n", err));
-		goto dongle_glom_out;
-	}
-dongle_glom_out:
-	return err;
-}
-
-static s32
-wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
-{
-	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-	s32 err = 0;
-
-	/* Setup timeout if Beacons are lost and roam is off to report link down */
-	if (roamvar) {
-		bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
-			sizeof(iovbuf));
-		err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-		if (unlikely(err)) {
-			WL_ERR(("bcn_timeout error (%d)\n", err));
-			goto dongle_rom_out;
-		}
-	}
-	/* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
-	bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
-	err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-	if (unlikely(err)) {
-		WL_ERR(("roam_off error (%d)\n", err));
-		goto dongle_rom_out;
-	}
-dongle_rom_out:
-	return err;
-}
-
-static s32
-wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
-	s32 scan_unassoc_time)
-{
-	s32 err = 0;
-
-	err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
-		sizeof(scan_assoc_time), true);
-	if (err) {
-		if (err == -EOPNOTSUPP) {
-			WL_INFO(("Scan assoc time is not supported\n"));
-		} else {
-			WL_ERR(("Scan assoc time error (%d)\n", err));
-		}
-		goto dongle_scantime_out;
-	}
-	err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
-		sizeof(scan_unassoc_time), true);
-	if (err) {
-		if (err == -EOPNOTSUPP) {
-			WL_INFO(("Scan unassoc time is not supported\n"));
-		} else {
-			WL_ERR(("Scan unassoc time error (%d)\n", err));
-		}
-		goto dongle_scantime_out;
-	}
-
-dongle_scantime_out:
-	return err;
-}
-
-static s32
-wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
-{
-	/* Room for "event_msgs" + '\0' + bitvec */
-	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-	s32 err = 0;
-
-	/* Set ARP offload */
-	bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
-	err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-	if (err) {
-		if (err == -EOPNOTSUPP)
-			WL_INFO(("arpoe is not supported\n"));
-		else
-			WL_ERR(("arpoe error (%d)\n", err));
-
-		goto dongle_offload_out;
-	}
-	bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
-	err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-	if (err) {
-		if (err == -EOPNOTSUPP)
-			WL_INFO(("arp_ol is not supported\n"));
-		else
-			WL_ERR(("arp_ol error (%d)\n", err));
-
-		goto dongle_offload_out;
-	}
-
-dongle_offload_out:
-	return err;
-}
-
-static s32 wl_pattern_atoh(s8 *src, s8 *dst)
-{
-	int i;
-	if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
-		WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
-		return -1;
-	}
-	src = src + 2;		/* Skip past 0x */
-	if (strlen(src) % 2 != 0) {
-		WL_ERR(("Mask invalid format. Needs to be of even length\n"));
-		return -1;
-	}
-	for (i = 0; *src != '\0'; i++) {
-		char num[3];
-		strncpy(num, src, 2);
-		num[2] = '\0';
-		dst[i] = (u8) simple_strtoul(num, NULL, 16);
-		src += 2;
-	}
-	return i;
-}
-
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
-{
-	/* Room for "event_msgs" + '\0' + bitvec */
-	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-	const s8 *str;
-	struct wl_pkt_filter pkt_filter;
-	struct wl_pkt_filter *pkt_filterp;
-	s32 buf_len;
-	s32 str_len;
-	u32 mask_size;
-	u32 pattern_size;
-	s8 buf[256];
-	s32 err = 0;
-
-	/* add a default packet filter pattern */
-	str = "pkt_filter_add";
-	str_len = strlen(str);
-	strncpy(buf, str, str_len);
-	buf[str_len] = '\0';
-	buf_len = str_len + 1;
-
-	pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
-
-	/* Parse packet filter id. */
-	pkt_filter.id = htod32(100);
-
-	/* Parse filter polarity. */
-	pkt_filter.negate_match = htod32(0);
-
-	/* Parse filter type. */
-	pkt_filter.type = htod32(0);
-
-	/* Parse pattern filter offset. */
-	pkt_filter.u.pattern.offset = htod32(0);
-
-	/* Parse pattern filter mask. */
-	mask_size = htod32(wl_pattern_atoh("0xff",
-		(char *)pkt_filterp->u.pattern.
-		    mask_and_pattern));
-
-	/* Parse pattern filter pattern. */
-	pattern_size = htod32(wl_pattern_atoh("0x00",
-		(char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
-
-	if (mask_size != pattern_size) {
-		WL_ERR(("Mask and pattern not the same size\n"));
-		err = -EINVAL;
-		goto dongle_filter_out;
-	}
-
-	pkt_filter.u.pattern.size_bytes = mask_size;
-	buf_len += WL_PKT_FILTER_FIXED_LEN;
-	buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
-
-	/* Keep-alive attributes are set in local
-	 * variable (keep_alive_pkt), and
-	 * then memcpy'ed into buffer (keep_alive_pktp) since there is no
-	 * guarantee that the buffer is properly aligned.
-	 */
-	memcpy((char *)pkt_filterp, &pkt_filter,
-		WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
-
-	err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
-	if (err) {
-		if (err == -EOPNOTSUPP) {
-			WL_INFO(("filter not supported\n"));
-		} else {
-			WL_ERR(("filter (%d)\n", err));
-		}
-		goto dongle_filter_out;
-	}
-
-	/* set mode to allow pattern */
-	bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
-		sizeof(iovbuf));
-	err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-	if (err) {
-		if (err == -EOPNOTSUPP) {
-			WL_INFO(("filter_mode not supported\n"));
-		} else {
-			WL_ERR(("filter_mode (%d)\n", err));
-		}
-		goto dongle_filter_out;
-	}
-
-dongle_filter_out:
-	return err;
-}
-#endif				/* !EMBEDDED_PLATFORM */
-
-s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
-{
-#ifndef DHD_SDALIGN
-#define DHD_SDALIGN	32
-#endif
-	struct net_device *ndev;
-	struct wireless_dev *wdev;
-	s32 err = 0;
-
-	WL_TRACE(("In\n"));
-	if (wl->dongle_up) {
-		WL_ERR(("Dongle is already up\n"));
-		return err;
-	}
-
-	ndev = wl_to_prmry_ndev(wl);
-	wdev = ndev->ieee80211_ptr;
-	if (need_lock)
-		rtnl_lock();
-#ifndef EMBEDDED_PLATFORM
-	err = wl_dongle_up(ndev, 0);
-	if (unlikely(err)) {
-		WL_ERR(("wl_dongle_up failed\n"));
-		goto default_conf_out;
-	}
-	err = wl_dongle_country(ndev, 0);
-	if (unlikely(err)) {
-		WL_ERR(("wl_dongle_country failed\n"));
-		goto default_conf_out;
-	}
-	err = wl_dongle_power(ndev, PM_FAST);
-	if (unlikely(err)) {
-		WL_ERR(("wl_dongle_power failed\n"));
-		goto default_conf_out;
-	}
-	err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
-	if (unlikely(err)) {
-		WL_ERR(("wl_dongle_glom failed\n"));
-		goto default_conf_out;
-	}
-	err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
-	if (unlikely(err)) {
-		WL_ERR(("wl_dongle_roam failed\n"));
-		goto default_conf_out;
-	}
-	wl_dongle_scantime(ndev, 40, 80);
-	wl_dongle_offload(ndev, 1, 0xf);
-	wl_dongle_filter(ndev, 1);
-#endif				/* !EMBEDDED_PLATFORM */
-
-	err = wl_dongle_mode(wl, ndev, wdev->iftype);
-	if (unlikely(err && err != -EINPROGRESS)) {
-		WL_ERR(("wl_dongle_mode failed\n"));
-		goto default_conf_out;
-	}
-	err = wl_dongle_probecap(wl);
-	if (unlikely(err)) {
-		WL_ERR(("wl_dongle_probecap failed\n"));
-		goto default_conf_out;
-	}
-
-	/* -EINPROGRESS: Call commit handler */
-
-default_conf_out:
-	if (need_lock)
-		rtnl_unlock();
-
-	wl->dongle_up = true;
-
-	return err;
-
-}
-
-static s32 wl_update_wiphybands(struct wl_priv *wl)
+s32 wl_update_wiphybands(struct wl_priv *wl)
 {
 	struct wiphy *wiphy;
 	s8 phylist_buf[128];
@@ -6271,16 +6370,27 @@
 static s32 __wl_cfg80211_up(struct wl_priv *wl)
 {
 	s32 err = 0;
+	struct net_device *ndev = wl_to_prmry_ndev(wl);
+	struct wireless_dev *wdev = ndev->ieee80211_ptr;
 
 	WL_TRACE(("In\n"));
-	wl_debugfs_add_netdev_params(wl);
 
-	err = wl_config_dongle(wl, false);
+	err = dhd_config_dongle(wl, false);
 	if (unlikely(err))
 		return err;
-	dhd_monitor_init(wl->pub);
-	wl_invoke_iscan(wl);
-	wl_set_drv_status(wl, READY);
+
+	err = wl_config_ifmode(wl, ndev, wdev->iftype);
+	if (unlikely(err && err != -EINPROGRESS)) {
+		WL_ERR(("wl_config_ifmode failed\n"));
+	}
+	err = wl_update_wiphybands(wl);
+	if (unlikely(err)) {
+		WL_ERR(("wl_update_wiphybands failed\n"));
+	}
+
+	err = dhd_monitor_init(wl->pub);
+	err = wl_invoke_iscan(wl);
+	wl_set_drv_status(wl, READY, ndev);
 	return err;
 }
 
@@ -6288,47 +6398,47 @@
 {
 	s32 err = 0;
 	unsigned long flags;
+	struct net_info *iter, *next;
+	struct net_device *ndev = wl_to_prmry_ndev(wl);
 
 	WL_TRACE(("In\n"));
 	/* Check if cfg80211 interface is already down */
-	if (!wl_get_drv_status(wl, READY))
+	if (!wl_get_drv_status(wl, READY, ndev))
 		return err;	/* it is even not ready */
-
-	wl_set_drv_status(wl, SCAN_ABORTING);
+	for_each_ndev(wl, iter, next)
+		wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
 
 	wl_term_iscan(wl);
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 	if (wl->scan_request) {
 		cfg80211_scan_done(wl->scan_request, true);
 		wl->scan_request = NULL;
 	}
-	wl_clr_drv_status(wl, READY);
-	wl_clr_drv_status(wl, SCANNING);
-	wl_clr_drv_status(wl, SCAN_ABORTING);
-	wl_clr_drv_status(wl, CONNECTING);
-	wl_clr_drv_status(wl, CONNECTED);
-	wl_clr_drv_status(wl, DISCONNECTING);
-	if (wl_get_drv_status(wl, AP_CREATED)) {
-		wl_clr_drv_status(wl, AP_CREATED);
-		wl_clr_drv_status(wl, AP_CREATING);
+	for_each_ndev(wl, iter, next) {
+		wl_clr_drv_status(wl, READY, iter->ndev);
+		wl_clr_drv_status(wl, SCANNING, iter->ndev);
+		wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev);
+		wl_clr_drv_status(wl, CONNECTING, iter->ndev);
+		wl_clr_drv_status(wl, CONNECTED, iter->ndev);
+		wl_clr_drv_status(wl, DISCONNECTING, iter->ndev);
+		wl_clr_drv_status(wl, AP_CREATED, iter->ndev);
+		wl_clr_drv_status(wl, AP_CREATING, iter->ndev);
 	}
 	wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
 		NL80211_IFTYPE_STATION;
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 
-	wl->dongle_up = false;
+	DNGL_FUNC(dhd_cfg80211_down, (wl));
 	wl_flush_eq(wl);
 	wl_link_down(wl);
 	if (wl->p2p_supported)
 		wl_cfgp2p_down(wl);
 	dhd_monitor_uninit();
 
-	wl_debugfs_remove_netdev(wl);
-
 	return err;
 }
 
-s32 wl_cfg80211_up(void)
+s32 wl_cfg80211_up(void *para)
 {
 	struct wl_priv *wl;
 	s32 err = 0;
@@ -6341,17 +6451,16 @@
 	if (err)
 		WL_ERR(("__wl_cfg80211_up failed\n"));
 	mutex_unlock(&wl->usr_sync);
-
 	return err;
 }
 
-/* Private Event  to Supplicant with indication that FW hangs */
+/* Private Event to Supplicant with indication that chip hangs */
 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
 {
 	struct wl_priv *wl;
 	wl = wlcfg_drv_priv;
 
-	WL_ERR(("In : FW crash Eventing\n"));
+	WL_ERR(("In : chip crash eventing\n"));
 	cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
 	if (wl != NULL) {
 		wl_link_down(wl);
@@ -6359,7 +6468,7 @@
 	return 0;
 }
 
-s32 wl_cfg80211_down(void)
+s32 wl_cfg80211_down(void *para)
 {
 	struct wl_priv *wl;
 	s32 err = 0;
@@ -6373,84 +6482,79 @@
 	return err;
 }
 
-static s32 wl_dongle_probecap(struct wl_priv *wl)
-{
-	s32 err = 0;
-
-	err = wl_update_wiphybands(wl);
-	if (unlikely(err))
-		return err;
-
-	return err;
-}
-
-static void *wl_read_prof(struct wl_priv *wl, s32 item)
+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item)
 {
 	unsigned long flags;
 	void *rptr = NULL;
+	struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
 
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+	if (!profile)
+		return NULL;
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 	switch (item) {
 	case WL_PROF_SEC:
-		rptr = &wl->profile->sec;
+		rptr = &profile->sec;
 		break;
 	case WL_PROF_ACT:
-		rptr = &wl->profile->active;
+		rptr = &profile->active;
 		break;
 	case WL_PROF_BSSID:
-		rptr = &wl->profile->bssid;
+		rptr = profile->bssid;
 		break;
 	case WL_PROF_SSID:
-		rptr = &wl->profile->ssid;
+		rptr = &profile->ssid;
 		break;
 	}
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 	if (!rptr)
 		WL_ERR(("invalid item (%d)\n", item));
 	return rptr;
 }
 
 static s32
-wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
-	s32 item)
+wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
+	const wl_event_msg_t *e, void *data, s32 item)
 {
 	s32 err = 0;
 	struct wlc_ssid *ssid;
 	unsigned long flags;
+	struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
 
-	flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+	if (!profile)
+		return WL_INVALID;
+	spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 	switch (item) {
 	case WL_PROF_SSID:
 		ssid = (wlc_ssid_t *) data;
-		memset(wl->profile->ssid.SSID, 0,
-			sizeof(wl->profile->ssid.SSID));
-		memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
-		wl->profile->ssid.SSID_len = ssid->SSID_len;
+		memset(profile->ssid.SSID, 0,
+			sizeof(profile->ssid.SSID));
+		memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
+		profile->ssid.SSID_len = ssid->SSID_len;
 		break;
 	case WL_PROF_BSSID:
 		if (data)
-			memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN);
+			memcpy(profile->bssid, data, ETHER_ADDR_LEN);
 		else
-			memset(wl->profile->bssid, 0, ETHER_ADDR_LEN);
+			memset(profile->bssid, 0, ETHER_ADDR_LEN);
 		break;
 	case WL_PROF_SEC:
-		memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
+		memcpy(&profile->sec, data, sizeof(profile->sec));
 		break;
 	case WL_PROF_ACT:
-		wl->profile->active = *(bool *)data;
+		profile->active = *(bool *)data;
 		break;
 	case WL_PROF_BEACONINT:
-		wl->profile->beacon_interval = *(u16 *)data;
+		profile->beacon_interval = *(u16 *)data;
 		break;
 	case WL_PROF_DTIMPERIOD:
-		wl->profile->dtim_period = *(u8 *)data;
+		profile->dtim_period = *(u8 *)data;
 		break;
 	default:
 		WL_ERR(("unsupported item (%d)\n", item));
 		err = -EOPNOTSUPP;
 		break;
 	}
-	dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+	spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 	return err;
 }
 
@@ -6467,7 +6571,7 @@
 
 static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev)
 {
-	return get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
+	return wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
 }
 
 static __used bool wl_is_ibssstarter(struct wl_priv *wl)
@@ -6578,114 +6682,28 @@
 	}
 }
 
-s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
-{
-	const struct firmware *fw_entry;
-	struct wl_priv *wl;
-
-	wl = wlcfg_drv_priv;
-
-	fw_entry = wl->fw->fw_entry;
-
-	if (fw_entry->size < wl->fw->ptr + size)
-		size = fw_entry->size - wl->fw->ptr;
-
-	memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
-	wl->fw->ptr += size;
-	return size;
-}
-
-void wl_cfg80211_release_fw(void)
-{
-	struct wl_priv *wl;
-
-	wl = wlcfg_drv_priv;
-	release_firmware(wl->fw->fw_entry);
-	wl->fw->ptr = 0;
-}
-
-void *wl_cfg80211_request_fw(s8 *file_name)
-{
-	struct wl_priv *wl;
-	const struct firmware *fw_entry = NULL;
-	s32 err = 0;
-
-	WL_TRACE(("In\n"));
-	WL_DBG(("file name : \"%s\"\n", file_name));
-	wl = wlcfg_drv_priv;
-
-	if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
-		err = request_firmware(&wl->fw->fw_entry, file_name,
-			&wl_cfg80211_get_sdio_func()->dev);
-		if (unlikely(err)) {
-			WL_ERR(("Could not download fw (%d)\n", err));
-			goto req_fw_out;
-		}
-		set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
-		fw_entry = wl->fw->fw_entry;
-		if (fw_entry) {
-			WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size,
-				fw_entry->data));
-		}
-	} else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
-		err = request_firmware(&wl->fw->fw_entry, file_name,
-			&wl_cfg80211_get_sdio_func()->dev);
-		if (unlikely(err)) {
-			WL_ERR(("Could not download nvram (%d)\n", err));
-			goto req_fw_out;
-		}
-		set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
-		fw_entry = wl->fw->fw_entry;
-		if (fw_entry) {
-			WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size,
-				fw_entry->data));
-		}
-	} else {
-		WL_DBG(("Downloading already done. Nothing to do more\n"));
-		err = -EPERM;
-	}
-
-req_fw_out:
-	if (unlikely(err)) {
-		return NULL;
-	}
-	wl->fw->ptr = 0;
-	return (void *)fw_entry->data;
-}
-
-s8 *wl_cfg80211_get_fwname(void)
-{
-	struct wl_priv *wl;
-
-	wl = wlcfg_drv_priv;
-	strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
-	return wl->fw->fw_name;
-}
-
-s8 *wl_cfg80211_get_nvramname(void)
-{
-	struct wl_priv *wl;
-
-	wl = wlcfg_drv_priv;
-	strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
-	return wl->fw->nvram_name;
-}
-
 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
 {
-	struct wl_priv *wl;
-	dhd_pub_t *dhd_pub;
+	struct wl_priv *wl = wlcfg_drv_priv;
 	struct ether_addr p2pif_addr;
+	struct ether_addr primary_mac;
 
-	wl = wlcfg_drv_priv;
-	dhd_pub = (dhd_pub_t *)wl->pub;
-	wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);
+	if (!wl->p2p)
+		return -1;
+	if (!p2p_is_on(wl)) {
+		get_primary_mac(wl, &primary_mac);
+		wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr);
+	} else {
+		memcpy(p2pdev_addr->octet,
+			wl->p2p->dev_addr.octet, ETHER_ADDR_LEN);
+	}
 
 	return 0;
 }
 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
 {
 	struct wl_priv *wl;
+
 	wl = wlcfg_drv_priv;
 
 	return wl_cfgp2p_set_p2p_noa(wl, net, buf, len);
@@ -6719,8 +6737,8 @@
 	if (wl->p2p && wl->p2p->vif_created) {
 		ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
 		bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION);
-	} else if (wl_get_drv_status(wl, AP_CREATING) ||
-		wl_get_drv_status(wl, AP_CREATED)) {
+	} else if (wl_get_drv_status(wl, AP_CREATING, net) ||
+		wl_get_drv_status(wl, AP_CREATED, net)) {
 		ndev = net;
 		bssidx = 0;
 	}
@@ -6743,69 +6761,6 @@
 	return ret;
 }
 
-static __used void wl_dongle_poweron(struct wl_priv *wl)
-{
-	WL_DBG(("Enter \n"));
-	dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
-
-#if defined(BCMLXSDMMC)
-	sdioh_start(NULL, 0);
-#endif
-#if defined(BCMLXSDMMC)
-	sdioh_start(NULL, 1);
-#endif
-	wl_cfg80211_resume(wl_to_wiphy(wl));
-}
-
-static __used void wl_dongle_poweroff(struct wl_priv *wl)
-{
-	WL_DBG(("Enter \n"));
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
-	wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
-#else
-	wl_cfg80211_suspend(wl_to_wiphy(wl));
-#endif
-
-#if defined(BCMLXSDMMC)
-	sdioh_stop(NULL);
-#endif
-	/* clean up dtim_skip setting */
-	dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
-}
-
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
-{
-	char buf[10+IFNAMSIZ];
-	struct dentry *fd;
-	s32 err = 0;
-
-	WL_TRACE(("In\n"));
-	sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name);
-	wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir);
-
-	fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir,
-		(u16 *)&wl->profile->beacon_interval);
-	if (!fd) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir,
-		(u8 *)&wl->profile->dtim_period);
-	if (!fd) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-err_out:
-	return err;
-}
-
-static void wl_debugfs_remove_netdev(struct wl_priv *wl)
-{
-	WL_DBG(("Enter \n"));
-}
-
 static const struct rfkill_ops wl_rfkill_ops = {
 	.set_block = wl_rfkill_set
 };
@@ -6834,7 +6789,7 @@
 		return -EINVAL;
 	if (setup) {
 		wl->rfkill = rfkill_alloc("brcmfmac-wifi",
-			&wl_cfg80211_get_sdio_func()->dev,
+			wl_cfg80211_get_parent_dev(),
 			RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl);
 
 		if (!wl->rfkill) {
@@ -6860,471 +6815,42 @@
 	return err;
 }
 
-#if defined(COEX_DHCP)
-/*
- * get named driver variable to uint register value and return error indication
- * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
- */
-static int
-dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
-	uint reg, int *retval)
+struct device *wl_cfg80211_get_parent_dev(void)
 {
-	union {
-		char buf[WLC_IOCTL_SMLEN];
-		int val;
-	} var;
-	int error;
-
-	bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
-		(char *)(&var), sizeof(var.buf));
-	error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
-
-	*retval = dtoh32(var.val);
-	return (error);
+	return cfg80211_parent_dev;
 }
 
-static int
-dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+void wl_cfg80211_set_parent_dev(void *dev)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
-	char ioctlbuf[1024];
-#else
-	static char ioctlbuf[1024];
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
-
-	bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
-
-	return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true));
-}
-/*
-get named driver variable to uint register value and return error indication
-calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
-*/
-static int
-dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
-{
-	char reg_addr[8];
-
-	memset(reg_addr, 0, sizeof(reg_addr));
-	memcpy((char *)&reg_addr[0], (char *)addr, 4);
-	memcpy((char *)&reg_addr[4], (char *)val, 4);
-
-	return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+	cfg80211_parent_dev = dev;
 }
 
-static bool btcoex_is_sco_active(struct net_device *dev)
+static void wl_cfg80211_clear_parent_dev(void)
 {
-	int ioc_res = 0;
-	bool res = FALSE;
-	int sco_id_cnt = 0;
-	int param27;
-	int i;
-
-	for (i = 0; i < 12; i++) {
-
-		ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
-
-		WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
-			__FUNCTION__, i, param27));
-
-		if (ioc_res < 0) {
-			WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
-			break;
-		}
-
-		if ((param27 & 0x6) == 2) { /* count both sco & esco  */
-			sco_id_cnt++;
-		}
-
-		if (sco_id_cnt > 2) {
-			WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d  samples:%d\n",
-				__FUNCTION__, sco_id_cnt, i));
-			res = TRUE;
-			break;
-		}
-
-		msleep(5);
-	}
-
-	return res;
+	cfg80211_parent_dev = NULL;
 }
 
-#if defined(BT_DHCP_eSCO_FIX)
-/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
-static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac)
 {
-	static bool saved_status = FALSE;
+	wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL,
+		0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
+	memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN);
+}
 
-	char buf_reg50va_dhcp_on[8] =
-		{ 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
-	char buf_reg51va_dhcp_on[8] =
-		{ 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-	char buf_reg64va_dhcp_on[8] =
-		{ 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-	char buf_reg65va_dhcp_on[8] =
-		{ 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-	char buf_reg71va_dhcp_on[8] =
-		{ 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-	uint32 regaddr;
-	static uint32 saved_reg50;
-	static uint32 saved_reg51;
-	static uint32 saved_reg64;
-	static uint32 saved_reg65;
-	static uint32 saved_reg71;
+int wl_cfg80211_do_driver_init(struct net_device *net)
+{
+	struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net);
 
-	if (trump_sco) {
-		/* this should reduce eSCO agressive retransmit
-		 * w/o breaking it
-		 */
+	if (!wl || !wl->wdev)
+		return -EINVAL;
 
-		/* 1st save current */
-		WL_TRACE(("Do new SCO/eSCO coex algo {save &"
-			  "override}\n"));
-		if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
-			(!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
-			(!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
-			(!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
-			(!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
-			saved_status = TRUE;
-			WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
-				  "0x%x 0x%x 0x%x 0x%x 0x%x\n",
-				  __FUNCTION__, saved_reg50, saved_reg51,
-				  saved_reg64, saved_reg65, saved_reg71));
-		} else {
-			WL_ERR((":%s: save btc_params failed\n",
-				__FUNCTION__));
-			saved_status = FALSE;
-			return -1;
-		}
-
-		WL_TRACE(("override with [50,51,64,65,71]:"
-			  "0x%x 0x%x 0x%x 0x%x 0x%x\n",
-			  *(u32 *)(buf_reg50va_dhcp_on+4),
-			  *(u32 *)(buf_reg51va_dhcp_on+4),
-			  *(u32 *)(buf_reg64va_dhcp_on+4),
-			  *(u32 *)(buf_reg65va_dhcp_on+4),
-			  *(u32 *)(buf_reg71va_dhcp_on+4)));
-
-		dev_wlc_bufvar_set(dev, "btc_params",
-			(char *)&buf_reg50va_dhcp_on[0], 8);
-		dev_wlc_bufvar_set(dev, "btc_params",
-			(char *)&buf_reg51va_dhcp_on[0], 8);
-		dev_wlc_bufvar_set(dev, "btc_params",
-			(char *)&buf_reg64va_dhcp_on[0], 8);
-		dev_wlc_bufvar_set(dev, "btc_params",
-			(char *)&buf_reg65va_dhcp_on[0], 8);
-		dev_wlc_bufvar_set(dev, "btc_params",
-			(char *)&buf_reg71va_dhcp_on[0], 8);
-
-		saved_status = TRUE;
-	} else if (saved_status) {
-		/* restore previously saved bt params */
-		WL_TRACE(("Do new SCO/eSCO coex algo {save &"
-			  "override}\n"));
-
-		regaddr = 50;
-		dev_wlc_intvar_set_reg(dev, "btc_params",
-			(char *)&regaddr, (char *)&saved_reg50);
-		regaddr = 51;
-		dev_wlc_intvar_set_reg(dev, "btc_params",
-			(char *)&regaddr, (char *)&saved_reg51);
-		regaddr = 64;
-		dev_wlc_intvar_set_reg(dev, "btc_params",
-			(char *)&regaddr, (char *)&saved_reg64);
-		regaddr = 65;
-		dev_wlc_intvar_set_reg(dev, "btc_params",
-			(char *)&regaddr, (char *)&saved_reg65);
-		regaddr = 71;
-		dev_wlc_intvar_set_reg(dev, "btc_params",
-			(char *)&regaddr, (char *)&saved_reg71);
-
-		WL_TRACE(("restore bt_params[50,51,64,65,71]:"
-			"0x%x 0x%x 0x%x 0x%x 0x%x\n",
-			saved_reg50, saved_reg51, saved_reg64,
-			saved_reg65, saved_reg71));
-
-		saved_status = FALSE;
-	} else {
-		WL_ERR((":%s att to restore not saved BTCOEX params\n",
-			__FUNCTION__));
+	if (dhd_do_driver_init(wl->wdev->netdev) < 0)
 		return -1;
-	}
-	return 0;
-}
-#endif /* BT_DHCP_eSCO_FIX */
 
-static void
-wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
-{
-#if defined(BT_DHCP_USE_FLAGS)
-	char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
-	char buf_flag7_default[8]   = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
-#endif
-
-#if defined(BT_DHCP_eSCO_FIX)
-	/* set = 1, save & turn on  0 - off & restore prev settings */
-	set_btc_esco_params(dev, set);
-#endif
-
-#if defined(BT_DHCP_USE_FLAGS)
-	WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
-	if (set == TRUE)
-		/* Forcing bt_flag7  */
-		dev_wlc_bufvar_set(dev, "btc_flags",
-			(char *)&buf_flag7_dhcp_on[0],
-			sizeof(buf_flag7_dhcp_on));
-	else
-		/* Restoring default bt flag7 */
-		dev_wlc_bufvar_set(dev, "btc_flags",
-			(char *)&buf_flag7_default[0],
-			sizeof(buf_flag7_default));
-#endif
-}
-
-static void wl_cfg80211_bt_timerfunc(ulong data)
-{
-	struct btcoex_info *bt_local = (struct btcoex_info *)data;
-	WL_TRACE(("%s\n", __FUNCTION__));
-	bt_local->timer_on = 0;
-	schedule_work(&bt_local->work);
-}
-
-static void wl_cfg80211_bt_handler(struct work_struct *work)
-{
-	struct btcoex_info *btcx_inf;
-
-	btcx_inf = container_of(work, struct btcoex_info, work);
-
-	if (btcx_inf->timer_on) {
-		btcx_inf->timer_on = 0;
-		del_timer_sync(&btcx_inf->timer);
-	}
-
-	switch (btcx_inf->bt_state) {
-		case BT_DHCP_START:
-			/* DHCP started
-			 * provide OPPORTUNITY window to get DHCP address
-			 */
-			WL_TRACE(("%s bt_dhcp stm: started \n",
-				__FUNCTION__));
-			btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
-			mod_timer(&btcx_inf->timer,
-				jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
-			btcx_inf->timer_on = 1;
-			break;
-
-		case BT_DHCP_OPPR_WIN:
-			if (btcx_inf->dhcp_done) {
-				WL_TRACE(("%s DHCP Done before T1 expiration\n",
-					__FUNCTION__));
-				goto btc_coex_idle;
-			}
-
-			/* DHCP is not over yet, start lowering BT priority
-			 * enforce btc_params + flags if necessary
-			 */
-			WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
-				BT_DHCP_OPPR_WIN_TIME));
-			if (btcx_inf->dev)
-				wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
-			btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
-			mod_timer(&btcx_inf->timer,
-				jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
-			btcx_inf->timer_on = 1;
-			break;
-
-		case BT_DHCP_FLAG_FORCE_TIMEOUT:
-			if (btcx_inf->dhcp_done) {
-				WL_TRACE(("%s DHCP Done before T2 expiration\n",
-					__FUNCTION__));
-			} else {
-				/* Noo dhcp during T1+T2, restore BT priority */
-				WL_TRACE(("%s DHCP wait interval T2:%d"
-					  "msec expired\n", __FUNCTION__,
-					  BT_DHCP_FLAG_FORCE_TIME));
-			}
-
-			/* Restoring default bt priority */
-			if (btcx_inf->dev)
-				wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
-btc_coex_idle:
-			btcx_inf->bt_state = BT_DHCP_IDLE;
-			btcx_inf->timer_on = 0;
-			break;
-
-		default:
-			WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
-				btcx_inf->bt_state));
-			if (btcx_inf->dev)
-				wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
-			btcx_inf->bt_state = BT_DHCP_IDLE;
-			btcx_inf->timer_on = 0;
-			break;
-	}
-
-	net_os_wake_unlock(btcx_inf->dev);
-}
-
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
-{
-	struct btcoex_info *btco_inf = NULL;
-
-	btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
-	if (!btco_inf)
-		return -ENOMEM;
-
-	btco_inf->bt_state = BT_DHCP_IDLE;
-	btco_inf->ts_dhcp_start = 0;
-	btco_inf->ts_dhcp_ok = 0;
-	/* Set up timer for BT  */
-	btco_inf->timer_ms = 10;
-	init_timer(&btco_inf->timer);
-	btco_inf->timer.data = (ulong)btco_inf;
-	btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
-
-	btco_inf->dev = wl->wdev->netdev;
-
-	INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
-
-	wl->btcoex_info = btco_inf;
 	return 0;
 }
 
-static void
-wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+void wl_cfg80211_enable_trace(int level)
 {
-	if (!wl->btcoex_info)
-		return;
-
-	if (!wl->btcoex_info->timer_on) {
-		wl->btcoex_info->timer_on = 0;
-		del_timer_sync(&wl->btcoex_info->timer);
-	}
-
-	cancel_work_sync(&wl->btcoex_info->work);
-
-	kfree(wl->btcoex_info);
-	wl->btcoex_info = NULL;
-}
-#endif		/* COEX_DHCP */
-
-int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
-{
-	char powermode_val = 0;
-	char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
-	char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
-	char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
-
-	uint32 regaddr;
-	static uint32 saved_reg66;
-	static uint32 saved_reg41;
-	static uint32 saved_reg68;
-	static bool saved_status = FALSE;
-
-#ifdef COEX_DHCP
-	char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
-	struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
-#endif /* COEX_DHCP */
-
-	/* Figure out powermode 1 or o command */
-	strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
-
-	if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
-
-		WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
-
-		/* Retrieve and saved orig regs value */
-		if ((saved_status == FALSE) &&
-			(!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
-			(!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
-			(!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
-				saved_status = TRUE;
-				WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
-					saved_reg66, saved_reg41, saved_reg68));
-
-				/* Disable PM mode during dhpc session */
-
-				/* Disable PM mode during dhpc session */
-#ifdef COEX_DHCP
-				/* Start  BT timer only for SCO connection */
-				if (btcoex_is_sco_active(dev)) {
-					/* btc_params 66 */
-					dev_wlc_bufvar_set(dev, "btc_params",
-						(char *)&buf_reg66va_dhcp_on[0],
-						sizeof(buf_reg66va_dhcp_on));
-					/* btc_params 41 0x33 */
-					dev_wlc_bufvar_set(dev, "btc_params",
-						(char *)&buf_reg41va_dhcp_on[0],
-						sizeof(buf_reg41va_dhcp_on));
-					/* btc_params 68 0x190 */
-					dev_wlc_bufvar_set(dev, "btc_params",
-						(char *)&buf_reg68va_dhcp_on[0],
-						sizeof(buf_reg68va_dhcp_on));
-					saved_status = TRUE;
-
-					btco_inf->bt_state = BT_DHCP_START;
-					btco_inf->timer_on = 1;
-					mod_timer(&btco_inf->timer, btco_inf->timer.expires);
-					WL_TRACE(("%s enable BT DHCP Timer\n",
-					__FUNCTION__));
-				}
-#endif /* COEX_DHCP */
-		}
-		else if (saved_status == TRUE) {
-			WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
-		}
-	}
-	else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
-
-
-		/* Restoring PM mode */
-
-#ifdef COEX_DHCP
-		/* Stop any bt timer because DHCP session is done */
-		WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
-		if (btco_inf->timer_on) {
-			btco_inf->timer_on = 0;
-			del_timer_sync(&btco_inf->timer);
-
-			if (btco_inf->bt_state != BT_DHCP_IDLE) {
-			/* need to restore original btc flags & extra btc params */
-				WL_TRACE(("%s bt->bt_state:%d\n",
-					__FUNCTION__, btco_inf->bt_state));
-				/* wake up btcoex thread to restore btlags+params  */
-				schedule_work(&btco_inf->work);
-			}
-		}
-
-		/* Restoring btc_flag paramter anyway */
-		if (saved_status == TRUE)
-			dev_wlc_bufvar_set(dev, "btc_flags",
-				(char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
-#endif /* COEX_DHCP */
-
-		/* Restore original values */
-		if (saved_status == TRUE) {
-			regaddr = 66;
-			dev_wlc_intvar_set_reg(dev, "btc_params",
-				(char *)&regaddr, (char *)&saved_reg66);
-			regaddr = 41;
-			dev_wlc_intvar_set_reg(dev, "btc_params",
-				(char *)&regaddr, (char *)&saved_reg41);
-			regaddr = 68;
-			dev_wlc_intvar_set_reg(dev, "btc_params",
-				(char *)&regaddr, (char *)&saved_reg68);
-
-			WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
-				saved_reg66, saved_reg41, saved_reg68));
-		}
-		saved_status = FALSE;
-
-	}
-	else {
-		WL_ERR(("%s Unkwown yet power setting, ignored\n",
-			__FUNCTION__));
-	}
-
-	snprintf(command, 3, "OK");
-
-	return (strlen("OK"));
+	wl_dbg_level |= WL_DBG_DBG;
 }
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index 262335e..2b8e664 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -68,6 +68,9 @@
 			printk args;						\
 		} 								\
 } while (0)
+#ifdef WL_INFO
+#undef WL_INFO
+#endif
 #define	WL_INFO(args)									\
 do {										\
 	if (wl_dbg_level & WL_DBG_INFO) {				\
@@ -75,6 +78,9 @@
 			printk args;						\
 		}								\
 } while (0)
+#ifdef WL_SCAN
+#undef WL_SCAN
+#endif
 #define	WL_SCAN(args)								\
 do {									\
 	if (wl_dbg_level & WL_DBG_SCAN) {			\
@@ -82,6 +88,9 @@
 		printk args;							\
 	}									\
 } while (0)
+#ifdef WL_TRACE
+#undef WL_TRACE
+#endif
 #define	WL_TRACE(args)								\
 do {									\
 	if (wl_dbg_level & WL_DBG_TRACE) {			\
@@ -102,39 +111,30 @@
 #endif				/* (WL_DBG_LEVEL > 0) */
 
 
-#define WL_SCAN_RETRY_MAX	3	/* used for ibss scan */
-#define WL_NUM_PMKIDS_MAX	MAXPMKID	/* will be used
-						 * for 2.6.33 kernel
-						 * or later
-						 */
-#define WL_SCAN_BUF_MAX 		(1024 * 8)
-#define WL_TLV_INFO_MAX 		1024
+#define WL_SCAN_RETRY_MAX	3
+#define WL_NUM_PMKIDS_MAX	MAXPMKID
+#define WL_SCAN_BUF_MAX 	(1024 * 8)
+#define WL_TLV_INFO_MAX 	1024
 #define WL_SCAN_IE_LEN_MAX      2048
-#define WL_BSS_INFO_MAX			2048
-#define WL_ASSOC_INFO_MAX	512	/*
-				 * needs to grab assoc info from dongle to
-				 * report it to cfg80211 through "connect"
-				 * event
-				 */
+#define WL_BSS_INFO_MAX		2048
+#define WL_ASSOC_INFO_MAX	512
 #define WL_IOCTL_LEN_MAX	1024
 #define WL_EXTRA_BUF_MAX	2048
-#define WL_ISCAN_BUF_MAX	2048	/*
-				 * the buf lengh can be WLC_IOCTL_MAXLEN (8K)
-				 * to reduce iteration
-				 */
+#define WL_ISCAN_BUF_MAX	2048
 #define WL_ISCAN_TIMER_INTERVAL_MS	3000
 #define WL_SCAN_ERSULTS_LAST 	(WL_SCAN_RESULTS_NO_MEM+1)
-#define WL_AP_MAX	256	/* virtually unlimitted as long
-				 * as kernel memory allows
-				 */
+#define WL_AP_MAX		256
 #define WL_FILE_NAME_MAX	256
-#define WL_DWELL_TIME		200
-#define WL_LONG_DWELL_TIME	1000
-#define VWDEV_CNT 3
+#define WL_DWELL_TIME 		200
+#define WL_MED_DWELL_TIME       400
+#define WL_LONG_DWELL_TIME 	1000
+#define IFACE_MAX_CNT 		2
 
 #define WL_SCAN_TIMER_INTERVAL_MS	8000 /* Scan timeout */
+#define WL_CHANNEL_SYNC_RETRY 	5
+#define WL_INVALID 		-1
 
-/* dongle status */
+/* driver status */
 enum wl_status {
 	WL_STATUS_READY = 0,
 	WL_STATUS_SCANNING,
@@ -143,7 +143,8 @@
 	WL_STATUS_CONNECTED,
 	WL_STATUS_DISCONNECTING,
 	WL_STATUS_AP_CREATING,
-	WL_STATUS_AP_CREATED
+	WL_STATUS_AP_CREATED,
+	WL_STATUS_SENDING_ACT_FRM
 };
 
 /* wi-fi mode */
@@ -153,7 +154,7 @@
 	WL_MODE_AP
 };
 
-/* dongle profile list */
+/* driver profile list */
 enum wl_prof_list {
 	WL_PROF_MODE,
 	WL_PROF_SSID,
@@ -166,7 +167,7 @@
 	WL_PROF_DTIMPERIOD
 };
 
-/* dongle iscan state */
+/* driver iscan state */
 enum wl_iscan_state {
 	WL_ISCAN_STATE_IDLE,
 	WL_ISCAN_STATE_SCANING
@@ -196,12 +197,8 @@
 	u8 variable[0];
 } __attribute__ ((packed));
 
-/* dongle configuration */
+/* driver configuration */
 struct wl_conf {
-	struct net_mode {
-		struct net_device *ndev;
-		s32 type;
-	} mode [VWDEV_CNT + 1];		/* adhoc , infrastructure or ap */
 	u32 frag_threshold;
 	u32 rts_threshold;
 	u32 retry_short;
@@ -259,22 +256,30 @@
 	u8 channel;
 };
 
-/* dongle profile */
+/* wl driver profile */
 struct wl_profile {
 	u32 mode;
+	s32 band;
 	struct wlc_ssid ssid;
+	struct wl_security sec;
+	struct wl_ibss ibss;
 	u8 bssid[ETHER_ADDR_LEN];
 	u16 beacon_interval;
 	u8 dtim_period;
-	struct wl_security sec;
-	struct wl_ibss ibss;
-	s32 band;
 	bool active;
 };
 
+struct net_info {
+	struct net_device *ndev;
+	struct wireless_dev *wdev;
+	struct wl_profile profile;
+	s32 mode;
+	unsigned long sme_state;
+	struct list_head list; /* list of all net_info structure */
+};
 typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl);
 
-/* dongle iscan controller */
+/* iscan controller */
 struct wl_iscan_ctrl {
 	struct net_device *dev;
 	struct timer_list timer;
@@ -323,9 +328,10 @@
 #define ESCAN_BUF_SIZE (64 * 1024)
 
 struct escan_info {
-    u32 escan_state;
-    u8 escan_buf[ESCAN_BUF_SIZE];
-    struct wiphy *wiphy;
+	u32 escan_state;
+	u8 escan_buf[ESCAN_BUF_SIZE];
+	struct wiphy *wiphy;
+	struct net_device *ndev;
 };
 
 struct ap_info {
@@ -341,14 +347,14 @@
 };
 struct btcoex_info {
 	struct timer_list timer;
-	uint32 timer_ms;
-	uint32 timer_on;
-	uint32 ts_dhcp_start;	/* ms ts ecord time stats */
-	uint32 ts_dhcp_ok;	/* ms ts ecord time stats */
-	bool dhcp_done;		/* flag, indicates that host done with
-				 * dhcp before t1/t2 expiration
-				 */
-	int bt_state;
+	u32 timer_ms;
+	u32 timer_on;
+	u32 ts_dhcp_start;	/* ms ts ecord time stats */
+	u32 ts_dhcp_ok;		/* ms ts ecord time stats */
+	bool dhcp_done;	/* flag, indicates that host done with
+					 * dhcp before t1/t2 expiration
+					 */
+	s32 bt_state;
 	struct work_struct work;
 	struct net_device *dev;
 };
@@ -360,40 +366,50 @@
 	u32 probe_req_ie_len;
 	u32 assoc_req_ie_len;
 };
-/* dongle private data of cfg80211 interface */
+
+struct afx_hdl {
+	wl_af_params_t *pending_tx_act_frm;
+	struct ether_addr	pending_tx_dst_addr;
+	struct net_device *dev;
+	struct work_struct work;
+	u32 bssidx;
+	u32 retry;
+	s32 peer_chan;
+	bool ack_recv;
+};
+
+/* private data of cfg80211 interface */
 struct wl_priv {
 	struct wireless_dev *wdev;	/* representing wl cfg80211 device */
-	struct wireless_dev *vwdev[VWDEV_CNT];
-	struct wl_conf *conf;	/* dongle configuration */
+
+	struct wireless_dev *p2p_wdev;	/* representing wl cfg80211 device for P2P */
+	struct net_device *p2p_net;    /* reference to p2p0 interface */
+
+	struct wl_conf *conf;
 	struct cfg80211_scan_request *scan_request;	/* scan request object */
 	EVENT_HANDLER evt_handler[WLC_E_LAST];
 	struct list_head eq_list;	/* used for event queue */
+	struct list_head net_list;     /* used for struct net_info */
 	spinlock_t eq_lock;	/* for event queue synchronization */
-	struct mutex usr_sync;	/* maily for dongle up/down synchronization */
+	spinlock_t cfgdrv_lock;	/* to protect scan status (and others if needed) */
+	struct completion act_frm_scan;
+	struct mutex usr_sync;	/* maily for up/down synchronization */
 	struct wl_scan_results *bss_list;
 	struct wl_scan_results *scan_results;
 
 	/* scan request object for internal purpose */
 	struct wl_scan_req *scan_req_int;
-
-	/* bss information for cfg80211 layer */
-	struct wl_cfg80211_bss_info *bss_info;
 	/* information element object for internal purpose */
 	struct wl_ie ie;
-
-	/* for synchronization of main event thread */
-	struct wl_profile *profile;	/* holding dongle profile */
 	struct wl_iscan_ctrl *iscan;	/* iscan controller */
 
 	/* association information container */
 	struct wl_connect_info conn_info;
 
-	/* control firwmare and nvram paramter downloading */
-	struct wl_fw_ctrl *fw;
 	struct wl_pmk_list *pmk_list;	/* wpa2 pmk list */
 	tsk_ctl_t event_tsk;  		/* task of main event handler thread */
-	unsigned long status;		/* current dongle status */
 	void *pub;
+	u32 iface_cnt;
 	u32 channel;		/* current channel */
 	bool iscan_on;		/* iscan on/off switch */
 	bool iscan_kickstart;	/* indicate iscan already started */
@@ -403,12 +419,12 @@
 	bool ibss_starter;	/* indicates this sta is ibss starter */
 	bool link_up;		/* link/connection up flag */
 
-	/* indicate whether dongle to support power save mode */
+	/* indicate whether chip to support power save mode */
 	bool pwr_save;
-	bool dongle_up;		/* indicate whether dongle up or not */
-	bool roam_on;		/* on/off switch for dongle self-roaming */
+	bool roam_on;		/* on/off switch for self-roaming */
 	bool scan_tried;	/* indicates if first scan attempted */
-	u8 *ioctl_buf;	/* ioctl buffer */
+	u8 *ioctl_buf;		/* ioctl buffer */
+	struct mutex ioctl_buf_sync;
 	u8 *escan_ioctl_buf;
 	u8 *extra_buf;	/* maily to grab assoc information */
 	struct dentry *debugfsdir;
@@ -416,8 +432,10 @@
 	bool rf_blocked;
 	struct ieee80211_channel remain_on_chan;
 	enum nl80211_channel_type remain_on_chan_type;
-	u64 cache_cookie;
-	wait_queue_head_t dongle_event_wait;
+	u64 send_action_id;
+	u64 last_roc_id;
+	wait_queue_head_t netif_change_event;
+	struct afx_hdl *afx_hdl;
 	struct ap_info *ap_info;
 	struct sta_info *sta_info;
 	struct p2p_info *p2p;
@@ -426,6 +444,152 @@
 	struct timer_list scan_timeout;   /* Timer for catch scan event timeout */
 };
 
+static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
+{
+	return bss = bss ?
+		(struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
+}
+
+static inline s32
+wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev,
+	struct wireless_dev * wdev, s32 mode)
+{
+	struct net_info *_net_info;
+	s32 err = 0;
+	if (wl->iface_cnt == IFACE_MAX_CNT)
+		return -ENOMEM;
+	_net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL);
+	if (!_net_info)
+		err = -ENOMEM;
+	else {
+		_net_info->mode = mode;
+		_net_info->ndev = ndev;
+		_net_info->wdev = wdev;
+		wl->iface_cnt++;
+		list_add(&_net_info->list, &wl->net_list);
+	}
+	return err;
+}
+
+static inline void
+wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev)
+{
+	struct net_info *_net_info, *next;
+
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+		if (ndev && (_net_info->ndev == ndev)) {
+			list_del(&_net_info->list);
+			wl->iface_cnt--;
+			if (_net_info->wdev) {
+				kfree(_net_info->wdev);
+				ndev->ieee80211_ptr = NULL;
+			}
+			kfree(_net_info);
+		}
+	}
+}
+
+static inline void
+wl_delete_all_netinfo(struct wl_priv *wl)
+{
+	struct net_info *_net_info, *next;
+
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+		list_del(&_net_info->list);
+			if (_net_info->wdev)
+				kfree(_net_info->wdev);
+			kfree(_net_info);
+	}
+	wl->iface_cnt = 0;
+}
+
+static inline bool
+wl_get_status_all(struct wl_priv *wl, s32 status)
+
+{
+	struct net_info *_net_info, *next;
+	u32 cnt = 0;
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+		if (_net_info->ndev &&
+			test_bit(status, &_net_info->sme_state))
+			cnt++;
+	}
+	return cnt? true: false;
+}
+
+static inline void
+wl_set_status_by_netdev(struct wl_priv *wl, s32 status,
+	struct net_device *ndev, u32 op)
+{
+
+	struct net_info *_net_info, *next;
+
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+		if (ndev && (_net_info->ndev == ndev)) {
+			switch (op) {
+				case 1:
+					set_bit(status, &_net_info->sme_state);
+					break;
+				case 2:
+					clear_bit(status, &_net_info->sme_state);
+					break;
+				case 4:
+					change_bit(status, &_net_info->sme_state);
+					break;
+			}
+		}
+
+	}
+}
+
+static inline u32
+wl_get_status_by_netdev(struct wl_priv *wl, s32 status,
+	struct net_device *ndev)
+{
+	struct net_info *_net_info, *next;
+
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+				if (ndev && (_net_info->ndev == ndev))
+					return test_bit(status, &_net_info->sme_state);
+	}
+	return 0;
+}
+
+static inline s32
+wl_get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev)
+{
+	struct net_info *_net_info, *next;
+
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+				if (ndev && (_net_info->ndev == ndev))
+					return _net_info->mode;
+	}
+	return -1;
+}
+
+static inline void
+wl_set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev,
+	s32 mode)
+{
+	struct net_info *_net_info, *next;
+
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+				if (ndev && (_net_info->ndev == ndev))
+					_net_info->mode = mode;
+	}
+}
+
+static inline struct wl_profile *
+wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev)
+{
+	struct net_info *_net_info, *next;
+
+	list_for_each_entry_safe(_net_info, next, &wl->net_list, list) {
+				if (ndev && (_net_info->ndev == ndev))
+					return &_net_info->profile;
+	}
+	return NULL;
+}
 #define wl_to_wiphy(w) (w->wdev->wiphy)
 #define wl_to_prmry_ndev(w) (w->wdev->netdev)
 #define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
@@ -435,112 +599,51 @@
 #define wl_to_iscan(w) (w->iscan)
 #define wl_to_conn(w) (&w->conn_info)
 #define wiphy_from_scan(w) (w->escan_info.wiphy)
-#define wl_get_drv_status(wl, stat)   (test_bit(WL_STATUS_ ## stat, &(wl)->status))
-#define wl_set_drv_status(wl, stat)   (set_bit(WL_STATUS_ ## stat, &(wl)->status))
-#define wl_clr_drv_status(wl, stat)   (clear_bit(WL_STATUS_ ## stat, &(wl)->status))
-#define wl_chg_drv_status(wl, stat)   (change_bit(WL_STATUS_ ## stat, &(wl)->status))
-
-static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
-{
-	return bss = bss ?
-		(struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
-}
-static inline s32 alloc_idx_vwdev(struct wl_priv *wl)
-{
-	s32 i = 0;
-	for (i = 0; i < VWDEV_CNT; i++) {
-		if (wl->vwdev[i] == NULL)
-				return i;
-	}
-	return -1;
-}
-
-static inline s32 get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device *ndev)
-{
-	s32 i = 0;
-	for (i = 0; i < VWDEV_CNT; i++) {
-		if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev))
-				return i;
-	}
-	return -1;
-}
-
-static inline s32 get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev)
-{
-	s32 i = 0;
-	for (i = 0; i <= VWDEV_CNT; i++) {
-		if (wl->conf->mode[i].ndev != NULL && (wl->conf->mode[i].ndev == ndev))
-			return wl->conf->mode[i].type;
-	}
-	return -1;
-}
-static inline void set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, s32 type)
-{
-	s32 i = 0;
-	for (i = 0; i <= VWDEV_CNT; i++) {
-		if (type == -1) {
-			/* free the info of netdev */
-			if (wl->conf->mode[i].ndev == ndev) {
-				wl->conf->mode[i].ndev = NULL;
-				wl->conf->mode[i].type = -1;
-				break;
-			}
-
-		} else {
-			if ((wl->conf->mode[i].ndev != NULL)&&
-			(wl->conf->mode[i].ndev == ndev)) {
-				/* update type of ndev */
-				wl->conf->mode[i].type = type;
-				break;
-			}
-			else if ((wl->conf->mode[i].ndev == NULL)&&
-			(wl->conf->mode[i].type == -1)) {
-				wl->conf->mode[i].ndev = ndev;
-				wl->conf->mode[i].type = type;
-				break;
-			}
-		}
-	}
-}
-#define free_vwdev_by_index(wl, __i) do {      \
-						if (wl->vwdev[__i] != NULL) \
-							kfree(wl->vwdev[__i]); \
-						wl->vwdev[__i] = NULL; \
-					} while (0)
+#define wl_get_drv_status_all(wl, stat) \
+	(wl_get_status_all(wl, WL_STATUS_ ## stat))
+#define wl_get_drv_status(wl, stat, ndev)  \
+	(wl_get_status_by_netdev(wl, WL_STATUS_ ## stat, ndev))
+#define wl_set_drv_status(wl, stat, ndev)  \
+	(wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1))
+#define wl_clr_drv_status(wl, stat, ndev)  \
+	(wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2))
+#define wl_chg_drv_status(wl, stat, ndev)  \
+	(wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4))
 
 #define for_each_bss(list, bss, __i)	\
 	for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
 
+#define for_each_ndev(wl, iter, next) \
+	list_for_each_entry_safe(iter, next, &wl->net_list, list)
+
+
 /* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0.
  * In addtion to that, wpa_version is WPA_VERSION_1
  */
 #define is_wps_conn(_sme) \
-	((_sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) && \
+	((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \
 	 (!_sme->crypto.n_ciphers_pairwise) && \
 	 (!_sme->crypto.cipher_group))
 extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data);
 extern s32 wl_cfg80211_attach_post(struct net_device *ndev);
-extern void wl_cfg80211_detach(void);
-/* event handler from dongle */
+extern void wl_cfg80211_detach(void *para);
+
 extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
             void *data);
-extern void wl_cfg80211_set_sdio_func(void *func);	/* set sdio function info */
-extern struct sdio_func *wl_cfg80211_get_sdio_func(void);	/* set sdio function info */
-extern s32 wl_cfg80211_up(void);	/* dongle up */
-extern s32 wl_cfg80211_down(void);	/* dongle down */
-extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
-int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
+void wl_cfg80211_set_parent_dev(void *dev);
+struct device *wl_cfg80211_get_parent_dev(void);
+
+extern s32 wl_cfg80211_up(void *para);
+extern s32 wl_cfg80211_down(void *para);
+extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
+	void* _net_attach);
+extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
 extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev);
 extern s32 wl_cfg80211_is_progress_ifadd(void);
 extern s32 wl_cfg80211_is_progress_ifchange(void);
 extern s32 wl_cfg80211_is_progress_ifadd(void);
 extern s32 wl_cfg80211_notify_ifchange(void);
 extern void wl_cfg80211_dbg_level(u32 level);
-extern void *wl_cfg80211_request_fw(s8 *file_name);
-extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size);
-extern void wl_cfg80211_release_fw(void);
-extern s8 *wl_cfg80211_get_fwname(void);
-extern s8 *wl_cfg80211_get_nvramname(void);
 extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
 extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len);
 extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len);
@@ -548,11 +651,12 @@
 	enum wl_management_type type);
 extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
 extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
+extern s32 wl_mode_to_nl80211_iftype(s32 mode);
+int wl_cfg80211_do_driver_init(struct net_device *net);
+void wl_cfg80211_enable_trace(int level);
 
 /* do scan abort */
-extern s32
-wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev);
+extern s32 wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev);
 
-extern s32
-wl_cfg80211_if_is_group_owner(void);
+extern s32 wl_cfg80211_if_is_group_owner(void);
 #endif				/* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index 4ee6557..880123e 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -30,6 +30,7 @@
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -39,26 +40,197 @@
 #include <bcmutils.h>
 #include <bcmendian.h>
 #include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
-#include <dhdioctl.h>
-#include <wlioctl.h>
 
 #include <wl_cfg80211.h>
 #include <wl_cfgp2p.h>
 #include <wldev_common.h>
+#include <wl_android.h>
 
-
-static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
 static s8 scanparambuf[WLC_IOCTL_SMLEN];
-static s8 *smbuf = ioctlbuf;
 
 static bool
 wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
 
 static s32
-wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
             s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete);
+
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
+static int wl_cfgp2p_if_open(struct net_device *net);
+static int wl_cfgp2p_if_stop(struct net_device *net);
+
+static const struct net_device_ops wl_cfgp2p_if_ops = {
+	.ndo_open		= wl_cfgp2p_if_open,
+	.ndo_stop		= wl_cfgp2p_if_stop,
+	.ndo_do_ioctl		= wl_cfgp2p_do_ioctl,
+	.ndo_start_xmit		= wl_cfgp2p_start_xmit,
+};
+
+bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len)
+{
+	wifi_p2p_pub_act_frame_t *pact_frm;
+
+	if (frame == NULL)
+		return false;
+	pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+	if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1)
+		return false;
+
+	if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
+		pact_frm->action == P2P_PUB_AF_ACTION &&
+		pact_frm->oui_type == P2P_VER &&
+		memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) {
+		return true;
+	}
+
+	return false;
+}
+
+bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
+{
+	wifi_p2p_action_frame_t *act_frm;
+
+	if (frame == NULL)
+		return false;
+	act_frm = (wifi_p2p_action_frame_t *)frame;
+	if (frame_len < sizeof(wifi_p2p_action_frame_t) -1)
+		return false;
+
+	if (act_frm->category == P2P_AF_CATEGORY &&
+		act_frm->type  == P2P_VER &&
+		memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) {
+		return true;
+	}
+
+	return false;
+}
+bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
+{
+
+	wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+
+	if (frame == NULL)
+		return false;
+
+	sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+	if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)
+		return false;
+	if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+		return false;
+
+	if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+		sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
+		sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
+		sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+		return true;
+	else
+		return false;
+
+}
+void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+	wifi_p2p_pub_act_frame_t *pact_frm;
+	wifi_p2p_action_frame_t *act_frm;
+	wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+	if (!frame || frame_len <= 2)
+		return;
+
+	if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
+		pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+		switch (pact_frm->subtype) {
+			case P2P_PAF_GON_REQ:
+				CFGP2P_DBG(("%s P2P Group Owner Negotiation Req Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_GON_RSP:
+				CFGP2P_DBG(("%s P2P Group Owner Negotiation Rsp Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_GON_CONF:
+				CFGP2P_DBG(("%s P2P Group Owner Negotiation Confirm Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_INVITE_REQ:
+				CFGP2P_DBG(("%s P2P Invitation Request  Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_INVITE_RSP:
+				CFGP2P_DBG(("%s P2P Invitation Response Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_DEVDIS_REQ:
+				CFGP2P_DBG(("%s P2P Device Discoverability Request Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_DEVDIS_RSP:
+				CFGP2P_DBG(("%s P2P Device Discoverability Response Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_PROVDIS_REQ:
+				CFGP2P_DBG(("%s P2P Provision Discovery Request Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_PAF_PROVDIS_RSP:
+				CFGP2P_DBG(("%s P2P Provision Discovery Response Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			default:
+				CFGP2P_DBG(("%s Unknown P2P Public Action Frame\n",
+					(tx)? "TX": "RX"));
+
+		}
+
+	} else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) {
+		act_frm = (wifi_p2p_action_frame_t *)frame;
+		switch (act_frm->subtype) {
+			case P2P_AF_NOTICE_OF_ABSENCE:
+				CFGP2P_DBG(("%s P2P Notice of Absence Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_AF_PRESENCE_REQ:
+				CFGP2P_DBG(("%s P2P Presence Request Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_AF_PRESENCE_RSP:
+				CFGP2P_DBG(("%s P2P Presence Response Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			case P2P_AF_GO_DISC_REQ:
+				CFGP2P_DBG(("%s P2P Discoverability Request Frame\n",
+					(tx)? "TX": "RX"));
+				break;
+			default:
+				CFGP2P_DBG(("%s Unknown P2P Action Frame\n",
+					(tx)? "TX": "RX"));
+		}
+
+	} else if (wl_cfgp2p_is_gas_action(frame, frame_len)) {
+		sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+		switch (sd_act_frm->action) {
+			case P2PSD_ACTION_ID_GAS_IREQ:
+				CFGP2P_DBG(("%s P2P GAS Initial Request\n",
+					(tx)? "TX" : "RX"));
+				break;
+			case P2PSD_ACTION_ID_GAS_IRESP:
+				CFGP2P_DBG(("%s P2P GAS Initial Response\n",
+					(tx)? "TX" : "RX"));
+				break;
+			case P2PSD_ACTION_ID_GAS_CREQ:
+				CFGP2P_DBG(("%s P2P GAS Comback Request\n",
+					(tx)? "TX" : "RX"));
+				break;
+			case P2PSD_ACTION_ID_GAS_CRESP:
+				CFGP2P_DBG(("%s P2P GAS Comback Response\n",
+					(tx)? "TX" : "RX"));
+				break;
+			default:
+				CFGP2P_DBG(("%s Unknown P2P GAS Frame\n",
+					(tx)? "TX" : "RX"));
+		}
+	}
+}
+
 /*
  *  Initialize variables related to P2P
  *
@@ -110,6 +282,8 @@
 void
 wl_cfgp2p_deinit_priv(struct wl_priv *wl)
 {
+	CFGP2P_DBG(("In\n"));
+
 	if (wl->p2p) {
 		kfree(wl->p2p);
 		wl->p2p = NULL;
@@ -142,7 +316,7 @@
 	 * firmware for P2P device address
 	 */
 	ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
-	            sizeof(null_eth_addr), ioctlbuf, sizeof(ioctlbuf), 0);
+		sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
 	if (ret && ret != BCME_UNSUPPORTED) {
 		CFGP2P_ERR(("failed to update device address\n"));
 	}
@@ -168,14 +342,14 @@
 	ifreq.chspec = chspec;
 	memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
 
-	CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
+	CFGP2P_DBG(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
 	    ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
 		ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
 		(if_type == WL_P2P_IF_GO) ? "go" : "client",
 	        (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
 
 	err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
-		ioctlbuf, sizeof(ioctlbuf));
+		wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 	return err;
 }
 
@@ -194,7 +368,7 @@
 	    netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2],
 	    mac->octet[3], mac->octet[4], mac->octet[5]));
 	ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
-		ioctlbuf, sizeof(ioctlbuf));
+		wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 	if (unlikely(ret < 0)) {
 		printk("'wl p2p_ifdel' error %d\n", ret);
 	}
@@ -225,7 +399,7 @@
 		(chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
 
 	err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
-		ioctlbuf, sizeof(ioctlbuf));
+		wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 
 	if (unlikely(err < 0)) {
 		printk("'wl p2p_ifupd' error %d\n", err);
@@ -251,8 +425,8 @@
 	    mac->octet[0], mac->octet[1], mac->octet[2],
 	    mac->octet[3], mac->octet[4], mac->octet[5]));
 
-	ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac),
-	            getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY));
+	ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf,
+		sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL);
 
 	if (ret == 0) {
 		memcpy(index, getbuf, sizeof(index));
@@ -262,7 +436,7 @@
 	return ret;
 }
 
-s32
+static s32
 wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on)
 {
 	s32 ret = BCME_OK;
@@ -311,13 +485,14 @@
 	discovery_mode.chspec = CH20MHZ_CHSPEC(channel);
 	discovery_mode.dwell = listen_ms;
 	ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
-	            sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx);
+		sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+		bssidx, &wl->ioctl_buf_sync);
 
 	return ret;
 }
 
 /* Get the index of the P2P Discovery BSS */
-s32
+static s32
 wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index)
 {
 	s32 ret;
@@ -381,7 +556,7 @@
  * @wl        : wl_private data
  * Returns 0 if succes
  */
-s32
+static s32
 wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
 {
 	s32 ret = BCME_OK;
@@ -419,7 +594,8 @@
  * Returns 0 if success.
  */
 s32
-wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len)
+wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev,
+	const u8 *ie, u32 ie_len)
 {
 	s32 ret = BCME_OK;
 	if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
@@ -511,9 +687,9 @@
 	wl_escan_params_t *eparams;
 	wlc_ssid_t ssid;
 	/* Scan parameters */
-#define P2PAPI_SCAN_NPROBES 4
-#define P2PAPI_SCAN_DWELL_TIME_MS 80
-#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 100
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 50
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
 #define P2PAPI_SCAN_HOME_TIME_MS 10
 	struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
 	wl_set_p2p_status(wl, SCANNING);
@@ -530,7 +706,7 @@
 		return -1;
 	}
 	memset(memblk, 0, memsize);
-	memset(ioctlbuf, 0, sizeof(ioctlbuf));
+	memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN);
 	if (search_state == WL_P2P_DISC_ST_SEARCH) {
 		/*
 		 * If we in SEARCH STATE, we don't need to set SSID explictly
@@ -569,7 +745,7 @@
 
 	eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES);
 	eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
-	if (wl_get_drv_status(wl, CONNECTED))
+	if (wl_get_drv_status_all(wl, CONNECTED))
 		eparams->params.active_time = htod32(-1);
 	else if (num_chans == 3)
 		eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
@@ -595,9 +771,54 @@
 	CFGP2P_INFO(("\n"));
 
 	ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
-	            memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx);
+		memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 	return ret;
 }
+
+/* search function to reach at common channel to send action frame
+ * Parameters:
+ * @wl       : wl_private data
+ * @ndev     : net device for bssidx
+ * @bssidx   : bssidx for BSS
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
+	s32 bssidx, s32 channel)
+{
+	s32 ret = 0;
+	u32 chan_cnt = 0;
+	u16 *default_chan_list = NULL;
+	if (!p2p_is_on(wl))
+		return -BCME_ERROR;
+	CFGP2P_ERR((" Enter\n"));
+	if (bssidx == P2PAPI_BSSCFG_PRIMARY)
+		bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
+	if (channel)
+		chan_cnt = 1;
+	else
+		chan_cnt = SOCIAL_CHAN_CNT;
+	default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL);
+	if (default_chan_list == NULL) {
+		CFGP2P_ERR(("channel list allocation failed \n"));
+		ret = -ENOMEM;
+		goto exit;
+	}
+	if (channel) {
+		default_chan_list[0] = channel;
+	} else {
+		default_chan_list[0] = SOCIAL_CHAN_1;
+		default_chan_list[1] = SOCIAL_CHAN_2;
+		default_chan_list[2] = SOCIAL_CHAN_3;
+	}
+	ret = wl_cfgp2p_escan(wl, ndev, true, SOCIAL_CHAN_CNT,
+		default_chan_list, WL_P2P_DISC_ST_SEARCH,
+		WL_SCAN_ACTION_START, bssidx);
+	kfree(default_chan_list);
+exit:
+	return ret;
+}
+
 /* Check whether pointed-to IE looks like WPA. */
 #define wl_cfgp2p_is_wpa_ie(ie, tlvs, len)	wl_cfgp2p_has_ie(ie, tlvs, len, \
 		(const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
@@ -635,7 +856,7 @@
 	u8 delete = 0;
 #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
 #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
-	if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
+	if (p2p_is_on(wl) && bssidx != -1) {
 		if (bssidx == P2PAPI_BSSCFG_PRIMARY)
 			bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
 		switch (pktflag) {
@@ -670,7 +891,7 @@
 				CFGP2P_ERR(("not suitable type\n"));
 				return -1;
 		}
-	} else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
+	} else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
 		switch (pktflag) {
 			case VNDR_IE_PRBRSP_FLAG :
 				mgmt_ie_buf = wl->ap_info->probe_res_ie;
@@ -689,7 +910,7 @@
 				return -1;
 		}
 		bssidx = 0;
-	} else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
+	} else if (bssidx == -1 && wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
 		switch (pktflag) {
 			case VNDR_IE_PRBREQ_FLAG :
 				mgmt_ie_buf = wl->sta_info->probe_req_ie;
@@ -735,8 +956,9 @@
 					CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
 						"%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
 						ie_buf[pos+1], ie_buf[pos+2]));
-					ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
-					    VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
+					ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
+						ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
+						ie_len-3, delete);
 				}
 				pos += ie_len;
 			}
@@ -760,8 +982,9 @@
 					CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :"
 						"%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
 						ie_buf[pos+1], ie_buf[pos+2]));
-					ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
-					    VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
+					ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
+						ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
+						ie_len-3, delete);
 				}
 				pos += ie_len;
 			}
@@ -867,7 +1090,7 @@
 }
 
 static s32
-wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
             s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete)
 {
 	s32 err = BCME_OK;
@@ -909,7 +1132,7 @@
 	memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3);
 	memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len);
 	err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len,
-		ioctlbuf, sizeof(ioctlbuf), bssidx);
+		wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 
 	CFGP2P_INFO(("vndr_ie iovar returns %d\n", err));
 	kfree(ie_setbuf);
@@ -964,7 +1187,7 @@
 			del_timer_sync(&wl->p2p->listen_timer);
 			spin_unlock_bh(&wl->p2p->timer_lock);
 		}
-		cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan,
+		cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan,
 		    wl->remain_on_chan_type, GFP_KERNEL);
 	} else
 		wl_clr_p2p_status(wl, LISTEN_EXPIRED);
@@ -1093,10 +1316,10 @@
 			wl_set_p2p_status(wl, ACTION_TX_NOACK);
 			CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
 		}
-		wake_up_interruptible(&wl->dongle_event_wait);
 	} else {
 		CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
 					"status : %d\n", status));
+		wake_up_interruptible(&wl->netif_change_event);
 	}
 	return ret;
 }
@@ -1126,15 +1349,15 @@
 	if (bssidx == P2PAPI_BSSCFG_PRIMARY)
 		bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
 
-	ret = wldev_iovar_setbuf_bsscfg(dev, "actframe",
-	           af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx);
+	ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params),
+		wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 
 	if (ret < 0) {
 
 		CFGP2P_ERR((" sending action frame is failed\n"));
 		goto exit;
 	}
-	timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+	timeout = wait_event_interruptible_timeout(wl->netif_change_event,
 	(wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
 	msecs_to_jiffies(MAX_WAIT_TIME));
 
@@ -1243,7 +1466,7 @@
 	/* Check if the BSS is up */
 	*(int*)getbuf = -1;
 	result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
-	                    sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0);
+		sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
 	if (result != 0) {
 		CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result));
 		CFGP2P_ERR(("NOTE: this ioctl error is normal "
@@ -1260,7 +1483,7 @@
 
 /* Bring up or down a BSS */
 s32
-wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up)
 {
 	s32 ret = BCME_OK;
 	s32 val = up ? 1 : 0;
@@ -1274,7 +1497,7 @@
 	bss_setbuf.val = htod32(val);
 	CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
 	ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
-		ioctlbuf, sizeof(ioctlbuf));
+		wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 
 	if (ret != 0) {
 		CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
@@ -1314,7 +1537,8 @@
 	return 0;
 }
 
-s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
+s32
+wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
 {
 	s32 ret = -1;
 	int count, start, duration;
@@ -1330,7 +1554,7 @@
 
 		sscanf(buf, "%d %d %d", &count, &start, &duration);
 		CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
-				count, start, duration));
+			count, start, duration));
 		if (count != -1)
 			wl->p2p->noa.desc[0].count = count;
 
@@ -1374,7 +1598,8 @@
 		dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000);
 
 		ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
-			"p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf));
+			"p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+			&wl->ioctl_buf_sync);
 
 		if (ret < 0) {
 			CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
@@ -1386,7 +1611,8 @@
 	return ret;
 }
 
-s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
+s32
+wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
 {
 	wifi_p2p_noa_desc_t *noa_desc;
 	int len = 0, i;
@@ -1428,7 +1654,8 @@
 	return len * 2;
 }
 
-s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
+s32
+wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
 {
 	int ps, ctw;
 	int ret = -1;
@@ -1446,7 +1673,7 @@
 			wl->p2p->ops.ops = ps;
 			ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
 				"p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops),
-				ioctlbuf, sizeof(ioctlbuf));
+				wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 			if (ret < 0) {
 				CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
 			}
@@ -1467,3 +1694,257 @@
 	}
 	return ret;
 }
+
+u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id)
+{
+	wifi_p2p_ie_t *ie = NULL;
+	u16 len = 0;
+	u8 *subel;
+	u8 subelt_id;
+	u16 subelt_len;
+
+	if (!buf) {
+		WL_ERR(("P2P IE not present"));
+		return 0;
+	}
+
+	ie = (wifi_p2p_ie_t*) buf;
+	len = ie->len;
+
+	/* Point subel to the P2P IE's subelt field.
+	 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
+	 */
+	subel = ie->subelts;
+	len -= 4;	/* exclude OUI + OUI_TYPE */
+
+	while (len >= 3) {
+		/* attribute id */
+		subelt_id = *subel;
+		subel += 1;
+		len -= 1;
+
+		/* 2-byte little endian */
+		subelt_len = *subel++;
+		subelt_len |= *subel++ << 8;
+
+		len -= 2;
+		len -= subelt_len;	/* for the remaining subelt fields */
+
+		if (subelt_id == element_id) {
+			/* This will point to start of subelement attrib after
+			 * attribute id & len
+			 */
+			return subel;
+		}
+
+		/* Go to next subelement */
+		subel += subelt_len;
+	}
+
+	/* Not Found */
+	return NULL;
+}
+
+#define P2P_GROUP_CAPAB_GO_BIT	0x01
+u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length)
+{
+	wifi_p2p_ie_t * p2p_ie = NULL;
+	u8 *capability = NULL;
+	bool p2p_go	= 0;
+	u8 *ptr = NULL;
+
+	if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) {
+		WL_ERR(("P2P IE not found"));
+		return NULL;
+	}
+
+	if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) {
+		WL_ERR(("P2P Capability attribute not found"));
+		return NULL;
+	}
+
+	/* Check Group capability for Group Owner bit */
+	p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT;
+	if (!p2p_go) {
+		return bi->BSSID.octet;
+	}
+
+	/* In probe responses, DEVICE INFO attribute will be present */
+	if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) {
+		/* If DEVICE_INFO is not found, this might be a beacon frame.
+		 * check for DEVICE_ID in the beacon frame.
+		 */
+		ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID);
+	}
+
+	if (!ptr)
+		WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
+
+	return ptr;
+}
+
+s32
+wl_cfgp2p_register_ndev(struct wl_priv *wl)
+{
+	int ret = 0;
+	struct net_device* net = NULL;
+	struct wireless_dev *wdev;
+	uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
+
+	/* Allocate etherdev, including space for private structure */
+	if (!(net = alloc_etherdev(sizeof(wl)))) {
+		CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
+		goto fail;
+	}
+
+	strcpy(net->name, "p2p%d");
+	net->name[IFNAMSIZ - 1] = '\0';
+
+	/* Copy the reference to wl_priv */
+	memcpy((void *)netdev_priv(net), &wl, sizeof(wl));
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+	ASSERT(!net->open);
+	net->do_ioctl = wl_cfgp2p_do_ioctl;
+	net->hard_start_xmit = wl_cfgp2p_start_xmit;
+	net->open = wl_cfgp2p_if_open;
+	net->stop = wl_cfgp2p_if_stop;
+#else
+	ASSERT(!net->netdev_ops);
+	net->netdev_ops = &wl_cfgp2p_if_ops;
+#endif
+
+	/* Register with a dummy MAC addr */
+	memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+
+	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+	if (unlikely(!wdev)) {
+		WL_ERR(("Could not allocate wireless device\n"));
+		return -ENOMEM;
+	}
+
+	wdev->wiphy = wl->wdev->wiphy;
+
+	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+
+	net->ieee80211_ptr = wdev;
+
+	SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy));
+
+	/* Associate p2p0 network interface with new wdev */
+	wdev->netdev = net;
+
+	/* store p2p net ptr for further reference. Note that iflist won't have this
+	 * entry as there corresponding firmware interface is a "Hidden" interface.
+	 */
+	if (wl->p2p_net) {
+		CFGP2P_ERR(("p2p_net defined already.\n"));
+		return -EINVAL;
+	} else {
+		wl->p2p_wdev = wdev;
+		wl->p2p_net = net;
+	}
+
+	ret = register_netdev(net);
+	if (ret) {
+		CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
+		goto fail;
+	}
+
+	printk("%s: P2P Interface Registered\n", net->name);
+
+	return ret;
+fail:
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+	net->open = NULL;
+#else
+	net->netdev_ops = NULL;
+#endif
+
+	if (net) {
+		unregister_netdev(net);
+		free_netdev(net);
+	}
+
+	return -ENODEV;
+}
+
+s32
+wl_cfgp2p_unregister_ndev(struct wl_priv *wl)
+{
+
+	if (!wl || !wl->p2p_net) {
+		CFGP2P_ERR(("Invalid Ptr\n"));
+		return -EINVAL;
+	}
+
+	unregister_netdev(wl->p2p_net);
+	free_netdev(wl->p2p_net);
+
+	return 0;
+}
+
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	CFGP2P_DBG(("(%s) is not used for data operations. Droping the packet. \n", ndev->name));
+	return 0;
+}
+
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+	int ret = 0;
+	struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net);
+	struct net_device *ndev = wl_to_prmry_ndev(wl);
+
+	/* There is no ifidx corresponding to p2p0 in our firmware. So we should
+	 * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs.
+	 * For Android PRIV CMD handling map it to primary I/F
+	 */
+	if (cmd == SIOCDEVPRIVATE+1) {
+		ret = wl_android_priv_cmd(ndev, ifr, cmd);
+
+	} else {
+		CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n",
+		__FUNCTION__, cmd));
+		return -1;
+	}
+
+	return ret;
+}
+
+static int wl_cfgp2p_if_open(struct net_device *net)
+{
+	struct wireless_dev *wdev = net->ieee80211_ptr;
+
+	if (!wdev)
+		return -EINVAL;
+
+	/* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now,
+	 * do it here. This will make sure that in concurrent mode, supplicant
+	 * is not dependent on a particular order of interface initialization.
+	 * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N
+	 * -iwlan0.
+	 */
+	wl_cfg80211_do_driver_init(net);
+
+	wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)
+		| BIT(NL80211_IFTYPE_P2P_GO));
+
+	return 0;
+}
+
+static int wl_cfgp2p_if_stop(struct net_device *net)
+{
+	struct wireless_dev *wdev = net->ieee80211_ptr;
+
+	if (!wdev)
+		return -EINVAL;
+
+	wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
+					& (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
+					BIT(NL80211_IFTYPE_P2P_GO)));
+	return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index 5a69168..1e5b119 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -101,13 +101,13 @@
 #define wl_to_p2p_bss_saved_ie(w, type) 	((wl)->p2p->bss_idx[type].saved_ie)
 #define wl_to_p2p_bss_private(w, type) 	((wl)->p2p->bss_idx[type].private_data)
 #define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
-#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
+#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:test_bit(WLP2P_STATUS_ ## stat, \
 									&(wl)->p2p->status))
-#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : set_bit(WLP2P_STATUS_ ## stat, \
+#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:set_bit(WLP2P_STATUS_ ## stat, \
 									&(wl)->p2p->status))
-#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : clear_bit(WLP2P_STATUS_ ## stat, \
+#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:clear_bit(WLP2P_STATUS_ ## stat, \
 									&(wl)->p2p->status))
-#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : change_bit(WLP2P_STATUS_ ## stat, \
+#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:change_bit(WLP2P_STATUS_ ## stat, \
 									&(wl)->p2p->status))
 #define p2p_on(wl) ((wl)->p2p->on)
 #define p2p_scan(wl) ((wl)->p2p->scan)
@@ -140,7 +140,14 @@
 		}									\
 	} while (0)
 
-
+extern bool
+wl_cfgp2p_is_pub_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_gas_action(void *frame, u32 frame_len);
+extern void
+wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len);
 extern s32
 wl_cfgp2p_init_priv(struct wl_priv *wl);
 extern void
@@ -172,6 +179,10 @@
 	u16 *channels,
 	s32 search_state, u16 action, u32 bssidx);
 
+extern s32
+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
+	s32 bssidx, s32 channel);
+
 extern wpa_ie_fixed_t *
 wl_cfgp2p_find_wpaie(u8 *parse, u32 len);
 
@@ -217,7 +228,7 @@
 wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx);
 
 extern s32
-wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up);
+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up);
 
 
 extern s32
@@ -235,13 +246,36 @@
 extern s32
 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
 
+extern u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id);
+
+extern u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length);
+
+extern s32
+wl_cfgp2p_register_ndev(struct wl_priv *wl);
+
+extern s32
+wl_cfgp2p_unregister_ndev(struct wl_priv *wl);
+
 /* WiFi Direct */
 #define SOCIAL_CHAN_1 1
 #define SOCIAL_CHAN_2 6
 #define SOCIAL_CHAN_3 11
+#define SOCIAL_CHAN_CNT 3
 #define WL_P2P_WILDCARD_SSID "DIRECT-"
 #define WL_P2P_WILDCARD_SSID_LEN 7
 #define WL_P2P_INTERFACE_PREFIX "p2p"
 #define WL_P2P_TEMP_CHAN "11"
+
+
+#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \
+					((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \
+					(frame->action == P2PSD_ACTION_ID_GAS_CREQ)))
+#define IS_P2P_PUB_ACT_REQ(frame, len) (wl_cfgp2p_is_pub_action(frame, len) && \
+						((frame->subtype == P2P_PAF_GON_REQ) || \
+						(frame->subtype == P2P_PAF_INVITE_REQ) || \
+						(frame->subtype == P2P_PAF_PROVDIS_REQ)))
+#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3))
 #define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0)
 #endif				/* _wl_cfgp2p_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
index ba3cc6c..d09448a 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.c
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 Exp $
+ * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 $
  */
 
 #include <wlioctl.h>
@@ -1564,6 +1564,63 @@
 	net_os_wake_unlock(dev);
 	return res;
 }
+
+static int
+wl_iw_set_pno_setadd(
+	struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra
+)
+{
+	int ret = -1;
+	char *tmp_ptr;
+	int size, tmp_size;
+
+	net_os_wake_lock(dev);
+	WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
+		__FUNCTION__, info->cmd, info->flags,
+		wrqu->data.pointer, wrqu->data.length));
+
+	if (g_onoff == G_WLAN_SET_OFF) {
+		WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+		goto exit_proc;
+	}
+
+	if (wrqu->data.length <= strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t)) {
+		WL_ERROR(("%s argument=%d less than %d\n", __FUNCTION__,
+		          wrqu->data.length, (int)(strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t))));
+		goto exit_proc;
+	}
+
+	
+	bcopy(PNOSETUP_SET_CMD, extra, strlen(PNOSETUP_SET_CMD));
+
+	tmp_ptr = extra + strlen(PNOSETUP_SET_CMD);
+	size = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
+	tmp_size = size;
+	
+	while (*tmp_ptr && tmp_size > 0) {
+		if ((*tmp_ptr == 'S') && (size - tmp_size) >= sizeof(cmd_tlv_t)) {
+			*(tmp_ptr + 1) = ((*(tmp_ptr + 1) - '0') << 4) + (*(tmp_ptr + 2) - '0');
+			memmove(tmp_ptr + 2, tmp_ptr + 3, tmp_size - 3);
+			tmp_size -= 2 + *(tmp_ptr + 1);
+			tmp_ptr += 2 + *(tmp_ptr + 1);
+			size--;
+		} else {
+			tmp_ptr++;
+			tmp_size--;
+		}
+	}
+
+	wrqu->data.length = strlen(PNOSETUP_SET_CMD) + size;
+	ret = wl_iw_set_pno_set(dev, info, wrqu, extra);
+
+exit_proc:
+	net_os_wake_unlock(dev);
+	return ret;
+
+}
 #endif 
 
 static int
@@ -1626,7 +1683,7 @@
 	strcpy(extra, flag);
 	wrqu.data.length = strlen(extra);
 	wireless_send_event(dev, cmd, &wrqu, extra);
-	net_os_wake_lock_timeout_enable(dev, DHD_EVENT_TIMEOUT);
+	net_os_wake_lock_timeout_enable(dev, DHD_EVENT_TIMEOUT_MS);
 	WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
 
 	return 0;
@@ -2567,6 +2624,8 @@
 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
 	IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
 	IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
+	IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE);
+	IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE);
 	IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
 #endif 
 
@@ -5473,7 +5532,15 @@
 	switch (paramid) {
 	case IW_AUTH_WPA_VERSION:
 		
-		iw->wpaversion = paramval;
+		if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
+			val = WPA_AUTH_DISABLED;
+		else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
+			val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
+		else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
+			val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
+		WL_ERROR(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
+		if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
+			return error;
 		break;
 
 	case IW_AUTH_CIPHER_PAIRWISE:
@@ -5491,7 +5558,27 @@
 		break;
 
 	case IW_AUTH_KEY_MGMT:
-		if (paramval & IW_AUTH_KEY_MGMT_PSK) {
+		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
+			return error;
+
+		if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
+			if (paramval & IW_AUTH_KEY_MGMT_PSK)
+				val = WPA_AUTH_PSK;
+			else
+				val = WPA_AUTH_UNSPECIFIED;
+			if (paramval & 0x04)
+				val |= WPA2_AUTH_FT;
+		}
+		else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+			if (paramval & IW_AUTH_KEY_MGMT_PSK)
+				val = WPA2_AUTH_PSK;
+			else
+				val = WPA2_AUTH_UNSPECIFIED;
+			if (paramval & 0x04)
+				val |= WPA2_AUTH_FT;
+		}
+
+		else if (paramval & IW_AUTH_KEY_MGMT_PSK) {
 			if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
 				val = WPA_AUTH_PSK;
 			else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
@@ -7526,6 +7613,8 @@
 			ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
 		else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
 			ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
+		else if (strnicmp(extra, PNOSETADD_SET_CMD, strlen(PNOSETADD_SET_CMD)) == 0)
+			ret = wl_iw_set_pno_setadd(dev, info, (union iwreq_data *)dwrq, extra);
 		else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
 			ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
 #endif 
@@ -8251,6 +8340,21 @@
 
 		break;
 	}
+
+	case WLC_E_ASSOC_REQ_IE:
+		cmd = IWEVASSOCREQIE;
+		wrqu.data.length = datalen;
+		if (datalen < sizeof(extra))
+			memcpy(extra, data, datalen);
+		break;
+
+	case WLC_E_ASSOC_RESP_IE:
+		cmd = IWEVASSOCRESPIE;
+		wrqu.data.length = datalen;
+		if (datalen < sizeof(extra))
+			memcpy(extra, data, datalen);
+		break;
+
 	case WLC_E_PMKID_CACHE: {
 		if (data)
 		{
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h
index c0cc14b..faca5f7 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.h
+++ b/drivers/net/wireless/bcmdhd/wl_iw.h
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 Exp $
+ * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 $
  */
 
 
@@ -51,9 +51,10 @@
 #define PNOSSIDCLR_SET_CMD			"PNOSSIDCLR"
 
 #define PNOSETUP_SET_CMD			"PNOSETUP " 
+#define PNOSETADD_SET_CMD			"PNOSETADD"
 #define PNOENABLE_SET_CMD			"PNOFORCE"
 #define PNODEBUG_SET_CMD			"PNODEBUG"
-#define TXPOWER_SET_CMD			"TXPOWER"
+#define TXPOWER_SET_CMD				"TXPOWER"
 
 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
@@ -226,6 +227,18 @@
 	iwe_stream_add_point(stream, ends, iwe, extra)
 #endif
 
+extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
+extern int dhd_pno_clean(dhd_pub_t *dhd);
+extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid,
+                       ushort  scan_fr, int pno_repeat, int pno_freq_expo_max);
+extern int dhd_pno_get_status(dhd_pub_t *dhd);
+extern int dhd_dev_pno_reset(struct net_device *dev);
+extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local,
+                           int nssid, ushort  scan_fr, int pno_repeat, int pno_freq_expo_max);
+extern int dhd_dev_pno_enable(struct net_device *dev,  int pfn_enabled);
+extern int dhd_dev_get_pno_status(struct net_device *dev);
+extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
+
 void	dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec);
 
 #define PNO_TLV_PREFIX			'S'
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c
similarity index 91%
rename from drivers/net/wireless/bcmdhd/dhd_linux_mon.c
rename to drivers/net/wireless/bcmdhd/wl_linux_mon.c
index dd9c71f..f44b4b0 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
+++ b/drivers/net/wireless/bcmdhd/wl_linux_mon.c
@@ -2,13 +2,13 @@
  * Broadcom Dongle Host Driver (DHD), Linux monitor network interface
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
- *
+ * 
  *         Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
  * under the terms of the GNU General Public License version 2 (the "GPL"),
  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  * following added to such license:
- *
+ * 
  *      As a special exception, the copyright holders of this software give you
  * permission to link this software with independent modules, and to copy and
  * distribute the resulting executable under terms of your choice, provided that
@@ -16,12 +16,12 @@
  * the license of that module.  An independent module is a module which is not
  * derived from this software.  The special exception does not apply to any
  * modifications of the software.
- *
+ * 
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_linux_mon.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $
+ * $Id: wl_linux_mon.c 303266 2011-12-16 00:15:23Z $
  */
 
 #include <linux/string.h>
@@ -96,16 +96,30 @@
 static struct net_device* lookup_real_netdev(char *name)
 {
 	int i;
+	int len = 0;
 	int last_name_len = 0;
 	struct net_device *ndev;
 	struct net_device *ndev_found = NULL;
 
-	/* We want to find interface "p2p-eth0-0" for monitor interface "mon.p2p-eth0-0", so
-	 * we skip "eth0" even if "mon.p2p-eth0-0" contains "eth0"
+	/* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0",
+	 * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon
+	 * iface would be mon-p2p0-0.
 	 */
 	for (i = 0; i < DHD_MAX_IFS; i++) {
 		ndev = dhd_idx2net(g_monitor.dhd_pub, i);
-		if (ndev && strstr(name, ndev->name)) {
+
+		/* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it
+		 * it matches, then this netdev is the corresponding real_netdev.
+		 */
+		if (ndev && strstr(ndev->name, "p2p-p2p0")) {
+			len = strlen("p2p");
+		} else {
+		/* if p2p- is not present, then the IFNAMSIZ have reached and name
+		 * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x
+		 */
+			len = 0;
+		}
+		if (ndev && strstr(name, (ndev->name + len))) {
 			if (strlen(ndev->name) > last_name_len) {
 				ndev_found = ndev;
 				last_name_len = strlen(ndev->name);
@@ -225,9 +239,10 @@
 	mon_if = ndev_to_monif(ndev);
 	if (mon_if == NULL || mon_if->real_ndev == NULL) {
 		MON_PRINT(" cannot find matched net dev, skip the packet\n");
+	} else {
+		MON_PRINT("enter, if name: %s, matched if name %s\n",
+		ndev->name, mon_if->real_ndev->name);
 	}
-
-	MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
 }
 
 static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
@@ -238,9 +253,10 @@
 	mon_if = ndev_to_monif(ndev);
 	if (mon_if == NULL || mon_if->real_ndev == NULL) {
 		MON_PRINT(" cannot find matched net dev, skip the packet\n");
+	} else {
+		MON_PRINT("enter, if name: %s, matched if name %s\n",
+		ndev->name, mon_if->real_ndev->name);
 	}
-
-	MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
 	return ret;
 }
 
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
index bb3eaea..d9a0b93 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.c
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -24,12 +24,13 @@
  * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
  */
 
-#include <linux/module.h>
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/netdevice.h>
 
 #include <wldev_common.h>
 #include <bcmutils.h>
-#include <dhd_dbg.h>
 
 #define htod32(i) i
 #define htod16(i) i
@@ -37,6 +38,13 @@
 #define dtoh16(i) i
 #define htodchanspec(i) i
 #define dtohchanspec(i) i
+
+#define	WLDEV_ERROR(args)						\
+	do {										\
+		printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__);	\
+		printk args;							\
+	} while (0)
+
 extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
 
 s32 wldev_ioctl(
@@ -71,26 +79,34 @@
 
 s32 wldev_iovar_getbuf(
 	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen)
+	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
 {
 	s32 ret = 0;
 	s32 iovar_len = 0;
-
+	if (buf_sync) {
+		mutex_lock(buf_sync);
+	}
 	iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
 	ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+	if (buf_sync)
+		mutex_unlock(buf_sync);
 	return ret;
 }
 
 
 s32 wldev_iovar_setbuf(
 	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen)
+	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
 {
 	s32 ret = 0;
 	s32 iovar_len;
-
+	if (buf_sync) {
+		mutex_lock(buf_sync);
+	}
 	iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
 	ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+	if (buf_sync)
+		mutex_unlock(buf_sync);
 	return ret;
 }
 
@@ -102,7 +118,7 @@
 	val = htod32(val);
 	memset(iovar_buf, 0, sizeof(iovar_buf));
 	return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
-		sizeof(iovar_buf));
+		sizeof(iovar_buf), NULL);
 }
 
 
@@ -114,7 +130,7 @@
 
 	memset(iovar_buf, 0, sizeof(iovar_buf));
 	err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
-		sizeof(iovar_buf));
+		sizeof(iovar_buf), NULL);
 	if (err == 0)
 	{
 		memcpy(pval, iovar_buf, sizeof(*pval));
@@ -148,7 +164,7 @@
 
 	if (buflen < 0 || iolen > (u32)buflen)
 	{
-		DHD_ERROR(("%s: buffer is too short\n", __FUNCTION__));
+		WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__));
 		return BCME_BUFTOOSHORT;
 	}
 
@@ -177,26 +193,37 @@
 
 s32 wldev_iovar_getbuf_bsscfg(
 	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
+	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
 {
 	s32 ret = 0;
 	s32 iovar_len = 0;
-
+	if (buf_sync) {
+		mutex_lock(buf_sync);
+	}
 	iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
 	ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+	if (buf_sync) {
+		mutex_unlock(buf_sync);
+	}
 	return ret;
 
 }
 
 s32 wldev_iovar_setbuf_bsscfg(
 	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
+	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
 {
 	s32 ret = 0;
 	s32 iovar_len;
-
+	if (buf_sync) {
+		mutex_lock(buf_sync);
+	}
 	iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
+
 	ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+	if (buf_sync) {
+		mutex_unlock(buf_sync);
+	}
 	return ret;
 }
 
@@ -208,7 +235,7 @@
 	val = htod32(val);
 	memset(iovar_buf, 0, sizeof(iovar_buf));
 	return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
-		sizeof(iovar_buf), bssidx);
+		sizeof(iovar_buf), bssidx, NULL);
 }
 
 
@@ -220,7 +247,7 @@
 
 	memset(iovar_buf, 0, sizeof(iovar_buf));
 	err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
-		sizeof(iovar_buf), bssidx);
+		sizeof(iovar_buf), bssidx, NULL);
 	if (err == 0)
 	{
 		memcpy(pval, iovar_buf, sizeof(*pval));
@@ -309,16 +336,16 @@
 		return error;
 
 	error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec),
-		smbuf, sizeof(smbuf));
+		smbuf, sizeof(smbuf), NULL);
 	if (error < 0)
-		DHD_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
+		WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
 
 	if ((error < 0) ||
 	    (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) {
 		bzero(&scbval, sizeof(scb_val_t));
 		error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1);
 		if (error < 0) {
-			DHD_ERROR(("%s: set country failed due to Disassoc error %d\n",
+			WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
 				__FUNCTION__, error));
 			return error;
 		}
@@ -328,14 +355,14 @@
 	memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
 	get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
 	error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
-		smbuf, sizeof(smbuf));
+		smbuf, sizeof(smbuf), NULL);
 	if (error < 0) {
-		DHD_ERROR(("%s: set country for %s as %s rev %d failed\n",
+		WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
 			__FUNCTION__, country_code, cspec.ccode, cspec.rev));
 		return error;
 	}
 	dhd_bus_country_set(dev, &cspec);
-	DHD_INFO(("%s: set country for %s as %s rev %d\n",
+	WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
 		__FUNCTION__, country_code, cspec.ccode, cspec.rev));
 	return 0;
 }
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h
index 4632680..6a1ba15 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.h
+++ b/drivers/net/wireless/bcmdhd/wldev_common.h
@@ -21,33 +21,33 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
+ * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
  */
 #ifndef __WLDEV_COMMON_H__
 #define __WLDEV_COMMON_H__
 
 #include <wlioctl.h>
 
-/** wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or 
+/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or
  *  netdev_ops->ndo_do_ioctl in new kernels)
  *  @dev: the net_device handle
  */
 s32 wldev_ioctl(
 	struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set);
 
-/** Retrieve named IOVARs, this function calls wl_dev_ioctl with 
+/** Retrieve named IOVARs, this function calls wl_dev_ioctl with
  *  WLC_GET_VAR IOCTL code
  */
 s32 wldev_iovar_getbuf(
 	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen);
+	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
 
 /** Set named IOVARs, this function calls wl_dev_ioctl with
  *  WLC_SET_VAR IOCTL code
  */
 s32 wldev_iovar_setbuf(
 	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen);
+	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
 
 s32 wldev_iovar_setint(
 	struct net_device *dev, s8 *iovar, s32 val);
@@ -67,15 +67,15 @@
  *  WLC_GET_VAR IOCTL code
  */
 s32 wldev_iovar_getbuf_bsscfg(
-	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
+	struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+	void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
 
 /** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
  *  WLC_SET_VAR IOCTL code
  */
 s32 wldev_iovar_setbuf_bsscfg(
-	struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
+	struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+	void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
 
 s32 wldev_iovar_getint_bsscfg(
 	struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx);
@@ -94,7 +94,7 @@
 extern int net_os_set_suspend_disable(struct net_device *dev, int val);
 extern int net_os_set_suspend(struct net_device *dev, int val);
 extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid,
-					int max, int *bytes_left);
+	int max, int *bytes_left);
 
 /* Get the link speed from dongle, speed is in kpbs */
 int wldev_get_link_speed(struct net_device *dev, int *plink_speed);
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c
index 421d5c8..a935585 100644
--- a/drivers/net/wireless/iwlegacy/iwl3945-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c
@@ -2910,14 +2910,13 @@
 		IWL_WARN(priv, "Invalid scan band\n");
 		return -EIO;
 	}
-
 	/*
-	 * If active scaning is requested but a certain channel
-	 * is marked passive, we can do active scanning if we
-	 * detect transmissions.
+	 * If active scaning is requested but a certain channel is marked
+	 * passive, we can do active scanning if we detect transmissions. For
+	 * passive only scanning disable switching to active on any channel.
 	 */
 	scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-					IWL_GOOD_CRC_TH_DISABLED;
+					IWL_GOOD_CRC_TH_NEVER;
 
 	if (!priv->is_internal_short_scan) {
 		scan->tx_cmd.len = cpu_to_le16(
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index f803fb6..857cf61 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -2023,6 +2023,7 @@
 	case IEEE80211_SMPS_STATIC:
 	case IEEE80211_SMPS_DYNAMIC:
 		return IWL_NUM_IDLE_CHAINS_SINGLE;
+	case IEEE80211_SMPS_AUTOMATIC:
 	case IEEE80211_SMPS_OFF:
 		return active_cnt;
 	default:
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 09f679d..272bcdf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -411,6 +411,24 @@
 	return 0;
 }
 
+void iwlagn_config_ht40(struct ieee80211_conf *conf,
+	struct iwl_rxon_context *ctx)
+{
+	if (conf_is_ht40_minus(conf)) {
+		ctx->ht.extension_chan_offset =
+			IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+		ctx->ht.is_40mhz = true;
+	} else if (conf_is_ht40_plus(conf)) {
+		ctx->ht.extension_chan_offset =
+			IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+		ctx->ht.is_40mhz = true;
+	} else {
+		ctx->ht.extension_chan_offset =
+			IEEE80211_HT_PARAM_CHA_SEC_NONE;
+		ctx->ht.is_40mhz = false;
+	}
+}
+
 int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct iwl_priv *priv = hw->priv;
@@ -424,6 +442,9 @@
 
 	mutex_lock(&priv->mutex);
 
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		goto out;
+
 	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
 		IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
 		goto out;
@@ -470,19 +491,11 @@
 				ctx->ht.enabled = conf_is_ht(conf);
 
 			if (ctx->ht.enabled) {
-				if (conf_is_ht40_minus(conf)) {
-					ctx->ht.extension_chan_offset =
-						IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-					ctx->ht.is_40mhz = true;
-				} else if (conf_is_ht40_plus(conf)) {
-					ctx->ht.extension_chan_offset =
-						IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-					ctx->ht.is_40mhz = true;
-				} else {
-					ctx->ht.extension_chan_offset =
-						IEEE80211_HT_PARAM_CHA_SEC_NONE;
-					ctx->ht.is_40mhz = false;
-				}
+				/* if HT40 is used, it should not change
+				 * after associated except channel switch */
+				if (!ctx->ht.is_40mhz ||
+						!iwl_is_associated_ctx(ctx))
+					iwlagn_config_ht40(conf, ctx);
 			} else
 				ctx->ht.is_40mhz = false;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 4974cd7..67cd2e3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -385,7 +385,10 @@
 		tx_cmd->tid_tspec = qc[0] & 0xf;
 		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
 	} else {
-		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+		if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+		else
+			tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
 	}
 
 	priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags);
@@ -775,10 +778,7 @@
 	iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
 	iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
 
-	/* Set up entry for this TFD in Tx byte-count array */
-	if (info->flags & IEEE80211_TX_CTL_AMPDU)
-		iwlagn_txq_update_byte_cnt_tbl(priv, txq,
-					       le16_to_cpu(tx_cmd->len));
+	iwlagn_txq_update_byte_cnt_tbl(priv, txq, le16_to_cpu(tx_cmd->len));
 
 	pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
 				       firstlen, PCI_DMA_BIDIRECTIONAL);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 97de5d9..a03dbcc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -144,13 +144,8 @@
 		FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
 	IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name);
-	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-					priv->ucode_write_complete, 5 * HZ);
-	if (ret == -ERESTARTSYS) {
-		IWL_ERR(priv, "Could not load the %s uCode section due "
-			"to interrupt\n", name);
-		return ret;
-	}
+	ret = wait_event_timeout(priv->wait_command_queue,
+				 priv->ucode_write_complete, 5 * HZ);
 	if (!ret) {
 		IWL_ERR(priv, "Could not load the %s uCode section\n",
 			name);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index f24165d..67d4c2d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -797,7 +797,7 @@
 		handled |= CSR_INT_BIT_FH_TX;
 		/* Wake up uCode load routine, now that load is complete */
 		priv->ucode_write_complete = 1;
-		wake_up_interruptible(&priv->wait_command_queue);
+		wake_up(&priv->wait_command_queue);
 	}
 
 	if (inta & ~handled) {
@@ -2872,21 +2872,9 @@
 
 			/* Configure HT40 channels */
 			ctx->ht.enabled = conf_is_ht(conf);
-			if (ctx->ht.enabled) {
-				if (conf_is_ht40_minus(conf)) {
-					ctx->ht.extension_chan_offset =
-						IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-					ctx->ht.is_40mhz = true;
-				} else if (conf_is_ht40_plus(conf)) {
-					ctx->ht.extension_chan_offset =
-						IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-					ctx->ht.is_40mhz = true;
-				} else {
-					ctx->ht.extension_chan_offset =
-						IEEE80211_HT_PARAM_CHA_SEC_NONE;
-					ctx->ht.is_40mhz = false;
-				}
-			} else
+			if (ctx->ht.enabled)
+				iwlagn_config_ht40(conf, ctx);
+			else
 				ctx->ht.is_40mhz = false;
 
 			if ((le16_to_cpu(ctx->staging.channel) != ch))
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index d171684..5a0acab 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -152,6 +152,8 @@
 			     struct ieee80211_vif *vif,
 			     struct ieee80211_bss_conf *bss_conf,
 			     u32 changes);
+void iwlagn_config_ht40(struct ieee80211_conf *conf,
+			struct iwl_rxon_context *ctx);
 
 /* uCode */
 void iwlagn_rx_calib_result(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 45cc51c..5638407 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -899,7 +899,7 @@
 	 * commands by clearing the ready bit */
 	clear_bit(STATUS_READY, &priv->status);
 
-	wake_up_interruptible(&priv->wait_command_queue);
+	wake_up(&priv->wait_command_queue);
 
 	if (!ondemand) {
 		/*
@@ -950,7 +950,7 @@
 		 */
 		clear_bit(STATUS_READY, &priv->status);
 		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-		wake_up_interruptible(&priv->wait_command_queue);
+		wake_up(&priv->wait_command_queue);
 		IWL_ERR(priv, "RF is used by WiMAX\n");
 		return;
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 76f9966..fc11277 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -194,7 +194,7 @@
 		return ret;
 	}
 
-	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+	ret = wait_event_timeout(priv->wait_command_queue,
 			!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
 			HOST_COMPLETE_TIMEOUT);
 	if (!ret) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index b774517..865ac1a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -738,7 +738,7 @@
 		wiphy_rfkill_set_hw_state(priv->hw->wiphy,
 			test_bit(STATUS_RF_KILL_HW, &priv->status));
 	else
-		wake_up_interruptible(&priv->wait_command_queue);
+		wake_up(&priv->wait_command_queue);
 }
 
 static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index c368c50..93152c3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -821,7 +821,7 @@
 		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 		IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
 			       get_cmd_string(cmd->hdr.cmd));
-		wake_up_interruptible(&priv->wait_command_queue);
+		wake_up(&priv->wait_command_queue);
 	}
 
 	/* Mark as unmapped */
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 463352c..db39742 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -997,6 +997,7 @@
 		spin_unlock_irqrestore(&card->buffer_lock, flags);
 		break;
 	default:
+		kfree(packet);
 		netdev_err(priv->dev, "can't transfer buffer of type %d\n",
 			   type);
 		err = -EINVAL;
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
index 3955642..8cfc0fa 100644
--- a/drivers/net/wireless/libra/libra_sdioif.c
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -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
@@ -28,6 +28,39 @@
 
 static suspend_handler_t *libra_suspend_hldr;
 static resume_handler_t *libra_resume_hldr;
+static notify_card_removal_t *libra_notify_card_removal_hdlr;
+static shutdown_handler_t *libra_sdio_shutdown_hdlr;
+
+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
@@ -89,6 +122,8 @@
 		goto cfg_error;
 	}
 
+	libra_enable_sdio_irq_in_chip(func, 0);
+
 	sdio_release_host(func);
 
 	return 0;
@@ -364,6 +399,8 @@
 
 static void libra_sdio_remove(struct sdio_func *func)
 {
+	if (libra_notify_card_removal_hdlr)
+		libra_notify_card_removal_hdlr();
 	libra_sdio_func = NULL;
 
 	printk(KERN_INFO "%s : Module removed.\n", __func__);
@@ -416,6 +453,31 @@
 #define libra_sdio_resume 0
 #endif
 
+static void libra_sdio_shutdown(struct device *dev)
+{
+	if (libra_sdio_shutdown_hdlr) {
+		libra_sdio_shutdown_hdlr();
+		printk(KERN_INFO "%s : Notified shutdown event to Libra driver.\n",
+			 __func__);
+	}
+}
+
+int libra_sdio_register_shutdown_hdlr(
+		shutdown_handler_t *libra_shutdown_hdlr)
+{
+	libra_sdio_shutdown_hdlr = libra_shutdown_hdlr;
+	return 0;
+}
+EXPORT_SYMBOL(libra_sdio_register_shutdown_hdlr);
+
+int libra_sdio_notify_card_removal(
+		notify_card_removal_t *libra_sdio_notify_card_removal_hdlr)
+{
+	libra_notify_card_removal_hdlr = libra_sdio_notify_card_removal_hdlr;
+	return 0;
+}
+EXPORT_SYMBOL(libra_sdio_notify_card_removal);
+
 static struct sdio_device_id libra_sdioid[] = {
     {.class = 0, .vendor = LIBRA_MAN_ID,  .device = LIBRA_REV_1_0_CARD_ID},
     {.class = 0, .vendor = VOLANS_MAN_ID, .device = VOLANS_REV_2_0_CARD_ID},
@@ -428,11 +490,12 @@
 };
 
 static struct sdio_driver libra_sdiofn_driver = {
-    .name      = "libra_sdiofn",
-    .id_table  = libra_sdioid,
-    .probe     = libra_sdio_probe,
-    .remove    = libra_sdio_remove,
-    .drv.pm    = &libra_sdio_pm_ops,
+	.name      = "libra_sdiofn",
+	.id_table  = libra_sdioid,
+	.probe     = libra_sdio_probe,
+	.remove    = libra_sdio_remove,
+	.drv.pm    = &libra_sdio_pm_ops,
+	.drv.shutdown    = libra_sdio_shutdown,
 };
 
 static int __init libra_sdioif_init(void)
@@ -442,6 +505,8 @@
 	libra_mmc_host_index = -1;
 	libra_suspend_hldr = NULL;
 	libra_resume_hldr = NULL;
+	libra_notify_card_removal_hdlr = NULL;
+	libra_sdio_shutdown_hdlr = NULL;
 
 	sdio_register_driver(&libra_sdiofn_driver);
 
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/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 6d9204fe..b33ceb1 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -589,8 +589,6 @@
 
 	WARN_ON(priv->fw_state != FW_STATE_READY);
 
-	cancel_work_sync(&priv->work);
-
 	p54spi_power_off(priv);
 	spin_lock_irqsave(&priv->tx_lock, flags);
 	INIT_LIST_HEAD(&priv->tx_pending);
@@ -598,6 +596,8 @@
 
 	priv->fw_state = FW_STATE_OFF;
 	mutex_unlock(&priv->mutex);
+
+	cancel_work_sync(&priv->work);
 }
 
 static int __devinit p54spi_probe(struct spi_device *spi)
@@ -657,6 +657,7 @@
 	init_completion(&priv->fw_comp);
 	INIT_LIST_HEAD(&priv->tx_pending);
 	mutex_init(&priv->mutex);
+	spin_lock_init(&priv->tx_lock);
 	SET_IEEE80211_DEV(hw, &spi->dev);
 	priv->common.open = p54spi_op_start;
 	priv->common.stop = p54spi_op_stop;
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 3f7ea1c..e6e174c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3514,7 +3514,7 @@
 	/* Apparently the data is read from end to start */
 	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, &reg);
 	/* The returned value is in CPU order, but eeprom is le */
-	rt2x00dev->eeprom[i] = cpu_to_le32(reg);
+	*(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);
 	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, &reg);
 	*(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
 	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, &reg);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 55cd3e1..dab7dc1 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -426,7 +426,6 @@
 static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 				 enum dev_state state)
 {
-	int mask = (state == STATE_RADIO_IRQ_ON);
 	u32 reg;
 	unsigned long flags;
 
@@ -448,25 +447,14 @@
 	}
 
 	spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
-	rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, mask);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_AC0_DMA_DONE, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_AC1_DMA_DONE, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_AC2_DMA_DONE, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_AC3_DMA_DONE, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_HCCA_DMA_DONE, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_MGMT_DMA_DONE, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_MCU_COMMAND, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_RXTX_COHERENT, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, mask);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, mask);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, mask);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, mask);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0);
+	reg = 0;
+	if (state == STATE_RADIO_IRQ_ON) {
+		rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, 1);
+		rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, 1);
+		rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, 1);
+		rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
+		rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, 1);
+	}
 	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
 	spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
 
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 6e7fe94..d4e9eac 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -878,6 +878,7 @@
 	{ USB_DEVICE(0x13b1, 0x0031) },
 	{ USB_DEVICE(0x1737, 0x0070) },
 	{ USB_DEVICE(0x1737, 0x0071) },
+	{ USB_DEVICE(0x1737, 0x0077) },
 	/* Logitec */
 	{ USB_DEVICE(0x0789, 0x0162) },
 	{ USB_DEVICE(0x0789, 0x0163) },
@@ -1069,7 +1070,6 @@
 	{ USB_DEVICE(0x1740, 0x0605) },
 	{ USB_DEVICE(0x1740, 0x0615) },
 	/* Linksys */
-	{ USB_DEVICE(0x1737, 0x0077) },
 	{ USB_DEVICE(0x1737, 0x0078) },
 	/* Logitec */
 	{ USB_DEVICE(0x0789, 0x0168) },
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index c446db6..8c82211 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -922,6 +922,7 @@
 	 * Powersaving work
 	 */
 	struct delayed_work autowakeup_work;
+	struct work_struct sleep_work;
 
 	/*
 	 * Data queue arrays for RX, TX, Beacon and ATIM.
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 939821b..dffaa8f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -449,6 +449,23 @@
 	return NULL;
 }
 
+static void rt2x00lib_sleep(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, sleep_work);
+
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+		return;
+
+	/*
+	 * Check again is powersaving is enabled, to prevent races from delayed
+	 * work execution.
+	 */
+	if (!test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
+		rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf,
+				 IEEE80211_CONF_CHANGE_PS);
+}
+
 static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
 				      struct sk_buff *skb,
 				      struct rxdone_entry_desc *rxdesc)
@@ -496,8 +513,7 @@
 	cam |= (tim_ie->bitmap_ctrl & 0x01);
 
 	if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
-		rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf,
-				 IEEE80211_CONF_CHANGE_PS);
+		queue_work(rt2x00dev->workqueue, &rt2x00dev->sleep_work);
 }
 
 static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
@@ -1108,6 +1124,7 @@
 
 	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
 	INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
+	INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
 
 	/*
 	 * Let the driver probe the device to detect the capabilities.
@@ -1164,6 +1181,7 @@
 	 */
 	cancel_work_sync(&rt2x00dev->intf_work);
 	cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
+	cancel_work_sync(&rt2x00dev->sleep_work);
 	if (rt2x00_is_usb(rt2x00dev)) {
 		del_timer_sync(&rt2x00dev->txstatus_timer);
 		cancel_work_sync(&rt2x00dev->rxdone_work);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c
index 3b5af01..0c77a14 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c
@@ -196,6 +196,8 @@
 		/* Allocate skb buffer to contain firmware */
 		/* info and tx descriptor info. */
 		skb = dev_alloc_skb(frag_length);
+		if (!skb)
+			return false;
 		skb_reserve(skb, extra_descoffset);
 		seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length -
 					extra_descoffset));
@@ -575,6 +577,8 @@
 
 	len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
 	skb = dev_alloc_skb(len);
+	if (!skb)
+		return false;
 	cb_desc = (struct rtl_tcb_desc *)(skb->cb);
 	cb_desc->queue_index = TXCMD_QUEUE;
 	cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
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/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index b07f8b7..e0e1688 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -328,6 +328,9 @@
 		nvs_ptr += 3;
 
 		for (i = 0; i < burst_len; i++) {
+			if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len)
+				goto out_badnvs;
+
 			val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
 			       | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
 
@@ -339,6 +342,9 @@
 			nvs_ptr += 4;
 			dest_addr += 4;
 		}
+
+		if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
+			goto out_badnvs;
 	}
 
 	/*
@@ -350,6 +356,10 @@
 	 */
 	nvs_ptr = (u8 *)wl->nvs +
 			ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
+
+	if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
+		goto out_badnvs;
+
 	nvs_len -= nvs_ptr - (u8 *)wl->nvs;
 
 	/* Now we must set the partition correctly */
@@ -365,6 +375,10 @@
 
 	kfree(nvs_aligned);
 	return 0;
+
+out_badnvs:
+	wl1271_error("nvs data is malformed");
+	return -EILSEQ;
 }
 
 static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 42935ac..b8ec8cd 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -121,6 +121,11 @@
 	if (!wl->nvs)
 		return -ENODEV;
 
+	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
+		wl1271_warning("FEM index from INI out of bounds");
+		return -EINVAL;
+	}
+
 	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
 	if (!gen_parms)
 		return -ENOMEM;
@@ -144,6 +149,12 @@
 	gp->tx_bip_fem_manufacturer =
 		gen_parms->general_params.tx_bip_fem_manufacturer;
 
+	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
+		wl1271_warning("FEM index from FW out of bounds");
+		ret = -EINVAL;
+		goto out;
+	}
+
 	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
 		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
 
@@ -163,6 +174,11 @@
 	if (!wl->nvs)
 		return -ENODEV;
 
+	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
+		wl1271_warning("FEM index from ini out of bounds");
+		return -EINVAL;
+	}
+
 	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
 	if (!gen_parms)
 		return -ENOMEM;
@@ -187,6 +203,12 @@
 	gp->tx_bip_fem_manufacturer =
 		gen_parms->general_params.tx_bip_fem_manufacturer;
 
+	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
+		wl1271_warning("FEM index from FW out of bounds");
+		ret = -EINVAL;
+		goto out;
+	}
+
 	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
 		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
 
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 56f76ab..9542e46 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -83,14 +83,18 @@
 	for (i = 0, j = 0;
 	     i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
 	     i++) {
-
 		flags = req->channels[i]->flags;
 
 		if (!test_bit(i, wl->scan.scanned_ch) &&
 		    !(flags & IEEE80211_CHAN_DISABLED) &&
-		    ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
-		    (req->channels[i]->band == band)) {
-
+		    (req->channels[i]->band == band) &&
+		    /*
+		     * In passive scans, we scan all remaining
+		     * channels, even if not marked as such.
+		     * In active scans, we only scan channels not
+		     * marked as passive.
+		     */
+		    (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
 			wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
 				     req->channels[i]->band,
 				     req->channels[i]->center_freq);
@@ -142,6 +146,10 @@
 	int ret;
 	u16 scan_options = 0;
 
+	/* skip active scans if we don't have SSIDs */
+	if (!passive && wl->scan.req->n_ssids == 0)
+		return WL1271_NOTHING_TO_SCAN;
+
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
 	if (!cmd || !trigger) {
@@ -152,8 +160,7 @@
 	/* We always use high priority scans */
 	scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
 
-	/* No SSIDs means that we have a forced passive scan */
-	if (passive || wl->scan.req->n_ssids == 0)
+	if (passive)
 		scan_options |= WL1271_SCAN_OPT_PASSIVE;
 
 	cmd->params.scan_options = cpu_to_le16(scan_options);
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 0ca86f9..1825629 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -327,12 +327,12 @@
 	xenvif_get(vif);
 
 	rtnl_lock();
-	if (netif_running(vif->dev))
-		xenvif_up(vif);
 	if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
 		dev_set_mtu(vif->dev, ETH_DATA_LEN);
 	netdev_update_features(vif->dev);
 	netif_carrier_on(vif->dev);
+	if (netif_running(vif->dev))
+		xenvif_up(vif);
 	rtnl_unlock();
 
 	return 0;
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index a306357..b8cdc6b 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -81,4 +81,10 @@
 	help
 	  OpenFirmware SPMI bus accessors
 
+config OF_SLIMBUS
+	def_tristate SLIMBUS
+	depends on SLIMBUS
+	help
+	  OpenFirmware SLIMBUS accessors
+
 endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 2087c5e..bc2b481 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -11,3 +11,4 @@
 obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 obj-$(CONFIG_OF_PCI)	+= of_pci.o
 obj-$(CONFIG_OF_SPMI)	+= of_spmi.o
+obj-$(CONFIG_OF_SLIMBUS)	+= of_slimbus.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
index da1f4b9..e29a5cf 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -14,7 +14,7 @@
 static struct of_bus *of_match_bus(struct device_node *np);
 static int __of_address_to_resource(struct device_node *dev,
 		const __be32 *addrp, u64 size, unsigned int flags,
-				    struct resource *r);
+		const char *name, struct resource *r);
 
 /* Debug utility */
 #ifdef DEBUG
@@ -215,7 +215,7 @@
 	addrp = of_get_pci_address(dev, bar, &size, &flags);
 	if (addrp == NULL)
 		return -EINVAL;
-	return __of_address_to_resource(dev, addrp, size, flags, r);
+	return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
 }
 EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
 #endif /* CONFIG_PCI */
@@ -529,7 +529,7 @@
 
 static int __of_address_to_resource(struct device_node *dev,
 		const __be32 *addrp, u64 size, unsigned int flags,
-				    struct resource *r)
+		const char *name, struct resource *r)
 {
 	u64 taddr;
 
@@ -551,7 +551,8 @@
 		r->end = taddr + size - 1;
 	}
 	r->flags = flags;
-	r->name = dev->full_name;
+	r->name = name ? name : dev->full_name;
+
 	return 0;
 }
 
@@ -569,11 +570,16 @@
 	const __be32	*addrp;
 	u64		size;
 	unsigned int	flags;
+	const char	*name = NULL;
 
 	addrp = of_get_address(dev, index, &size, &flags);
 	if (addrp == NULL)
 		return -EINVAL;
-	return __of_address_to_resource(dev, addrp, size, flags, r);
+
+	/* Get optional "reg-names" property to add a name to a resource */
+	of_property_read_string_index(dev, "reg-names",	index, &name);
+
+	return __of_address_to_resource(dev, addrp, size, flags, name, r);
 }
 EXPORT_SYMBOL_GPL(of_address_to_resource);
 
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 02ed367..39bcf16 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -661,6 +661,90 @@
 EXPORT_SYMBOL_GPL(of_property_read_string);
 
 /**
+ * of_property_read_string_index - Find and read a string from a multiple
+ * strings property.
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ * @index:	index of the string in the list of strings
+ * @out_string:	pointer to null terminated return string, modified only if
+ *		return value is 0.
+ *
+ * Search for a property in a device tree node and retrieve a null
+ * terminated string value (pointer to data, not a copy) in the list of strings
+ * contained in that property.
+ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * property does not have a value, and -EILSEQ if the string is not
+ * null-terminated within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+int of_property_read_string_index(struct device_node *np, const char *propname,
+				  int index, const char **output)
+{
+	struct property *prop = of_find_property(np, propname, NULL);
+	int i = 0;
+	size_t l = 0, total = 0;
+	const char *p;
+
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+	if (strnlen(prop->value, prop->length) >= prop->length)
+		return -EILSEQ;
+
+	p = prop->value;
+
+	for (i = 0; total < prop->length; total += l, p += l) {
+		l = strlen(p) + 1;
+		if ((*p != 0) && (i++ == index)) {
+			*output = p;
+			return 0;
+		}
+	}
+	return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(of_property_read_string_index);
+
+
+/**
+ * of_property_count_strings - Find and return the number of strings from a
+ * multiple strings property.
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ *
+ * Search for a property in a device tree node and retrieve the number of null
+ * terminated string contain in it. Returns the number of strings on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ */
+int of_property_count_strings(struct device_node *np, const char *propname)
+{
+	struct property *prop = of_find_property(np, propname, NULL);
+	int i = 0;
+	size_t l = 0, total = 0;
+	const char *p;
+
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+	if (strnlen(prop->value, prop->length) >= prop->length)
+		return -EILSEQ;
+
+	p = prop->value;
+
+	for (i = 0; total < prop->length; total += l, p += l) {
+		l = strlen(p) + 1;
+		if (*p != 0)
+			i++;
+	}
+	return i;
+}
+EXPORT_SYMBOL_GPL(of_property_count_strings);
+
+/**
  * of_parse_phandle - Resolve a phandle property to a device_node pointer
  * @np: Pointer to device node holding phandle property
  * @phandle_name: Name of property holding a phandle value
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 19c0115..8a31313 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -346,9 +346,18 @@
 	/* Only dereference the resource if both the
 	 * resource and the irq are valid. */
 	if (r && irq != NO_IRQ) {
+		const char *name = NULL;
+
+		/*
+		 * Get optional "interrupts-names" property to add a name
+		 * to the resource.
+		 */
+		of_property_read_string_index(dev, "interrupt-names", index,
+					      &name);
+
 		r->start = r->end = irq;
 		r->flags = IORESOURCE_IRQ;
-		r->name = dev->full_name;
+		r->name = name ? name : dev->full_name;
 	}
 
 	return irq;
diff --git a/drivers/of/of_slimbus.c b/drivers/of/of_slimbus.c
new file mode 100644
index 0000000..512ca73
--- /dev/null
+++ b/drivers/of/of_slimbus.c
@@ -0,0 +1,83 @@
+/* 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.
+ */
+
+/* OF helpers for SLIMbus */
+#include <linux/slimbus/slimbus.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_slimbus.h>
+
+int of_register_slim_devices(struct slim_controller *ctrl)
+{
+	struct device_node *node;
+	struct slim_boardinfo *binfo = NULL;
+	int n = 0;
+	int ret = 0;
+
+	if (!ctrl->dev.of_node)
+		return -EINVAL;
+
+	for_each_child_of_node(ctrl->dev.of_node, node) {
+		struct property *prop;
+		struct slim_device *slim;
+		char *name;
+		prop = of_find_property(node, "elemental-addr", NULL);
+		if (!prop || prop->length != 6) {
+			dev_err(&ctrl->dev, "of_slim: invalid E-addr");
+			continue;
+		}
+		name = kzalloc(SLIMBUS_NAME_SIZE, GFP_KERNEL);
+		if (!name) {
+			dev_err(&ctrl->dev, "of_slim: out of memory");
+			ret = -ENOMEM;
+			goto of_slim_err;
+		}
+		if (of_modalias_node(node, name, SLIMBUS_NAME_SIZE) < 0) {
+			dev_err(&ctrl->dev, "of_slim: modalias failure on %s\n",
+				node->full_name);
+			kfree(name);
+			continue;
+		}
+		slim = kzalloc(sizeof(struct slim_device), GFP_KERNEL);
+		if (!slim) {
+			dev_err(&ctrl->dev, "of_slim: out of memory");
+			ret = -ENOMEM;
+			kfree(name);
+			goto of_slim_err;
+		}
+		memcpy(slim->e_addr, prop->value, 6);
+
+		binfo = krealloc(binfo, (n + 1) * sizeof(struct slim_boardinfo),
+					GFP_KERNEL);
+		if (!binfo) {
+			dev_err(&ctrl->dev, "out of memory");
+			kfree(name);
+			kfree(slim);
+			return -ENOMEM;
+		}
+		slim->name = (const char *)name;
+		binfo[n].bus_num = ctrl->nr;
+		binfo[n].slim_slave = slim;
+		n++;
+	}
+	return slim_register_board_info(binfo, n);
+of_slim_err:
+	n--;
+	while (n >= 0) {
+		kfree(binfo[n].slim_slave->name);
+		kfree(binfo[n].slim_slave);
+	}
+	kfree(binfo);
+	return ret;
+}
diff --git a/drivers/of/of_spmi.c b/drivers/of/of_spmi.c
index 9f2a396..61085c9 100644
--- a/drivers/of/of_spmi.c
+++ b/drivers/of/of_spmi.c
@@ -18,63 +18,167 @@
 #include <linux/of_spmi.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/types.h>
 
-/**
- * Allocate resources for a child of a spmi-container node.
+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;
+};
+
+/*
+ * Initialize r_info structure for safe usage
  */
-static int of_spmi_allocate_resources(struct spmi_controller *ctrl,
-				      struct spmi_boardinfo *info,
-				      struct device_node *node,
-				      uint32_t num_reg)
+static inline void of_spmi_init_resource(struct of_spmi_res_info *r_info,
+					 struct device_node *node)
 {
-	int i, num_irq = 0;
+	r_info->node = node;
+	r_info->num_reg = 0;
+	r_info->num_irq = 0;
+}
+
+/*
+ * Allocate dev_node array for spmi_device
+ */
+static inline int of_spmi_alloc_device_store(struct of_spmi_dev_info *d_info,
+					     uint32_t num_dev_node)
+{
+	d_info->b_info.num_dev_node = num_dev_node;
+	d_info->b_info.dev_node = kzalloc(sizeof(struct spmi_resource) *
+						num_dev_node, GFP_KERNEL);
+	if (!d_info->b_info.dev_node)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/*
+ * Calculate the number of resources to allocate
+ *
+ * The caller is responsible for initializing the of_spmi_res_info structure.
+ */
+static void of_spmi_sum_node_resources(struct of_spmi_res_info *r_info,
+				       bool has_reg)
+{
+	struct of_irq oirq;
 	uint64_t size;
 	uint32_t flags;
+	int i = 0;
+
+	while (of_irq_map_one(r_info->node, i, &oirq) == 0)
+		i++;
+
+	r_info->num_irq += i;
+
+	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.
+	 */
+	i = 0;
+	while (of_get_address(r_info->node, i, &size, &flags) != NULL)
+		i++;
+
+	r_info->num_reg += i;
+}
+
+/*
+ * free spmi_resource for the spmi_device
+ */
+static void of_spmi_free_device_resources(struct of_spmi_dev_info *d_info)
+{
+	int i;
+
+	for (i = 0; i < d_info->b_info.num_dev_node; i++)
+		kfree(d_info->b_info.dev_node[i].resource);
+
+	kfree(d_info->b_info.dev_node);
+}
+
+/*
+ * Gather node resources and populate
+ */
+static void of_spmi_populate_node_resources(struct of_spmi_dev_info *d_info,
+					    struct of_spmi_res_info *r_info,
+					    int idx)
+
+{
+	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;
+	uint64_t size;
+	uint32_t flags;
 
-	while (of_irq_map_one(node, num_irq, &oirq) == 0)
-		num_irq++;
+	res = d_info->b_info.dev_node[idx].resource;
+	d_info->b_info.dev_node[idx].of_node = r_info->node;
 
-	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;
+	if ((num_irq || num_reg) && (res != NULL)) {
 		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);
 	}
+}
+
+/*
+ * Allocate enough memory to handle the resources associated with the
+ * device_node. The number of device nodes included in this allocation
+ * depends on whether the spmi-dev-container flag is specified or not.
+ */
+static int of_spmi_allocate_node_resources(struct of_spmi_dev_info *d_info,
+					   struct of_spmi_res_info *r_info,
+					   uint32_t idx)
+{
+	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
+	struct resource *res = NULL;
+
+	if (num_irq || num_reg) {
+		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+		if (!res)
+			return -ENOMEM;
+	}
+	d_info->b_info.dev_node[idx].num_resources = num_reg + num_irq;
+	d_info->b_info.dev_node[idx].resource = res;
 
 	return 0;
 }
 
-static int of_spmi_create_device(struct spmi_controller *ctrl,
-				 struct spmi_boardinfo *info,
-			  struct device_node *node)
+/*
+ * create a single spmi_device
+ */
+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,70 +190,213 @@
 	return 0;
 }
 
-static void of_spmi_walk_container_children(struct spmi_controller *ctrl,
-				     struct spmi_boardinfo *info,
-				     struct device_node *container)
+/*
+ * Walks all children of a node containing the spmi-dev-container
+ * binding. This special type of spmi_device can include resources
+ * from more than one device node.
+ */
+static void of_spmi_walk_dev_container(struct of_spmi_dev_info *d_info,
+					struct device_node *container)
 {
+	struct of_spmi_res_info r_info = {};
+	struct spmi_controller *ctrl = d_info->ctrl;
 	struct device_node *node;
-	uint64_t size;
-	uint32_t flags, num_reg = 0;
+	int rc, i, num_dev_node = 0;
+
+	if (!of_device_is_available(container))
+		return;
+
+	/*
+	 * Count the total number of device_nodes so we know how much
+	 * device_store to allocate.
+	 */
+	for_each_child_of_node(container, node) {
+		if (!of_device_is_available(node))
+			continue;
+		num_dev_node++;
+	}
+
+	rc = of_spmi_alloc_device_store(d_info, num_dev_node);
+	if (rc) {
+		dev_err(&ctrl->dev, "%s: unable to allocate"
+				" device resources\n", __func__);
+		return;
+	}
+
+	i = 0;
+	for_each_child_of_node(container, node) {
+		if (!of_device_is_available(node))
+			continue;
+		of_spmi_init_resource(&r_info, node);
+		of_spmi_sum_node_resources(&r_info, 1);
+		rc = of_spmi_allocate_node_resources(d_info, &r_info, i);
+		if (rc) {
+			dev_err(&ctrl->dev, "%s: unable to allocate"
+					" resources\n", __func__);
+			of_spmi_free_device_resources(d_info);
+			return;
+		}
+		of_spmi_populate_node_resources(d_info, &r_info, i);
+		i++;
+	}
+
+	rc = of_spmi_create_device(d_info, container);
+	if (rc) {
+		dev_err(&ctrl->dev, "%s: unable to create device for"
+				" node %s\n", __func__, container->full_name);
+		of_spmi_free_device_resources(d_info);
+		return;
+	}
+}
+
+/*
+ * Walks all children of a node containing the spmi-slave-container
+ * binding. This indicates that all spmi_devices created from this
+ * point all share the same slave_id.
+ */
+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;
 	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);
+		if (!of_device_is_available(node))
+			continue;
+
+		/**
+		 * Check to see if this node contains children which
+		 * should be all created as the same spmi_device.
+		 */
+		if (of_get_property(node, "spmi-dev-container", NULL)) {
+			of_spmi_walk_dev_container(d_info, node);
+			continue;
+		}
+
+		rc = of_spmi_alloc_device_store(d_info, 1);
+		if (rc) {
+			dev_err(&ctrl->dev, "%s: unable to allocate"
+					" device resources\n", __func__);
+			goto slave_err;
+		}
+
+		of_spmi_init_resource(&r_info, node);
+		of_spmi_sum_node_resources(&r_info, 1);
+
+		rc = of_spmi_allocate_node_resources(d_info, &r_info, 0);
 		if (rc) {
 			dev_err(&ctrl->dev, "%s: unable to allocate"
 						" resources\n", __func__);
-			return;
+			goto slave_err;
 		}
-		rc = of_spmi_create_device(ctrl, info, node);
+
+		of_spmi_populate_node_resources(d_info, &r_info, 0);
+
+		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);
-			return;
+			goto slave_err;
 		}
 	}
+	return;
+
+slave_err:
+	of_spmi_free_device_resources(d_info);
 }
 
 int of_spmi_register_devices(struct spmi_controller *ctrl)
 {
-	struct device_node *node;
+	struct device_node *node = ctrl->dev.of_node;
 
 	/* Only register child devices if the ctrl has a node pointer set */
-	if (!ctrl->dev.of_node)
+	if (!node)
 		return -ENODEV;
 
+	if (of_get_property(node, "spmi-slave-container", NULL)) {
+		dev_err(&ctrl->dev, "%s: structural error: spmi-slave-container"
+			" is prohibited at the root level\n", __func__);
+		return -EINVAL;
+	} else if (of_get_property(node, "spmi-dev-container", NULL)) {
+		dev_err(&ctrl->dev, "%s: structural error: spmi-dev-container"
+			" is prohibited at the root level\n", __func__);
+		return -EINVAL;
+	}
+
+	/**
+	 * Make best effort to launch as many nodes as possible. If there are
+	 * syntax errors, we will simply ignore that subtree and keep going.
+	 */
 	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;
+		int len, rc, have_dev_container = 0;
 
 		slave_id = of_get_property(node, "reg", &len);
 		if (!slave_id) {
-			dev_err(&ctrl->dev, "of_spmi: invalid sid "
-					"on %s\n", node->full_name);
+			dev_err(&ctrl->dev, "%s: invalid sid "
+					"on %s\n", __func__, node->full_name);
 			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);
-			continue;
+		if (of_get_property(node, "spmi-dev-container", NULL))
+			have_dev_container = 1;
+		if (of_get_property(node, "spmi-slave-container", NULL)) {
+			if (have_dev_container)
+				of_spmi_walk_dev_container(&d_info, node);
+			else
+				of_spmi_walk_slave_container(&d_info, node);
 		} else {
-			rc = of_spmi_allocate_resources(ctrl, &info, node, 0);
-			if (rc)
+			struct of_spmi_res_info r_info;
+
+			/**
+			 * A dev container at the second level without a slave
+			 * container is considered an error.
+			 */
+			if (have_dev_container) {
+				dev_err(&ctrl->dev, "%s: structural error,"
+				     " node %s has spmi-dev-container without"
+				     " specifying spmi-slave-container\n",
+				     __func__, node->full_name);
 				continue;
-			of_spmi_create_device(ctrl, &info, node);
+			}
+
+			if (!of_device_is_available(node))
+				continue;
+
+			rc = of_spmi_alloc_device_store(&d_info, 1);
+			if (rc) {
+				dev_err(&ctrl->dev, "%s: unable to allocate"
+					" device resources\n", __func__);
+				continue;
+			}
+
+			of_spmi_init_resource(&r_info, node);
+			of_spmi_sum_node_resources(&r_info, 0);
+			rc = of_spmi_allocate_node_resources(&d_info,
+								&r_info, 0);
+			if (rc) {
+				dev_err(&ctrl->dev, "%s: unable to allocate"
+						" resources\n", __func__);
+				of_spmi_free_device_resources(&d_info);
+				continue;
+			}
+
+			of_spmi_populate_node_resources(&d_info, &r_info, 0);
+
+			rc = of_spmi_create_device(&d_info, node);
+			if (rc) {
+				dev_err(&ctrl->dev, "%s: unable to create"
+						" device\n", __func__);
+				of_spmi_free_device_resources(&d_info);
+				continue;
+			}
 		}
 	}
 
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index dccd863..f8c752e 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -239,26 +239,45 @@
 	return err;
 }
 
+static int timer_mode;
+
 static int __init oprofile_init(void)
 {
 	int err;
 
+	/* always init architecture to setup backtrace support */
 	err = oprofile_arch_init(&oprofile_ops);
-	if (err < 0 || timer) {
-		printk(KERN_INFO "oprofile: using timer interrupt.\n");
+
+	timer_mode = err || timer;	/* fall back to timer mode on errors */
+	if (timer_mode) {
+		if (!err)
+			oprofile_arch_exit();
 		err = oprofile_timer_init(&oprofile_ops);
 		if (err)
 			return err;
 	}
-	return oprofilefs_register();
+
+	err = oprofilefs_register();
+	if (!err)
+		return 0;
+
+	/* failed */
+	if (timer_mode)
+		oprofile_timer_exit();
+	else
+		oprofile_arch_exit();
+
+	return err;
 }
 
 
 static void __exit oprofile_exit(void)
 {
-	oprofile_timer_exit();
 	oprofilefs_unregister();
-	oprofile_arch_exit();
+	if (timer_mode)
+		oprofile_timer_exit();
+	else
+		oprofile_arch_exit();
 }
 
 
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
index 89f6345..84a208d 100644
--- a/drivers/oprofile/oprofile_files.c
+++ b/drivers/oprofile/oprofile_files.c
@@ -45,7 +45,7 @@
 		return -EINVAL;
 
 	retval = oprofilefs_ulong_from_user(&val, buf, count);
-	if (retval)
+	if (retval <= 0)
 		return retval;
 
 	retval = oprofile_set_timeout(val);
@@ -84,7 +84,7 @@
 		return -EINVAL;
 
 	retval = oprofilefs_ulong_from_user(&val, buf, count);
-	if (retval)
+	if (retval <= 0)
 		return retval;
 
 	retval = oprofile_set_ulong(&oprofile_backtrace_depth, val);
@@ -141,9 +141,10 @@
 		return -EINVAL;
 
 	retval = oprofilefs_ulong_from_user(&val, buf, count);
-	if (retval)
+	if (retval <= 0)
 		return retval;
 
+	retval = 0;
 	if (val)
 		retval = oprofile_start();
 	else
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index e9ff6f7..1c0b799 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -60,6 +60,13 @@
 }
 
 
+/*
+ * Note: If oprofilefs_ulong_from_user() returns 0, then *val remains
+ * unchanged and might be uninitialized. This follows write syscall
+ * implementation when count is zero: "If count is zero ... [and if]
+ * no errors are detected, 0 will be returned without causing any
+ * other effect." (man 2 write)
+ */
 int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
 {
 	char tmpbuf[TMPBUFSIZE];
@@ -79,7 +86,7 @@
 	spin_lock_irqsave(&oprofilefs_lock, flags);
 	*val = simple_strtoul(tmpbuf, NULL, 0);
 	spin_unlock_irqrestore(&oprofilefs_lock, flags);
-	return 0;
+	return count;
 }
 
 
@@ -99,7 +106,7 @@
 		return -EINVAL;
 
 	retval = oprofilefs_ulong_from_user(&value, buf, count);
-	if (retval)
+	if (retval <= 0)
 		return retval;
 
 	retval = oprofile_set_ulong(file->private_data, value);
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index 3ef4462..878fba1 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -110,6 +110,7 @@
 	ops->start = oprofile_hrtimer_start;
 	ops->stop = oprofile_hrtimer_stop;
 	ops->cpu_type = "timer";
+	printk(KERN_INFO "oprofile: using timer interrupt.\n");
 	return 0;
 }
 
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index aca972b..dd7e0c5 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -278,8 +278,8 @@
 
 static int is_shpc_capable(struct pci_dev *dev)
 {
-	if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device ==
-						PCI_DEVICE_ID_AMD_GOLAM_7450))
+	if (dev->vendor == PCI_VENDOR_ID_AMD &&
+	    dev->device == PCI_DEVICE_ID_AMD_GOLAM_7450)
 		return 1;
 	if (!pci_find_capability(dev, PCI_CAP_ID_SHPC))
 		return 0;
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 36547f0..75ba231 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -944,8 +944,8 @@
 	ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */
 	ctrl_dbg(ctrl, "Hotplug Controller:\n");
 
-	if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
-				PCI_DEVICE_ID_AMD_GOLAM_7450)) {
+	if (pdev->vendor == PCI_VENDOR_ID_AMD &&
+	    pdev->device == PCI_DEVICE_ID_AMD_GOLAM_7450) {
 		/* amd shpc driver doesn't use Base Offset; assume 0 */
 		ctrl->mmio_base = pci_resource_start(pdev, 0);
 		ctrl->mmio_size = pci_resource_len(pdev, 0);
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index f02c34d..0ec8930 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -307,6 +307,11 @@
 	return (pte->val & 3) != 0;
 }
 
+static inline bool dma_pte_superpage(struct dma_pte *pte)
+{
+	return (pte->val & (1 << 7));
+}
+
 static inline int first_pte_in_page(struct dma_pte *pte)
 {
 	return !((unsigned long)pte & ~VTD_PAGE_MASK);
@@ -578,17 +583,18 @@
 
 static void domain_update_iommu_superpage(struct dmar_domain *domain)
 {
-	int i, mask = 0xf;
+	struct dmar_drhd_unit *drhd;
+	struct intel_iommu *iommu = NULL;
+	int mask = 0xf;
 
 	if (!intel_iommu_superpage) {
 		domain->iommu_superpage = 0;
 		return;
 	}
 
-	domain->iommu_superpage = 4; /* 1TiB */
-
-	for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
-		mask |= cap_super_page_val(g_iommus[i]->cap);
+	/* set iommu_superpage to the smallest common denominator */
+	for_each_active_iommu(iommu, drhd) {
+		mask &= cap_super_page_val(iommu->cap);
 		if (!mask) {
 			break;
 		}
@@ -731,29 +737,23 @@
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
-				      unsigned long pfn, int large_level)
+				      unsigned long pfn, int target_level)
 {
 	int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
 	struct dma_pte *parent, *pte = NULL;
 	int level = agaw_to_level(domain->agaw);
-	int offset, target_level;
+	int offset;
 
 	BUG_ON(!domain->pgd);
 	BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
 	parent = domain->pgd;
 
-	/* Search pte */
-	if (!large_level)
-		target_level = 1;
-	else
-		target_level = large_level;
-
 	while (level > 0) {
 		void *tmp_page;
 
 		offset = pfn_level_offset(pfn, level);
 		pte = &parent[offset];
-		if (!large_level && (pte->val & DMA_PTE_LARGE_PAGE))
+		if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
 			break;
 		if (level == target_level)
 			break;
@@ -817,13 +817,14 @@
 }
 
 /* clear last level pte, a tlb flush should be followed */
-static void dma_pte_clear_range(struct dmar_domain *domain,
+static int dma_pte_clear_range(struct dmar_domain *domain,
 				unsigned long start_pfn,
 				unsigned long last_pfn)
 {
 	int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
 	unsigned int large_page = 1;
 	struct dma_pte *first_pte, *pte;
+	int order;
 
 	BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
 	BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
@@ -847,6 +848,9 @@
 				   (void *)pte - (void *)first_pte);
 
 	} while (start_pfn && start_pfn <= last_pfn);
+
+	order = (large_page - 1) * 9;
+	return order;
 }
 
 /* free page table pages. last level pte should already be cleared */
@@ -3740,6 +3744,7 @@
 		vm_domain_exit(dmar_domain);
 		return -ENOMEM;
 	}
+	domain_update_iommu_cap(dmar_domain);
 	domain->priv = dmar_domain;
 
 	return 0;
@@ -3865,14 +3870,15 @@
 {
 	struct dmar_domain *dmar_domain = domain->priv;
 	size_t size = PAGE_SIZE << gfp_order;
+	int order;
 
-	dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
+	order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
 			    (iova + size - 1) >> VTD_PAGE_SHIFT);
 
 	if (dmar_domain->max_addr == iova + size)
 		dmar_domain->max_addr = iova;
 
-	return gfp_order;
+	return order;
 }
 
 static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 2f10328..e174982 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -869,5 +869,15 @@
 
 void pci_msi_init_pci_dev(struct pci_dev *dev)
 {
+	int pos;
 	INIT_LIST_HEAD(&dev->msi_list);
+
+	/* Disable the msi hardware to avoid screaming interrupts
+	 * during boot.  This is the power on reset default so
+	 * usually this should be a noop.
+	 */
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	if (pos)
+		msi_set_enable(dev, pos, 0);
+	msix_set_enable(dev, 0);
 }
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index d36f41e..56b04bc 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -393,7 +393,6 @@
 
 	if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
 		printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
-		pcie_clear_aspm();
 		pcie_no_aspm();
 	}
 
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 6892601..e25af67 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -68,7 +68,7 @@
 	struct aspm_latency acceptable[8];
 };
 
-static int aspm_disabled, aspm_force, aspm_clear_state;
+static int aspm_disabled, aspm_force;
 static bool aspm_support_enabled = true;
 static DEFINE_MUTEX(aspm_lock);
 static LIST_HEAD(link_list);
@@ -500,9 +500,6 @@
 	int pos;
 	u32 reg32;
 
-	if (aspm_clear_state)
-		return -EINVAL;
-
 	/*
 	 * Some functions in a slot might not all be PCIe functions,
 	 * very strange. Disable ASPM for the whole slot
@@ -574,9 +571,6 @@
 	    pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
 		return;
 
-	if (aspm_disabled && !aspm_clear_state)
-		return;
-
 	/* VIA has a strange chipset, root port is under a bridge */
 	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
 	    pdev->bus->self)
@@ -608,7 +602,7 @@
 	 * the BIOS's expectation, we'll do so once pci_enable_device() is
 	 * called.
 	 */
-	if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) {
+	if (aspm_policy != POLICY_POWERSAVE) {
 		pcie_config_aspm_path(link);
 		pcie_set_clkpm(link, policy_to_clkpm_state(link));
 	}
@@ -649,8 +643,7 @@
 	struct pci_dev *parent = pdev->bus->self;
 	struct pcie_link_state *link, *root, *parent_link;
 
-	if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
-	    !parent || !parent->link_state)
+	if (!pci_is_pcie(pdev) || !parent || !parent->link_state)
 		return;
 	if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
 	    (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
@@ -734,13 +727,18 @@
  * pci_disable_link_state - disable pci device's link state, so the link will
  * never enter specific states
  */
-static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
+static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem,
+				     bool force)
 {
 	struct pci_dev *parent = pdev->bus->self;
 	struct pcie_link_state *link;
 
-	if (aspm_disabled || !pci_is_pcie(pdev))
+	if (aspm_disabled && !force)
 		return;
+
+	if (!pci_is_pcie(pdev))
+		return;
+
 	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
 	    pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
 		parent = pdev;
@@ -768,16 +766,31 @@
 
 void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
 {
-	__pci_disable_link_state(pdev, state, false);
+	__pci_disable_link_state(pdev, state, false, false);
 }
 EXPORT_SYMBOL(pci_disable_link_state_locked);
 
 void pci_disable_link_state(struct pci_dev *pdev, int state)
 {
-	__pci_disable_link_state(pdev, state, true);
+	__pci_disable_link_state(pdev, state, true, false);
 }
 EXPORT_SYMBOL(pci_disable_link_state);
 
+void pcie_clear_aspm(struct pci_bus *bus)
+{
+	struct pci_dev *child;
+
+	/*
+	 * Clear any ASPM setup that the firmware has carried out on this bus
+	 */
+	list_for_each_entry(child, &bus->devices, bus_list) {
+		__pci_disable_link_state(child, PCIE_LINK_STATE_L0S |
+					 PCIE_LINK_STATE_L1 |
+					 PCIE_LINK_STATE_CLKPM,
+					 false, true);
+	}
+}
+
 static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
 {
 	int i;
@@ -935,6 +948,7 @@
 static int __init pcie_aspm_disable(char *str)
 {
 	if (!strcmp(str, "off")) {
+		aspm_policy = POLICY_DEFAULT;
 		aspm_disabled = 1;
 		aspm_support_enabled = false;
 		printk(KERN_INFO "PCIe ASPM is disabled\n");
@@ -947,16 +961,18 @@
 
 __setup("pcie_aspm=", pcie_aspm_disable);
 
-void pcie_clear_aspm(void)
-{
-	if (!aspm_force)
-		aspm_clear_state = 1;
-}
-
 void pcie_no_aspm(void)
 {
-	if (!aspm_force)
+	/*
+	 * Disabling ASPM is intended to prevent the kernel from modifying
+	 * existing hardware state, not to clear existing state. To that end:
+	 * (a) set policy to POLICY_DEFAULT in order to avoid changing state
+	 * (b) prevent userspace from changing policy
+	 */
+	if (!aspm_force) {
+		aspm_policy = POLICY_DEFAULT;
 		aspm_disabled = 1;
+	}
 }
 
 /**
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 1196f61..cec4629 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2745,20 +2745,6 @@
 	/* disable must be done via function #0 */
 	if (PCI_FUNC(dev->devfn))
 		return;
-
-	pci_read_config_byte(dev, 0xCB, &disable);
-
-	if (disable & 0x02)
-		return;
-
-	pci_read_config_byte(dev, 0xCA, &write_enable);
-	pci_write_config_byte(dev, 0xCA, 0x57);
-	pci_write_config_byte(dev, 0xCB, disable | 0x02);
-	pci_write_config_byte(dev, 0xCA, write_enable);
-
-	dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n");
-	dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n");
-
 	/*
 	 * RICOH 0xe823 SD/MMC card reader fails to recognize
 	 * certain types of SD/MMC cards. Lowering the SD base
@@ -2781,6 +2767,20 @@
 
 		dev_notice(&dev->dev, "MMC controller base frequency changed to 50Mhz.\n");
 	}
+
+	pci_read_config_byte(dev, 0xCB, &disable);
+
+	if (disable & 0x02)
+		return;
+
+	pci_read_config_byte(dev, 0xCA, &write_enable);
+	pci_write_config_byte(dev, 0xCA, 0x57);
+	pci_write_config_byte(dev, 0xCB, disable | 0x02);
+	pci_write_config_byte(dev, 0xCA, write_enable);
+
+	dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n");
+	dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n");
+
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 492b7d8..d4e7a10 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -400,9 +400,8 @@
 			dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n",
 				pci_name(dev), i);
 			if (pci_claim_resource(dev, i)) {
-				dev_err(&pdev->xdev->dev, "Could not claim "
-					"resource %s/%d! Device offline. Try "
-					"giving less than 4GB to domain.\n",
+				dev_err(&pdev->xdev->dev, "Could not claim resource %s/%d! "
+					"Device offline. Try using e820_host=1 in the guest config.\n",
 					pci_name(dev), i);
 			}
 		}
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 749c2a1..1932029 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1269,10 +1269,8 @@
 
 static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
 {
-	if (!verify_cis_cache(skt)) {
-		pcmcia_put_socket(skt);
+	if (!verify_cis_cache(skt))
 		return 0;
-	}
 
 	dev_dbg(&skt->dev, "cis mismatch - different card\n");
 
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 4279603..f2981bf 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,13 +20,14 @@
 
 #include "bam.h"
 #include "sps_bam.h"
+#include "spsi.h"
 
 /**
  *  Valid BAM Hardware version.
  *
  */
 #define BAM_MIN_VERSION 2
-#define BAM_MAX_VERSION 0x1f
+#define BAM_MAX_VERSION 0x2f
 
 #ifdef CONFIG_SPS_SUPPORT_NDP_BAM
 
@@ -94,6 +95,8 @@
  *
  */
 /* CTRL */
+#define CACHE_MISS_ERR_RESP_EN                 0x80000
+#define LOCAL_CLK_GATING                       0x60000
 #define IBC_DISABLE                            0x10000
 #define BAM_CACHED_DESC_STORE                   0x8000
 #define BAM_DESC_CACHE_SEL                      0x6000
@@ -171,17 +174,23 @@
 #define AHB_MASTER_ERR_CTRLS_BAM_ERR_HTRANS             0x3
 
 /* TRUST_REG  */
+#define LOCK_EE_CTRL                            0x2000
 #define BAM_VMID                                0x1f00
 #define BAM_RST_BLOCK                             0x80
 #define BAM_EE                                     0x7
 
 /* TEST_BUS_SEL */
+#define BAM_SW_EVENTS_ZERO                    0x200000
+#define BAM_SW_EVENTS_SEL                     0x180000
 #define BAM_DATA_ERASE                         0x40000
 #define BAM_DATA_FLUSH                         0x20000
 #define BAM_CLK_ALWAYS_ON                      0x10000
 #define BAM_TESTBUS_SEL                           0x7f
 
 /* CNFG_BITS */
+#define CNFG_BITS_MULTIPLE_EVENTS_DESC_AVAIL_EN  0x40000000
+#define CNFG_BITS_MULTIPLE_EVENTS_SIZE_EN        0x20000000
+#define CNFG_BITS_BAM_ZLT_W_CD_SUPPORT           0x10000000
 #define CNFG_BITS_BAM_CD_ENABLE                   0x8000000
 #define CNFG_BITS_BAM_AU_ACCUMED                  0x4000000
 #define CNFG_BITS_BAM_PSM_P_HD_DATA               0x2000000
@@ -221,6 +230,7 @@
 
 /* P_TRUST_REGn */
 #define BAM_P_VMID                              0x1f00
+#define BAM_P_SUP_GROUP                           0xf8
 #define BAM_P_EE                                   0x7
 
 /* P_IRQ_STTSn */
@@ -662,6 +672,12 @@
 
 	bam_write_reg_field(base, CTRL, BAM_EN, 1);
 
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	bam_write_reg_field(base, CTRL, CACHE_MISS_ERR_RESP_EN, 1);
+
+	bam_write_reg_field(base, CTRL, LOCAL_CLK_GATING, 1);
+#endif
+
 	bam_write_reg(base, DESC_CNT_TRSHLD, summing_threshold);
 
 	bam_write_reg(base, CNFG_BITS, cfg_bits);
@@ -740,8 +756,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 +783,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 +800,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;
 	}
 
@@ -855,6 +877,14 @@
 	bam_write_reg_field(base, P_CTRL(pipe), P_SYS_STRM,
 			    param->stream_mode);
 
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	bam_write_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP,
+				param->lock_group);
+
+	SPS_DBG("sps:bam=0x%x(va).pipe=%d.lock_group=%d.\n",
+			(u32) base, pipe, param->lock_group);
+#endif
+
 	if (param->mode == BAM_PIPE_MODE_BAM2BAM) {
 		u32 peer_dest_addr = param->peer_phys_addr +
 				      P_EVNT_REG(param->peer_pipe);
@@ -866,11 +896,19 @@
 
 		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,
 			param->peer_pipe);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		bam_write_reg_field(base, P_CTRL(pipe), P_WRITE_NWD,
+					param->write_nwd);
+
+		SPS_DBG("sps:%s WRITE_NWD bit for this bam2bam pipe.",
+			param->write_nwd ? "Set" : "Do not set");
+#endif
 	}
 
 	/* Pipe Enable - at last */
@@ -1051,3 +1089,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/bam.h b/drivers/platform/msm/sps/bam.h
index d672a88..789769f 100644
--- a/drivers/platform/msm/sps/bam.h
+++ b/drivers/platform/msm/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
@@ -39,6 +39,13 @@
 	BAM_STREAM_MODE_ENABLE = 1,
 };
 
+/* NWD written Type */
+enum bam_write_nwd {
+	BAM_WRITE_NWD_DISABLE = 0,
+	BAM_WRITE_NWD_ENABLE = 1,
+};
+
+
 /* Enable Type */
 enum bam_enable {
 	BAM_DISABLE = 0,
@@ -63,8 +70,10 @@
 	u32 pipe_irq_mask;
 	enum bam_pipe_dir dir;
 	enum bam_pipe_mode mode;
+	enum bam_write_nwd write_nwd;
 	u32 desc_base;	/* Physical address of descriptor FIFO */
 	u32 desc_size;	/* Size (bytes) of descriptor FIFO */
+	u32 lock_group;	/* The lock group this pipe belongs to */
 	enum bam_stream_mode stream_mode;
 	u32 ee;		/* BAM execution environment index */
 
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index c17da9b..0fe8f2a 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,10 +820,16 @@
 		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;
 	}
 
+	if ((connect->lock_group != SPSRM_CLEAR)
+		&& (connect->lock_group > BAM_MAX_P_LOCK_GROUP_NUM)) {
+		SPS_ERR("sps:The value of pipe lock group is invalid.\n");
+		return SPS_ERROR;
+	}
+
 	mutex_lock(&sps->lock);
 	/*
 	 * Must lock the BAM device at the top level function, so must
@@ -614,12 +842,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 +902,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 +927,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 +957,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 +974,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 +991,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 +1015,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 +1039,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 +1064,35 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
+
+	if ((flags & SPS_IOVEC_FLAG_NWD) &&
+		!(flags & (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_CMD))) {
+		SPS_ERR("sps:NWD is only valid with EOT or CMD.\n");
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_EOT) &&
+		(flags & SPS_IOVEC_FLAG_CMD)) {
+		SPS_ERR("sps:EOT and CMD are not allowed to coexist.\n");
+		return SPS_ERROR;
+	} else if (!(flags & SPS_IOVEC_FLAG_CMD) &&
+		(flags & (SPS_IOVEC_FLAG_LOCK | SPS_IOVEC_FLAG_UNLOCK))) {
+		SPS_ERR("sps:pipe lock and unlock flags are only valid with "
+			"Command Descriptor.\n");
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_LOCK) &&
+		(flags & SPS_IOVEC_FLAG_UNLOCK)) {
+		SPS_ERR("sps:Can't lock and unlock a pipe by the same"
+			"Command Descriptor.\n");
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_IMME) &&
+		(flags & SPS_IOVEC_FLAG_CMD)) {
+		SPS_ERR("sps:Immediate and CMD are not allowed to coexist.\n");
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_IMME) &&
+		(flags & SPS_IOVEC_FLAG_NWD)) {
+		SPS_ERR("sps:Immediate and NWD are not allowed to coexist.\n");
+		return SPS_ERROR;
+	}
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -857,7 +1117,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 +1140,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 +1163,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 +1185,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 +1200,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 +1220,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 +1241,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 +1269,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 +1313,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 +1340,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);
 
@@ -1086,6 +1352,32 @@
 EXPORT_SYMBOL(sps_free_mem);
 
 /**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ *
+ */
+int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num)
+{
+	struct sps_pipe *pipe = h;
+	struct sps_bam *bam;
+	int result;
+
+	SPS_DBG("sps:%s.", __func__);
+
+	bam = sps_bam_lock(pipe);
+	if (bam == NULL)
+		return SPS_ERROR;
+
+	result = sps_bam_pipe_get_unused_desc_num(bam, pipe->pipe_index,
+						desc_num);
+
+	sps_bam_unlock(bam);
+
+	return result;
+}
+EXPORT_SYMBOL(sps_get_unused_desc_num);
+
+/**
  * Register a BAM device
  *
  */
@@ -1103,7 +1395,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 +1406,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 +1414,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 +1431,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 +1444,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 +1452,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 +1474,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 +1482,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 +1511,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 +1533,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 +1578,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 +1609,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 +1639,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 +1738,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 +1789,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 +1876,7 @@
 #endif
 	sps->is_ready = true;
 
-	SPS_INFO("sps is ready.");
+	SPS_INFO("sps:sps is ready.");
 
 	return 0;
 clk_err:
@@ -1590,7 +1892,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 +1933,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 +1952,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..6c8b1f9 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
@@ -35,7 +35,9 @@
 
 /* Mask for valid hardware descriptor flags */
 #define BAM_IOVEC_FLAG_MASK   \
-	(SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_EOB)
+	(SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_EOB |   \
+	SPS_IOVEC_FLAG_NWD | SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_LOCK |   \
+	SPS_IOVEC_FLAG_UNLOCK | SPS_IOVEC_FLAG_IMME)
 
 /* Mask for invalid BAM-to-BAM pipe options */
 #define BAM2BAM_O_INVALID   \
@@ -102,7 +104,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 +140,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 +148,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 +169,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 +196,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 +214,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 +228,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 +253,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 +272,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 +286,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 +295,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 +314,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 +342,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 +394,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 +410,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 +434,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 +445,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 +453,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 +468,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 +487,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 +505,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 +516,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 +569,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 +583,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 +621,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 +632,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 +644,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,23 +708,25 @@
 	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;
 	hw_params.ee = dev->props.ee;
+	hw_params.lock_group = map_pipe->lock_group;
 
 	/* 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 +744,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;
@@ -739,6 +754,14 @@
 		/* Clear the data FIFO for debug */
 		if (map->data.base != NULL && bam_pipe->mode == SPS_MODE_SRC)
 			memset(map->data.base, 0, hw_params.data_size);
+
+		/* set NWD bit for BAM2BAM producer pipe */
+		if (bam_pipe->mode == SPS_MODE_SRC) {
+			if ((params->options & SPS_O_WRITE_NWD) == 0)
+				hw_params.write_nwd = BAM_WRITE_NWD_DISABLE;
+			else
+				hw_params.write_nwd = BAM_WRITE_NWD_ENABLE;
+		}
 	} else {
 		/* System mode */
 		hw_params.mode = BAM_PIPE_MODE_SYSTEM;
@@ -754,7 +777,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 +811,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;
+		return SPS_ERROR;
 	}
 
 	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;
+		return SPS_ERROR;
 	}
 
 	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 +893,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 +919,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 +962,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 +1008,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 +1018,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 +1032,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 +1103,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 +1118,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 +1148,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 +1158,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 +1177,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 +1260,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 +1693,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 +1798,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 +1837,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 +1873,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 +1928,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;
 	}
@@ -1936,3 +1960,29 @@
 	return result;
 }
 
+/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ */
+int sps_bam_pipe_get_unused_desc_num(struct sps_bam *dev, u32 pipe_index,
+					u32 *desc_num)
+{
+	u32 sw_offset, peer_offset, fifo_size;
+	u32 desc_size = sizeof(struct sps_iovec);
+	struct sps_pipe *pipe = dev->pipes[pipe_index];
+
+	if (pipe == NULL)
+		return SPS_ERROR;
+
+	fifo_size = pipe->desc_size;
+
+	sw_offset = bam_pipe_get_desc_read_offset(dev->base, pipe_index);
+	peer_offset = bam_pipe_get_desc_write_offset(dev->base, pipe_index);
+
+	if (sw_offset <= peer_offset)
+		*desc_num = (peer_offset - sw_offset) / desc_size;
+	else
+		*desc_num = (peer_offset + fifo_size - sw_offset) / desc_size;
+
+	return 0;
+}
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 3af891e..6004b75 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 {
@@ -546,4 +545,20 @@
 int sps_bam_pipe_timer_ctrl(struct sps_bam *dev, u32 pipe_index,
 			    struct sps_timer_ctrl *timer_ctrl,
 			    struct sps_timer_result *timer_result);
+
+
+/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ *
+ * @dev - pointer to BAM device descriptor
+ *
+ * @pipe_index - pipe index
+ *
+ * @desc_num - number of unused descriptors
+ *
+ */
+int sps_bam_pipe_get_unused_desc_num(struct sps_bam *dev, u32 pipe_index,
+					u32 *desc_num);
+
 #endif	/* _SPSBAM_H_ */
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..c980eb0 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
@@ -22,9 +22,6 @@
 #include "spsi.h"
 #include "sps_core.h"
 
-/* "Clear" value for the connection parameter struct */
-#define SPSRM_CLEAR     0xcccccccc
-
 /* Max BAM FIFO sizes */
 #define SPSRM_MAX_DESC_FIFO_SIZE    0xffff
 #define SPSRM_MAX_DATA_FIFO_SIZE    0xffff
@@ -70,7 +67,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 +176,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) {
@@ -195,6 +195,8 @@
 		pipe->pipe_index = map->src.pipe_index;
 		if (pipe->connect.event_thresh != SPSRM_CLEAR)
 			map->src.event_threshold = pipe->connect.event_thresh;
+		if (pipe->connect.lock_group != SPSRM_CLEAR)
+			map->src.lock_group = pipe->connect.lock_group;
 	} else {
 		map->client_dest = pipe;
 		pipe->bam = map->dest.bam;
@@ -202,6 +204,8 @@
 		if (pipe->connect.event_thresh != SPSRM_CLEAR)
 			map->dest.event_threshold =
 			pipe->connect.event_thresh;
+		if (pipe->connect.lock_group != SPSRM_CLEAR)
+			map->dest.lock_group = pipe->connect.lock_group;
 	}
 	pipe->map = map;
 
@@ -355,7 +359,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 +373,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 +381,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 +390,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 +413,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 +440,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 +478,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 +491,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 +508,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 +617,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 +625,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 +642,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 +698,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 +720,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 +743,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 +756,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 +770,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 +792,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..8e4907b 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,15 @@
 #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
+#define BAM_MAX_P_LOCK_GROUP_NUM   31
+
 /* Adjust for offset of struct sps_q_event */
 #define SPS_EVENT_INDEX(e)    ((e) - 1)
 #define SPS_ERROR -1
@@ -33,34 +37,89 @@
 /* BAM identifier used in log messages */
 #define BAM_ID(dev)       ((dev)->props.phys_addr)
 
+/* "Clear" value for the connection parameter struct */
+#define SPSRM_CLEAR     0xcccccccc
+
 #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)
@@ -72,6 +131,7 @@
 	u32 bam_phys;		/* Physical address of BAM. */
 	u32 pipe_index;		/* Pipe index */
 	u32 event_threshold;	/* Pipe event threshold */
+	u32 lock_group;	/* The lock group this pipe belongs to */
 	void *bam;
 };
 
@@ -121,6 +181,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/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 6caa48f..053b81f 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_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
@@ -39,6 +39,11 @@
 
 static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
 
+static inline int bam_offset(struct msm_usb_bam_platform_data *pdata)
+{
+	return pdata->usb_active_bam * CONNECTIONS_NUM * 2;
+}
+
 static int connect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
 						u8 *usb_pipe_idx)
 {
@@ -51,7 +56,7 @@
 			(usb_bam_pdev->dev.platform_data);
 	struct usb_bam_pipe_connect *pipe_connection =
 			(struct usb_bam_pipe_connect *)(pdata->connections +
-						(2*connection_idx+pipe_dir));
+			 bam_offset(pdata) + (2*connection_idx+pipe_dir));
 
 	pipe = sps_alloc_endpoint();
 	if (pipe == NULL) {
@@ -162,6 +167,7 @@
 
 	return 0;
 }
+
 static int usb_bam_init(void)
 {
 	u32 h_usb;
@@ -207,6 +213,62 @@
 	return 0;
 }
 
+static char *bam_enable_strings[2] = {
+	[HSUSB_BAM] = "hsusb",
+	[HSIC_BAM]  = "hsic",
+};
+
+static ssize_t
+usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
+		    char *buf)
+{
+	struct platform_device *pdev = container_of(dev, struct platform_device,
+						    dev);
+	struct msm_usb_bam_platform_data *pdata =
+		(struct msm_usb_bam_platform_data *)
+			(usb_bam_pdev->dev.platform_data);
+
+	if (!pdev || !pdata)
+		return 0;
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+			 bam_enable_strings[pdata->usb_active_bam]);
+}
+
+static ssize_t usb_bam_store_enable(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct platform_device *pdev = container_of(dev, struct platform_device,
+						    dev);
+	struct msm_usb_bam_platform_data *pdata =
+		(struct msm_usb_bam_platform_data *)
+			(usb_bam_pdev->dev.platform_data);
+	char str[10], *pstr;
+	int ret, i;
+
+	strlcpy(str, buf, sizeof(str));
+	pstr = strim(str);
+
+	for (i = 0; i < ARRAY_SIZE(bam_enable_strings); i++) {
+		if (!strncmp(pstr, bam_enable_strings[i], sizeof(str)))
+			pdata->usb_active_bam = i;
+	}
+
+	dev_dbg(&pdev->dev, "active_bam=%s\n",
+		bam_enable_strings[pdata->usb_active_bam]);
+
+	ret = usb_bam_init();
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize usb bam\n");
+		return ret;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUSR, usb_bam_show_enable,
+		   usb_bam_store_enable);
+
 static int usb_bam_probe(struct platform_device *pdev)
 {
 	int ret, i;
@@ -222,13 +284,11 @@
 	}
 	usb_bam_pdev = pdev;
 
-	ret = usb_bam_init();
-	if (ret) {
-		dev_err(&pdev->dev, "failed to initialize usb bam\n");
-		return ret;
-	}
+	ret = device_create_file(&pdev->dev, &dev_attr_enable);
+	if (ret)
+		dev_err(&pdev->dev, "failed to create device file\n");
 
-	return 0;
+	return ret;
 }
 
 static struct platform_driver usb_bam_driver = {
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index 1658575..ec85987 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -370,15 +370,17 @@
 				  &sretval);
 	if (!retval) {
 		user_brightness = sretval.retval[0];
-		if (user_brightness != 0)
+		if (user_brightness > sabi_config->min_brightness)
 			user_brightness -= sabi_config->min_brightness;
+		else
+			user_brightness = 0;
 	}
 	return user_brightness;
 }
 
 static void set_brightness(u8 user_brightness)
 {
-	u8 user_level = user_brightness - sabi_config->min_brightness;
+	u8 user_level = user_brightness + sabi_config->min_brightness;
 
 	sabi_set_command(sabi_config->commands.set_brightness, user_level);
 }
@@ -631,6 +633,15 @@
 		.callback = dmi_check_cb,
 	},
 	{
+		.ident = "R700",
+		.matches = {
+		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		      DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
+		      DMI_MATCH(DMI_BOARD_NAME, "SR700"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
 		.ident = "R530/R730",
 		.matches = {
 		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
@@ -676,6 +687,24 @@
 		},
 		.callback = dmi_check_cb,
 	},
+		{
+		.ident = "X520",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
+			DMI_MATCH(DMI_BOARD_NAME, "X520"),
+		},
+		.callback = dmi_check_cb,
+	},
+	{
+		.ident = "R528/R728",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
+			DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
+		},
+		.callback = dmi_check_cb,
+	},
 	{ },
 };
 MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
@@ -760,7 +789,7 @@
 	sabi_iface = ioremap_nocache(ifaceP, 16);
 	if (!sabi_iface) {
 		pr_err("Can't remap %x\n", ifaceP);
-		goto exit;
+		goto error_no_signature;
 	}
 	if (debug) {
 		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
@@ -792,7 +821,8 @@
 	/* create a backlight device to talk to this one */
 	memset(&props, 0, sizeof(struct backlight_properties));
 	props.type = BACKLIGHT_PLATFORM;
-	props.max_brightness = sabi_config->max_brightness;
+	props.max_brightness = sabi_config->max_brightness -
+				sabi_config->min_brightness;
 	backlight_device = backlight_device_register("samsung", &sdev->dev,
 						     NULL, &backlight_ops,
 						     &props);
@@ -811,7 +841,6 @@
 	if (retval)
 		goto error_file_create;
 
-exit:
 	return 0;
 
 error_file_create:
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index f23d5a8..9b88be4 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -754,9 +754,13 @@
 	struct wmi_block *wblock, *next;
 
 	/* Delete devices for all the GUIDs */
-	list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
+	list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
+		list_del(&wblock->list);
 		if (wblock->dev.class)
 			device_unregister(&wblock->dev);
+		else
+			kfree(wblock);
+	}
 }
 
 static bool guid_already_parsed(const char *guid_string)
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index dfbd5a6..258fef2 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -295,6 +295,45 @@
 	}
 }
 
+#ifdef CONFIG_AMD_NB
+
+#include <asm/amd_nb.h>
+
+static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
+{
+	resource_size_t start, end;
+	struct pnp_resource *pnp_res;
+	struct resource *res;
+	struct resource mmconfig_res, *mmconfig;
+
+	mmconfig = amd_get_mmconfig_range(&mmconfig_res);
+	if (!mmconfig)
+		return;
+
+	list_for_each_entry(pnp_res, &dev->resources, list) {
+		res = &pnp_res->res;
+		if (res->end < mmconfig->start || res->start > mmconfig->end ||
+		    (res->start == mmconfig->start && res->end == mmconfig->end))
+			continue;
+
+		dev_info(&dev->dev, FW_BUG
+			 "%pR covers only part of AMD MMCONFIG area %pR; adding more reservations\n",
+			 res, mmconfig);
+		if (mmconfig->start < res->start) {
+			start = mmconfig->start;
+			end = res->start - 1;
+			pnp_add_mem_resource(dev, start, end, 0);
+		}
+		if (mmconfig->end > res->end) {
+			start = res->end + 1;
+			end = mmconfig->end;
+			pnp_add_mem_resource(dev, start, end, 0);
+		}
+		break;
+	}
+}
+#endif
+
 /*
  *  PnP Quirks
  *  Cards or devices that need some tweaking due to incomplete resource info
@@ -322,6 +361,9 @@
 	/* PnP resources that might overlap PCI BARs */
 	{"PNP0c01", quirk_system_pci_resources},
 	{"PNP0c02", quirk_system_pci_resources},
+#ifdef CONFIG_AMD_NB
+	{"PNP0c01", quirk_amd_mmconfig_area},
+#endif
 	{""}
 };
 
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3dfa68e..ff67876 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -281,6 +281,16 @@
 	  To compile this driver as a module, choose M here: the module will
 	  be called smb137b.
 
+config SMB349_CHARGER
+	tristate "smb349 charger"
+	depends on I2C
+	help
+	  Say Y to enable support for the SMB349 switching mode based charger
+	  and sysfs. The driver supports controlling charger-enable and
+	  current limiting capabilities. The driver also lets the
+	  SMB349 be operated as a slave device via the power supply
+	  framework.
+
 config BATTERY_MSM_FAKE
 	tristate "Fake MSM battery"
 	depends on ARCH_MSM && BATTERY_MSM
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 03db839..c662c2d 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -40,6 +40,7 @@
 obj-$(CONFIG_BATTERY_MSM8X60)   += msm_charger.o
 obj-$(CONFIG_PM8058_CHARGER)    += pmic8058-charger.o
 obj-$(CONFIG_ISL9519_CHARGER)   += isl9519q.o
+obj-$(CONFIG_SMB349_CHARGER)   += smb349.o
 obj-$(CONFIG_PM8058_FIX_USB)    += pm8058_usb_fix.o
 obj-$(CONFIG_BATTERY_QCIBAT)    += qci_battery.o
 obj-$(CONFIG_BATTERY_BQ27520)	+= bq27520_fuelgauger.o
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c
index 1fefe82..91a783d 100644
--- a/drivers/power/ds2780_battery.c
+++ b/drivers/power/ds2780_battery.c
@@ -39,6 +39,7 @@
 	struct device *dev;
 	struct power_supply bat;
 	struct device *w1_dev;
+	struct task_struct *mutex_holder;
 };
 
 enum current_types {
@@ -49,8 +50,8 @@
 static const char model[] = "DS2780";
 static const char manufacturer[] = "Maxim/Dallas";
 
-static inline struct ds2780_device_info *to_ds2780_device_info(
-	struct power_supply *psy)
+static inline struct ds2780_device_info *
+to_ds2780_device_info(struct power_supply *psy)
 {
 	return container_of(psy, struct ds2780_device_info, bat);
 }
@@ -60,17 +61,28 @@
 	return dev_get_drvdata(dev);
 }
 
-static inline int ds2780_read8(struct device *dev, u8 *val, int addr)
+static inline int ds2780_battery_io(struct ds2780_device_info *dev_info,
+	char *buf, int addr, size_t count, int io)
 {
-	return w1_ds2780_io(dev, val, addr, sizeof(u8), 0);
+	if (dev_info->mutex_holder == current)
+		return w1_ds2780_io_nolock(dev_info->w1_dev, buf, addr, count, io);
+	else
+		return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
 }
 
-static int ds2780_read16(struct device *dev, s16 *val, int addr)
+static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val,
+	int addr)
+{
+	return ds2780_battery_io(dev_info, val, addr, sizeof(u8), 0);
+}
+
+static int ds2780_read16(struct ds2780_device_info *dev_info, s16 *val,
+	int addr)
 {
 	int ret;
 	u8 raw[2];
 
-	ret = w1_ds2780_io(dev, raw, addr, sizeof(u8) * 2, 0);
+	ret = ds2780_battery_io(dev_info, raw, addr, sizeof(raw), 0);
 	if (ret < 0)
 		return ret;
 
@@ -79,16 +91,16 @@
 	return 0;
 }
 
-static inline int ds2780_read_block(struct device *dev, u8 *val, int addr,
-	size_t count)
+static inline int ds2780_read_block(struct ds2780_device_info *dev_info,
+	u8 *val, int addr, size_t count)
 {
-	return w1_ds2780_io(dev, val, addr, count, 0);
+	return ds2780_battery_io(dev_info, val, addr, count, 0);
 }
 
-static inline int ds2780_write(struct device *dev, u8 *val, int addr,
-	size_t count)
+static inline int ds2780_write(struct ds2780_device_info *dev_info, u8 *val,
+	int addr, size_t count)
 {
-	return w1_ds2780_io(dev, val, addr, count, 1);
+	return ds2780_battery_io(dev_info, val, addr, count, 1);
 }
 
 static inline int ds2780_store_eeprom(struct device *dev, int addr)
@@ -122,7 +134,7 @@
 {
 	int ret;
 
-	ret = ds2780_write(dev_info->w1_dev, &conductance,
+	ret = ds2780_write(dev_info, &conductance,
 				DS2780_RSNSP_REG, sizeof(u8));
 	if (ret < 0)
 		return ret;
@@ -134,7 +146,7 @@
 static int ds2780_get_rsgain_register(struct ds2780_device_info *dev_info,
 	u16 *rsgain)
 {
-	return ds2780_read16(dev_info->w1_dev, rsgain, DS2780_RSGAIN_MSB_REG);
+	return ds2780_read16(dev_info, rsgain, DS2780_RSGAIN_MSB_REG);
 }
 
 /* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */
@@ -144,8 +156,8 @@
 	int ret;
 	u8 raw[] = {rsgain >> 8, rsgain & 0xFF};
 
-	ret = ds2780_write(dev_info->w1_dev, raw,
-				DS2780_RSGAIN_MSB_REG, sizeof(u8) * 2);
+	ret = ds2780_write(dev_info, raw,
+				DS2780_RSGAIN_MSB_REG, sizeof(raw));
 	if (ret < 0)
 		return ret;
 
@@ -167,7 +179,7 @@
 	 * Bits 2 - 0 of the voltage value are in bits 7 - 5 of the
 	 * voltage LSB register
 	 */
-	ret = ds2780_read16(dev_info->w1_dev, &voltage_raw,
+	ret = ds2780_read16(dev_info, &voltage_raw,
 				DS2780_VOLT_MSB_REG);
 	if (ret < 0)
 		return ret;
@@ -196,7 +208,7 @@
 	 * Bits 2 - 0 of the temperature value are in bits 7 - 5 of the
 	 * temperature LSB register
 	 */
-	ret = ds2780_read16(dev_info->w1_dev, &temperature_raw,
+	ret = ds2780_read16(dev_info, &temperature_raw,
 				DS2780_TEMP_MSB_REG);
 	if (ret < 0)
 		return ret;
@@ -222,13 +234,13 @@
 	 * The units of measurement for current are dependent on the value of
 	 * the sense resistor.
 	 */
-	ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
+	ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG);
 	if (ret < 0)
 		return ret;
 
 	if (sense_res_raw == 0) {
 		dev_err(dev_info->dev, "sense resistor value is 0\n");
-		return -ENXIO;
+		return -EINVAL;
 	}
 	sense_res = 1000 / sense_res_raw;
 
@@ -248,7 +260,7 @@
 	 * Bits 7 - 0 of the current value are in bits 7 - 0 of the current
 	 * LSB register
 	 */
-	ret = ds2780_read16(dev_info->w1_dev, &current_raw, reg_msb);
+	ret = ds2780_read16(dev_info, &current_raw, reg_msb);
 	if (ret < 0)
 		return ret;
 
@@ -267,7 +279,7 @@
 	 * The units of measurement for accumulated current are dependent on
 	 * the value of the sense resistor.
 	 */
-	ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
+	ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG);
 	if (ret < 0)
 		return ret;
 
@@ -285,7 +297,7 @@
 	 * Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR
 	 * LSB register
 	 */
-	ret = ds2780_read16(dev_info->w1_dev, &current_raw, DS2780_ACR_MSB_REG);
+	ret = ds2780_read16(dev_info, &current_raw, DS2780_ACR_MSB_REG);
 	if (ret < 0)
 		return ret;
 
@@ -299,7 +311,7 @@
 	int ret;
 	u8 raw;
 
-	ret = ds2780_read8(dev_info->w1_dev, &raw, DS2780_RARC_REG);
+	ret = ds2780_read8(dev_info, &raw, DS2780_RARC_REG);
 	if (ret < 0)
 		return ret;
 
@@ -345,7 +357,7 @@
 	 * Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC
 	 * LSB register
 	 */
-	ret = ds2780_read16(dev_info->w1_dev, &charge_raw, DS2780_RAAC_MSB_REG);
+	ret = ds2780_read16(dev_info, &charge_raw, DS2780_RAAC_MSB_REG);
 	if (ret < 0)
 		return ret;
 
@@ -356,7 +368,7 @@
 static int ds2780_get_control_register(struct ds2780_device_info *dev_info,
 	u8 *control_reg)
 {
-	return ds2780_read8(dev_info->w1_dev, control_reg, DS2780_CONTROL_REG);
+	return ds2780_read8(dev_info, control_reg, DS2780_CONTROL_REG);
 }
 
 static int ds2780_set_control_register(struct ds2780_device_info *dev_info,
@@ -364,7 +376,7 @@
 {
 	int ret;
 
-	ret = ds2780_write(dev_info->w1_dev, &control_reg,
+	ret = ds2780_write(dev_info, &control_reg,
 				DS2780_CONTROL_REG, sizeof(u8));
 	if (ret < 0)
 		return ret;
@@ -503,7 +515,7 @@
 	struct power_supply *psy = to_power_supply(dev);
 	struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
 
-	ret = ds2780_read8(dev_info->w1_dev, &sense_resistor, DS2780_RSNSP_REG);
+	ret = ds2780_read8(dev_info, &sense_resistor, DS2780_RSNSP_REG);
 	if (ret < 0)
 		return ret;
 
@@ -584,7 +596,7 @@
 	struct power_supply *psy = to_power_supply(dev);
 	struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
 
-	ret = ds2780_read8(dev_info->w1_dev, &sfr, DS2780_SFR_REG);
+	ret = ds2780_read8(dev_info, &sfr, DS2780_SFR_REG);
 	if (ret < 0)
 		return ret;
 
@@ -611,7 +623,7 @@
 		return -EINVAL;
 	}
 
-	ret = ds2780_write(dev_info->w1_dev, &new_setting,
+	ret = ds2780_write(dev_info, &new_setting,
 				DS2780_SFR_REG, sizeof(u8));
 	if (ret < 0)
 		return ret;
@@ -632,7 +644,7 @@
 		DS2780_EEPROM_BLOCK1_END -
 		DS2780_EEPROM_BLOCK1_START + 1 - off);
 
-	return ds2780_read_block(dev_info->w1_dev, buf,
+	return ds2780_read_block(dev_info, buf,
 				DS2780_EEPROM_BLOCK1_START + off, count);
 }
 
@@ -650,7 +662,7 @@
 		DS2780_EEPROM_BLOCK1_END -
 		DS2780_EEPROM_BLOCK1_START + 1 - off);
 
-	ret = ds2780_write(dev_info->w1_dev, buf,
+	ret = ds2780_write(dev_info, buf,
 				DS2780_EEPROM_BLOCK1_START + off, count);
 	if (ret < 0)
 		return ret;
@@ -685,9 +697,8 @@
 		DS2780_EEPROM_BLOCK0_END -
 		DS2780_EEPROM_BLOCK0_START + 1 - off);
 
-	return ds2780_read_block(dev_info->w1_dev, buf,
+	return ds2780_read_block(dev_info, buf,
 				DS2780_EEPROM_BLOCK0_START + off, count);
-
 }
 
 static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
@@ -704,7 +715,7 @@
 		DS2780_EEPROM_BLOCK0_END -
 		DS2780_EEPROM_BLOCK0_START + 1 - off);
 
-	ret = ds2780_write(dev_info->w1_dev, buf,
+	ret = ds2780_write(dev_info, buf,
 				DS2780_EEPROM_BLOCK0_START + off, count);
 	if (ret < 0)
 		return ret;
@@ -768,6 +779,7 @@
 	dev_info->bat.properties	= ds2780_battery_props;
 	dev_info->bat.num_properties	= ARRAY_SIZE(ds2780_battery_props);
 	dev_info->bat.get_property	= ds2780_battery_get_property;
+	dev_info->mutex_holder		= current;
 
 	ret = power_supply_register(&pdev->dev, &dev_info->bat);
 	if (ret) {
@@ -797,6 +809,8 @@
 		goto fail_remove_bin_file;
 	}
 
+	dev_info->mutex_holder = NULL;
+
 	return 0;
 
 fail_remove_bin_file:
@@ -816,6 +830,8 @@
 {
 	struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
 
+	dev_info->mutex_holder = current;
+
 	/* remove attributes */
 	sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 93de829..c275a06 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -16,6 +16,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/errno.h>
+#include <linux/power_supply.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
@@ -25,10 +26,13 @@
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #define BMS_CONTROL		0x224
+#define BMS_S1_DELAY		0x225
 #define BMS_OUTPUT0		0x230
 #define BMS_OUTPUT1		0x231
+#define BMS_TOLERANCES		0x232
 #define BMS_TEST1		0x237
 
 #define ADC_ARB_SECP_CNTRL	0x190
@@ -53,16 +57,20 @@
 };
 
 struct pm8921_soc_params {
+	uint16_t	last_good_ocv_raw;
+	int		cc;
+
+	int		last_good_ocv_uv;
+};
+
+struct pm8921_rbatt_params {
 	uint16_t	ocv_for_rbatt_raw;
 	uint16_t	vsense_for_rbatt_raw;
 	uint16_t	vbatt_for_rbatt_raw;
-	uint16_t	last_good_ocv_raw;
-	int		cc;
 
 	int		ocv_for_rbatt_uv;
 	int		vsense_for_rbatt_uv;
 	int		vbatt_for_rbatt_uv;
-	int		last_good_ocv_uv;
 };
 
 /**
@@ -82,11 +90,14 @@
 	struct single_row_lut	*fcc_temp_lut;
 	struct single_row_lut	*fcc_sf_lut;
 	struct pc_temp_ocv_lut	*pc_temp_ocv_lut;
-	struct pc_sf_lut	*pc_sf_lut;
+	struct sf_lut		*pc_sf_lut;
+	struct sf_lut		*rbatt_sf_lut;
 	struct work_struct	calib_hkadc_work;
 	struct delayed_work	calib_ccadc_work;
 	unsigned int		calib_delay_ms;
 	unsigned int		revision;
+	unsigned int		xoadc_v0625_usb_present;
+	unsigned int		xoadc_v0625_usb_absent;
 	unsigned int		xoadc_v0625;
 	unsigned int		xoadc_v125;
 	unsigned int		batt_temp_channel;
@@ -96,16 +107,21 @@
 	unsigned int		batt_id_channel;
 	unsigned int		pmic_bms_irq[PM_BMS_MAX_INTS];
 	DECLARE_BITMAP(enabled_irqs, PM_BMS_MAX_INTS);
-	spinlock_t		bms_output_lock;
+	struct mutex		bms_output_lock;
 	spinlock_t		bms_100_lock;
 	struct single_row_lut	*adjusted_fcc_temp_lut;
 	unsigned int		charging_began;
 	unsigned int		start_percent;
 	unsigned int		end_percent;
-
+	enum battery_type	batt_type;
 	uint16_t		ocv_reading_at_100;
 	int			cc_reading_at_100;
 	int			max_voltage_uv;
+
+	int			batt_temp_suspend;
+	int			soc_rbatt_suspend;
+	int			default_rbatt_mohm;
+	uint16_t		prev_last_good_ocv_raw;
 };
 
 static struct pm8921_bms_chip *the_chip;
@@ -114,6 +130,9 @@
 #define DEFAULT_OCV_MICROVOLTS		3900000
 #define DEFAULT_CHARGE_CYCLES		0
 
+static int last_usb_cal_delta_uv = 1800;
+module_param(last_usb_cal_delta_uv, int, 0644);
+
 static int last_chargecycles = DEFAULT_CHARGE_CYCLES;
 static int last_charge_increase;
 module_param(last_chargecycles, int, 0644);
@@ -299,6 +318,23 @@
 	return 0;
 }
 
+static int usb_chg_plugged_in(void)
+{
+	union power_supply_propval ret = {0,};
+	static struct power_supply *psy;
+
+	if (psy == NULL) {
+		psy = power_supply_get_by_name("usb");
+		if (psy == NULL)
+			return 0;
+	}
+
+	if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
+		return 0;
+
+	return ret.intval;
+}
+
 #define HOLD_OREG_DATA		BIT(1)
 static int pm_bms_lock_output_data(struct pm8921_bms_chip *chip)
 {
@@ -352,14 +388,6 @@
 		return -EINVAL;
 	}
 
-	/* make sure the bms registers are locked */
-	rc = pm8xxx_readb(chip->dev->parent, BMS_CONTROL, &reg);
-	if (rc) {
-		pr_err("fail to read BMS_OUTPUT0 for type %d rc = %d\n",
-			type, rc);
-		return rc;
-	}
-
 	rc = pm_bms_masked_write(chip, BMS_CONTROL, SELECT_OUTPUT_DATA,
 					type << SELECT_OUTPUT_TYPE_SHIFT);
 	if (rc) {
@@ -401,18 +429,32 @@
 #define XOADC_CALIB_UV		625000
 #define VBATT_MUL_FACTOR	3
 static int adjust_xo_vbatt_reading(struct pm8921_bms_chip *chip,
-							unsigned int uv)
+					int usb_chg, unsigned int uv)
 {
-	u64 numerator, denominator;
+	s64 numerator, denominator;
+	int local_delta;
 
 	if (uv == 0)
 		return 0;
 
-	numerator = ((u64)uv - chip->xoadc_v0625) * XOADC_CALIB_UV;
-	denominator =  chip->xoadc_v125 - chip->xoadc_v0625;
+	/* dont adjust if not calibrated */
+	if (chip->xoadc_v0625 == 0 || chip->xoadc_v125 == 0) {
+		pr_debug("No cal yet return %d\n", VBATT_MUL_FACTOR * uv);
+		return VBATT_MUL_FACTOR * uv;
+	}
+
+	if (usb_chg)
+		local_delta = last_usb_cal_delta_uv;
+	else
+		local_delta = 0;
+
+	pr_debug("using delta = %d\n", local_delta);
+	numerator = ((s64)uv - chip->xoadc_v0625 - local_delta)
+							* XOADC_CALIB_UV;
+	denominator =  (s64)chip->xoadc_v125 - chip->xoadc_v0625 - local_delta;
 	if (denominator == 0)
 		return uv * VBATT_MUL_FACTOR;
-	return (XOADC_CALIB_UV + div_u64(numerator, denominator))
+	return (XOADC_CALIB_UV + local_delta + div_s64(numerator, denominator))
 						* VBATT_MUL_FACTOR;
 }
 
@@ -479,11 +521,12 @@
 }
 
 static int convert_vbatt_raw_to_uv(struct pm8921_bms_chip *chip,
+					int usb_chg,
 					uint16_t reading, int *result)
 {
 	*result = xoadc_reading_to_microvolt(reading);
 	pr_debug("raw = %04x vbatt = %u\n", reading, *result);
-	*result = adjust_xo_vbatt_reading(chip, *result);
+	*result = adjust_xo_vbatt_reading(chip, usb_chg, *result);
 	pr_debug("after adj vbatt = %u\n", *result);
 	return 0;
 }
@@ -581,8 +624,9 @@
 		return 100;
 }
 
-static int interpolate_scalingfactor_pc(struct pm8921_bms_chip *chip,
-				int cycles, int pc)
+static int interpolate_scalingfactor(struct pm8921_bms_chip *chip,
+				struct sf_lut *sf_lut,
+				int row_entry, int pc)
 {
 	int i, scalefactorrow1, scalefactorrow2, scalefactor;
 	int rows, cols;
@@ -593,71 +637,71 @@
 	 * sf table could be null when no battery aging data is available, in
 	 * that case return 100%
 	 */
-	if (!chip->pc_sf_lut)
+	if (!sf_lut)
 		return 100;
 
-	rows = chip->pc_sf_lut->rows;
-	cols = chip->pc_sf_lut->cols;
-	if (pc > chip->pc_sf_lut->percent[0]) {
+	rows = sf_lut->rows;
+	cols = sf_lut->cols;
+	if (pc > sf_lut->percent[0]) {
 		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
 		row1 = 0;
 		row2 = 0;
 	}
-	if (pc < chip->pc_sf_lut->percent[rows - 1]) {
+	if (pc < sf_lut->percent[rows - 1]) {
 		pr_debug("pc %d less than known pc ranges for sf", pc);
 		row1 = rows - 1;
 		row2 = rows - 1;
 	}
 	for (i = 0; i < rows; i++) {
-		if (pc == chip->pc_sf_lut->percent[i]) {
+		if (pc == sf_lut->percent[i]) {
 			row1 = i;
 			row2 = i;
 			break;
 		}
-		if (pc > chip->pc_sf_lut->percent[i]) {
+		if (pc > sf_lut->percent[i]) {
 			row1 = i - 1;
 			row2 = i;
 			break;
 		}
 	}
 
-	if (cycles < chip->pc_sf_lut->cycles[0])
-		cycles = chip->pc_sf_lut->cycles[0];
-	if (cycles > chip->pc_sf_lut->cycles[cols - 1])
-		cycles = chip->pc_sf_lut->cycles[cols - 1];
+	if (row_entry < sf_lut->row_entries[0])
+		row_entry = sf_lut->row_entries[0];
+	if (row_entry > sf_lut->row_entries[cols - 1])
+		row_entry = sf_lut->row_entries[cols - 1];
 
 	for (i = 0; i < cols; i++)
-		if (cycles <= chip->pc_sf_lut->cycles[i])
+		if (row_entry <= sf_lut->row_entries[i])
 			break;
-	if (cycles == chip->pc_sf_lut->cycles[i]) {
+	if (row_entry == sf_lut->row_entries[i]) {
 		scalefactor = linear_interpolate(
-				chip->pc_sf_lut->sf[row1][i],
-				chip->pc_sf_lut->percent[row1],
-				chip->pc_sf_lut->sf[row2][i],
-				chip->pc_sf_lut->percent[row2],
+				sf_lut->sf[row1][i],
+				sf_lut->percent[row1],
+				sf_lut->sf[row2][i],
+				sf_lut->percent[row2],
 				pc);
 		return scalefactor;
 	}
 
 	scalefactorrow1 = linear_interpolate(
-				chip->pc_sf_lut->sf[row1][i - 1],
-				chip->pc_sf_lut->cycles[i - 1],
-				chip->pc_sf_lut->sf[row1][i],
-				chip->pc_sf_lut->cycles[i],
-				cycles);
+				sf_lut->sf[row1][i - 1],
+				sf_lut->row_entries[i - 1],
+				sf_lut->sf[row1][i],
+				sf_lut->row_entries[i],
+				row_entry);
 
 	scalefactorrow2 = linear_interpolate(
-				chip->pc_sf_lut->sf[row2][i - 1],
-				chip->pc_sf_lut->cycles[i - 1],
-				chip->pc_sf_lut->sf[row2][i],
-				chip->pc_sf_lut->cycles[i],
-				cycles);
+				sf_lut->sf[row2][i - 1],
+				sf_lut->row_entries[i - 1],
+				sf_lut->sf[row2][i],
+				sf_lut->row_entries[i],
+				row_entry);
 
 	scalefactor = linear_interpolate(
 				scalefactorrow1,
-				chip->pc_sf_lut->percent[row1],
+				sf_lut->percent[row1],
 				scalefactorrow2,
-				chip->pc_sf_lut->percent[row2],
+				sf_lut->percent[row2],
 				pc);
 
 	return scalefactor;
@@ -774,12 +818,61 @@
 	return 100;
 }
 
-static int read_soc_params_raw(struct pm8921_bms_chip *chip,
-				struct pm8921_soc_params *raw)
+#define BMS_MODE_BIT	BIT(6)
+#define EN_VBAT_BIT	BIT(5)
+#define OVERRIDE_MODE_DELAY_MS	20
+int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+								int *vbat_uv)
 {
-	unsigned long flags;
+	int16_t vsense_raw;
+	int16_t vbat_raw;
+	int vsense_uv;
+	int usb_chg;
 
-	spin_lock_irqsave(&chip->bms_output_lock, flags);
+	if (the_chip == NULL) {
+		pr_err("Called to early\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&the_chip->bms_output_lock);
+
+	pm8xxx_writeb(the_chip->dev->parent, BMS_S1_DELAY, 0x00);
+	pm_bms_masked_write(the_chip, BMS_CONTROL,
+			BMS_MODE_BIT | EN_VBAT_BIT, BMS_MODE_BIT | EN_VBAT_BIT);
+
+	msleep(OVERRIDE_MODE_DELAY_MS);
+
+	pm_bms_lock_output_data(the_chip);
+	pm_bms_read_output_data(the_chip, VSENSE_AVG, &vsense_raw);
+	pm_bms_read_output_data(the_chip, VBATT_AVG, &vbat_raw);
+	pm_bms_unlock_output_data(the_chip);
+	pm_bms_masked_write(the_chip, BMS_CONTROL,
+			BMS_MODE_BIT | EN_VBAT_BIT, 0);
+
+	pm8xxx_writeb(the_chip->dev->parent, BMS_S1_DELAY, 0x0B);
+
+	mutex_unlock(&the_chip->bms_output_lock);
+
+	usb_chg = usb_chg_plugged_in();
+
+	convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv);
+	convert_vsense_to_uv(the_chip, vsense_raw, &vsense_uv);
+	*ibat_ua = vsense_uv * 1000 / (int)the_chip->r_sense;
+
+	pr_debug("vsense_raw = 0x%x vbat_raw = 0x%x"
+			" ibat_ua = %d vbat_uv = %d\n",
+			(uint16_t)vsense_raw, (uint16_t)vbat_raw,
+			*ibat_ua, *vbat_uv);
+	return 0;
+}
+EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+
+static int read_rbatt_params_raw(struct pm8921_bms_chip *chip,
+				struct pm8921_rbatt_params *raw)
+{
+	int usb_chg;
+
+	mutex_lock(&chip->bms_output_lock);
 	pm_bms_lock_output_data(chip);
 
 	pm_bms_read_output_data(chip,
@@ -788,36 +881,94 @@
 			VBATT_FOR_RBATT, &raw->vbatt_for_rbatt_raw);
 	pm_bms_read_output_data(chip,
 			VSENSE_FOR_RBATT, &raw->vsense_for_rbatt_raw);
+
+	pm_bms_unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+
+	usb_chg = usb_chg_plugged_in();
+	convert_vbatt_raw_to_uv(chip, usb_chg,
+			raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
+	convert_vbatt_raw_to_uv(chip, usb_chg,
+			raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
+	convert_vsense_to_uv(chip, raw->vsense_for_rbatt_raw,
+					&raw->vsense_for_rbatt_uv);
+
+	pr_debug("vbatt_for_rbatt_raw = 0x%x, vbatt_for_rbatt= %duV\n",
+			raw->vbatt_for_rbatt_raw, raw->vbatt_for_rbatt_uv);
+	pr_debug("ocv_for_rbatt_raw = 0x%x, ocv_for_rbatt= %duV\n",
+			raw->ocv_for_rbatt_raw, raw->ocv_for_rbatt_uv);
+	pr_debug("vsense_for_rbatt_raw = 0x%x, vsense_for_rbatt= %duV\n",
+			raw->vsense_for_rbatt_raw, raw->vsense_for_rbatt_uv);
+	return 0;
+}
+
+static int read_soc_params_raw(struct pm8921_bms_chip *chip,
+				struct pm8921_soc_params *raw)
+{
+	int usb_chg;
+
+	mutex_lock(&chip->bms_output_lock);
+	pm_bms_lock_output_data(chip);
+
 	pm_bms_read_output_data(chip,
 			LAST_GOOD_OCV_VALUE, &raw->last_good_ocv_raw);
 	read_cc(chip, &raw->cc);
 
 	pm_bms_unlock_output_data(chip);
-	spin_unlock_irqrestore(&chip->bms_output_lock, flags);
+	mutex_unlock(&chip->bms_output_lock);
 
-	convert_vbatt_raw_to_uv(chip,
-			raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
-	convert_vbatt_raw_to_uv(chip,
-			raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
-	convert_vbatt_raw_to_uv(chip,
+	usb_chg =  usb_chg_plugged_in();
+
+	if (chip->prev_last_good_ocv_raw == 0 ||
+		chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
+		chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
+		convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
-	convert_vsense_to_uv(chip,
-			raw->vsense_for_rbatt_raw, &raw->vsense_for_rbatt_uv);
+		last_ocv_uv = raw->last_good_ocv_uv;
+	} else {
+		raw->last_good_ocv_uv = last_ocv_uv;
+	}
 
 	if (raw->last_good_ocv_uv)
 		last_ocv_uv = raw->last_good_ocv_uv;
 
+	pr_debug("0p625 = %duV\n", chip->xoadc_v0625);
+	pr_debug("1p25 = %duV\n", chip->xoadc_v125);
+	pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
+			raw->last_good_ocv_raw, raw->last_good_ocv_uv);
+	pr_debug("cc_raw= 0x%x\n", raw->cc);
 	return 0;
 }
 
-static int calculate_rbatt(struct pm8921_bms_chip *chip,
-				struct pm8921_soc_params *raw)
+static int get_rbatt(struct pm8921_bms_chip *chip, int soc_rbatt, int batt_temp)
+{
+	int rbatt, scalefactor;
+
+	rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+	pr_debug("rbatt before scaling = %d\n", rbatt);
+	if (chip->rbatt_sf_lut == NULL)  {
+		pr_debug("RBATT = %d\n", rbatt);
+		return rbatt;
+	}
+
+	scalefactor = interpolate_scalingfactor(chip, chip->rbatt_sf_lut,
+							batt_temp, soc_rbatt);
+	pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
+				scalefactor, batt_temp, soc_rbatt);
+	rbatt = (rbatt * scalefactor) / 100;
+
+	pr_debug("RBATT = %d\n", rbatt);
+	return rbatt;
+}
+
+static int calculate_rbatt_resume(struct pm8921_bms_chip *chip,
+				struct pm8921_rbatt_params *raw)
 {
 	unsigned int  r_batt;
 
-	if (raw->ocv_for_rbatt_uv == 0
-		|| raw->ocv_for_rbatt_uv == raw->vbatt_for_rbatt_uv
-		|| raw->vsense_for_rbatt_raw == 0) {
+	if (raw->ocv_for_rbatt_uv <= 0
+		|| raw->ocv_for_rbatt_uv <= raw->vbatt_for_rbatt_uv
+		|| raw->vsense_for_rbatt_raw <= 0) {
 		pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
 					"vsen = %d\n",
 					raw->ocv_for_rbatt_uv,
@@ -827,7 +978,6 @@
 	}
 	r_batt = ((raw->ocv_for_rbatt_uv - raw->vbatt_for_rbatt_uv)
 			* chip->r_sense) / raw->vsense_for_rbatt_uv;
-	last_rbatt = r_batt;
 	pr_debug("r_batt = %umilliOhms", r_batt);
 	return r_batt;
 }
@@ -871,7 +1021,6 @@
 static int adc_based_ocv(struct pm8921_bms_chip *chip, int *ocv)
 {
 	int vbatt, rbatt, ibatt_ua, rc;
-	struct pm8921_soc_params raw;
 
 	rc = get_battery_uvolts(chip, &vbatt);
 	if (rc) {
@@ -885,11 +1034,7 @@
 		return rc;
 	}
 
-	read_soc_params_raw(chip, &raw);
-
-	rbatt = calculate_rbatt(the_chip, &raw);
-	if (rbatt < 0)
-		rbatt = (last_rbatt < 0) ? DEFAULT_RBATT_MOHMS : last_rbatt;
+	rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
 	*ocv = vbatt + (ibatt_ua * rbatt)/1000;
 	return 0;
 }
@@ -903,7 +1048,8 @@
 	pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
 					pc, ocv_uv, batt_temp);
 
-	scalefactor = interpolate_scalingfactor_pc(chip, chargecycles, pc);
+	scalefactor = interpolate_scalingfactor(chip,
+					chip->pc_sf_lut, chargecycles, pc);
 	pr_debug("scalefactor = %u batt_temp = %d\n", scalefactor, batt_temp);
 
 	/* Multiply the initial FCC value by the scale factor. */
@@ -940,16 +1086,10 @@
 }
 
 static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
-					struct pm8921_soc_params *raw,
-				 int fcc_uah, int batt_temp, int chargecycles)
+				int rbatt, int fcc_uah,
+				int batt_temp, int chargecycles)
 {
-	int rbatt, voltage_unusable_uv, pc_unusable;
-
-	rbatt = calculate_rbatt(chip, raw);
-	if (rbatt < 0) {
-		rbatt = (last_rbatt < 0) ? DEFAULT_RBATT_MOHMS : last_rbatt;
-		pr_debug("rbatt unavailable assuming %d\n", rbatt);
-	}
+	int voltage_unusable_uv, pc_unusable;
 
 	/* calculate unusable charge */
 	voltage_unusable_uv = (rbatt * chip->i_test)
@@ -999,18 +1139,16 @@
 						int *fcc_uah,
 						int *unusable_charge_uah,
 						int *remaining_charge_uah,
-						int *cc_uah)
+						int *cc_uah,
+						int *rbatt)
 {
 	unsigned long flags;
+	int soc_rbatt;
 
 	*fcc_uah = calculate_fcc_uah(chip, batt_temp, chargecycles);
 	pr_debug("FCC = %uuAh batt_temp = %d, cycles = %d\n",
 					*fcc_uah, batt_temp, chargecycles);
 
-	*unusable_charge_uah = calculate_unusable_charge_uah(chip, raw,
-					*fcc_uah, batt_temp, chargecycles);
-
-	pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
 
 	spin_lock_irqsave(&chip->bms_100_lock, flags);
 	/* calculate remainging charge */
@@ -1025,6 +1163,15 @@
 				(int64_t)raw->cc - chip->cc_reading_at_100,
 				chip->cc_reading_at_100);
 	spin_unlock_irqrestore(&chip->bms_100_lock, flags);
+
+	soc_rbatt = ((*remaining_charge_uah - *cc_uah) * 100) / *fcc_uah;
+	if (soc_rbatt < 0)
+		soc_rbatt = 0;
+	*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
+
+	*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
+					*fcc_uah, batt_temp, chargecycles);
+	pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
 }
 
 static int calculate_real_fcc_uah(struct pm8921_bms_chip *chip,
@@ -1036,12 +1183,14 @@
 	int remaining_charge_uah;
 	int cc_uah;
 	int real_fcc_uah;
+	int rbatt;
 
 	calculate_soc_params(chip, raw, batt_temp, chargecycles,
 						&fcc_uah,
 						&unusable_charge_uah,
 						&remaining_charge_uah,
-						&cc_uah);
+						&cc_uah,
+						&rbatt);
 
 	real_fcc_uah = remaining_charge_uah - cc_uah;
 	*ret_fcc_uah = fcc_uah;
@@ -1063,12 +1212,14 @@
 	int remaining_charge_uah, soc;
 	int update_userspace = 1;
 	int cc_uah;
+	int rbatt;
 
 	calculate_soc_params(chip, raw, batt_temp, chargecycles,
 						&fcc_uah,
 						&unusable_charge_uah,
 						&remaining_charge_uah,
-						&cc_uah);
+						&cc_uah,
+						&rbatt);
 
 	/* calculate remaining usable charge */
 	remaining_usable_charge_uah = remaining_charge_uah
@@ -1076,8 +1227,14 @@
 					- unusable_charge_uah;
 
 	pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
-	soc = (remaining_usable_charge_uah * 100)
-		/ (fcc_uah - unusable_charge_uah);
+	if (fcc_uah - unusable_charge_uah <= 0) {
+		pr_warn("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+						fcc_uah, unusable_charge_uah);
+		soc = 0;
+	} else {
+		soc = (remaining_usable_charge_uah * 100)
+			/ (fcc_uah - unusable_charge_uah);
+	}
 
 	if (soc > 100)
 		soc = 100;
@@ -1123,11 +1280,13 @@
 
 	return soc;
 }
-
+#define MIN_DELTA_625_UV	1000
 static void calib_hkadc(struct pm8921_bms_chip *chip)
 {
 	int voltage, rc;
 	struct pm8xxx_adc_chan_result result;
+	int usb_chg;
+	int this_delta;
 
 	rc = pm8xxx_adc_read(the_chip->ref1p25v_channel, &result);
 	if (rc) {
@@ -1147,10 +1306,30 @@
 		return;
 	}
 	voltage = xoadc_reading_to_microvolt(result.adc_code);
-	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld\n",
-				result.adc_code, voltage, result.measurement);
+
+	usb_chg = usb_chg_plugged_in();
+	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld "
+				"usb_chg = %d\n",
+				result.adc_code, voltage, result.measurement,
+				usb_chg);
+
+	if (usb_chg)
+		chip->xoadc_v0625_usb_present = voltage;
+	else
+		chip->xoadc_v0625_usb_absent = voltage;
 
 	chip->xoadc_v0625 = voltage;
+	if (chip->xoadc_v0625_usb_present && chip->xoadc_v0625_usb_absent) {
+		this_delta = chip->xoadc_v0625_usb_present
+						- chip->xoadc_v0625_usb_absent;
+		pr_debug("this_delta= %duV\n", this_delta);
+		if (this_delta > MIN_DELTA_625_UV)
+			last_usb_cal_delta_uv = this_delta;
+		pr_debug("625V_present= %d, 625V_absent= %d, delta = %duV\n",
+			chip->xoadc_v0625_usb_present,
+			chip->xoadc_v0625_usb_absent,
+			last_usb_cal_delta_uv);
+	}
 }
 
 static void calibrate_hkadc_work(struct work_struct *work)
@@ -1161,12 +1340,18 @@
 	calib_hkadc(chip);
 }
 
+void pm8921_bms_calibrate_hkadc(void)
+{
+	schedule_work(&the_chip->calib_hkadc_work);
+}
+
 static void calibrate_ccadc_work(struct work_struct *work)
 {
 	struct pm8921_bms_chip *chip = container_of(work,
 				struct pm8921_bms_chip, calib_ccadc_work.work);
 
 	pm8xxx_calib_ccadc();
+	calib_hkadc(chip);
 	schedule_delayed_work(&chip->calib_ccadc_work,
 			round_jiffies_relative(msecs_to_jiffies
 			(chip->calib_delay_ms)));
@@ -1175,14 +1360,13 @@
 int pm8921_bms_get_vsense_avg(int *result)
 {
 	int rc = -EINVAL;
-	unsigned long flags;
 
 	if (the_chip) {
-		spin_lock_irqsave(&the_chip->bms_output_lock, flags);
+		mutex_lock(&the_chip->bms_output_lock);
 		pm_bms_lock_output_data(the_chip);
 		rc = read_vsense_avg(the_chip, result);
 		pm_bms_unlock_output_data(the_chip);
-		spin_unlock_irqrestore(&the_chip->bms_output_lock, flags);
+		mutex_unlock(&the_chip->bms_output_lock);
 	}
 
 	pr_err("called before initialization\n");
@@ -1192,7 +1376,6 @@
 
 int pm8921_bms_get_battery_current(int *result_ua)
 {
-	unsigned long flags;
 	int vsense;
 
 	if (!the_chip) {
@@ -1204,15 +1387,15 @@
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&the_chip->bms_output_lock, flags);
+	mutex_lock(&the_chip->bms_output_lock);
 	pm_bms_lock_output_data(the_chip);
 	read_vsense_avg(the_chip, &vsense);
 	pm_bms_unlock_output_data(the_chip);
-	spin_unlock_irqrestore(&the_chip->bms_output_lock, flags);
-	pr_debug("vsense=%d\n", vsense);
+	mutex_unlock(&the_chip->bms_output_lock);
+	pr_debug("vsense=%duV\n", vsense);
 	/* cast for signed division */
 	*result_ua = vsense * 1000 / (int)the_chip->r_sense;
-
+	pr_debug("ibat=%duA\n", *result_ua);
 	return 0;
 }
 EXPORT_SYMBOL(pm8921_bms_get_battery_current);
@@ -1245,6 +1428,44 @@
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
 
+int pm8921_bms_get_rbatt(void)
+{
+	int batt_temp, rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
+	int fcc_uah;
+	int unusable_charge_uah;
+	int remaining_charge_uah;
+	int cc_uah;
+	int rbatt;
+
+	if (!the_chip) {
+		pr_err("called before initialization\n");
+		return -EINVAL;
+	}
+
+	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					the_chip->batt_temp_channel, rc);
+		return rc;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	read_soc_params_raw(the_chip, &raw);
+
+	calculate_soc_params(the_chip, &raw, batt_temp, last_chargecycles,
+						&fcc_uah,
+						&unusable_charge_uah,
+						&remaining_charge_uah,
+						&cc_uah,
+						&rbatt);
+	return rbatt;
+}
+EXPORT_SYMBOL_GPL(pm8921_bms_get_rbatt);
+
 int pm8921_bms_get_fcc(void)
 {
 	int batt_temp, rc;
@@ -1268,6 +1489,10 @@
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
 
+#define IBAT_TOL_MASK		0x0F
+#define OCV_TOL_MASK			0xF0
+#define IBAT_TOL_DEFAULT	0x03
+#define IBAT_TOL_NOCHG		0x0F
 void pm8921_bms_charging_began(void)
 {
 	int batt_temp, rc;
@@ -1291,12 +1516,14 @@
 	bms_start_percent = the_chip->start_percent;
 	bms_start_ocv_uv = raw.last_good_ocv_uv;
 	calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
-
+	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+			IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
 
 #define DELTA_FCC_PERCENT	3
+#define MIN_START_PERCENT_FOR_LEARNING	30
 void pm8921_bms_charging_end(int is_battery_full)
 {
 	int batt_temp, rc;
@@ -1320,7 +1547,8 @@
 
 	calculate_cc_uah(the_chip, raw.cc, &bms_end_cc_uah);
 
-	if (is_battery_full) {
+	if (is_battery_full
+		&& the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
 		unsigned long flags;
 		int fcc_uah, new_fcc_uah, delta_fcc_uah;
 
@@ -1331,18 +1559,25 @@
 		if (delta_fcc_uah < 0)
 			delta_fcc_uah = -delta_fcc_uah;
 
-		if (delta_fcc_uah * 100  <= (DELTA_FCC_PERCENT * fcc_uah)) {
-			pr_debug("delta_fcc=%d < %d percent of fcc=%d\n",
-				delta_fcc_uah, DELTA_FCC_PERCENT, fcc_uah);
-			last_real_fcc_mah = new_fcc_uah/1000;
-			last_real_fcc_batt_temp = batt_temp;
-			readjust_fcc_table();
-		} else {
+		if (delta_fcc_uah * 100  > (DELTA_FCC_PERCENT * fcc_uah)) {
+			/* new_fcc_uah is outside the scope limit it */
+			if (new_fcc_uah > fcc_uah)
+				new_fcc_uah
+				= (fcc_uah + DELTA_FCC_PERCENT * fcc_uah);
+			else
+				new_fcc_uah
+				= (fcc_uah - DELTA_FCC_PERCENT * fcc_uah);
+
 			pr_debug("delta_fcc=%d > %d percent of fcc=%d"
-				"will not update real fcc\n",
-				delta_fcc_uah, DELTA_FCC_PERCENT, fcc_uah);
+					"restring it to %d\n",
+					delta_fcc_uah, DELTA_FCC_PERCENT,
+					fcc_uah, new_fcc_uah);
 		}
 
+		last_real_fcc_mah = new_fcc_uah/1000;
+		last_real_fcc_batt_temp = batt_temp;
+		readjust_fcc_table();
+
 		spin_lock_irqsave(&the_chip->bms_100_lock, flags);
 		the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw;
 		the_chip->cc_reading_at_100 = raw.cc;
@@ -1373,6 +1608,8 @@
 			last_chargecycles);
 	the_chip->start_percent = -EINVAL;
 	the_chip->end_percent = -EINVAL;
+	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+				IBAT_TOL_MASK, IBAT_TOL_NOCHG);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
 
@@ -1501,6 +1738,90 @@
 	return -EINVAL;
 }
 
+static int pm8921_bms_suspend(struct device *dev)
+{
+	int rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+	struct pm8921_soc_params raw;
+	int fcc_uah;
+	int remaining_charge_uah;
+	int cc_uah;
+
+	chip->batt_temp_suspend = 0;
+	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					chip->batt_temp_channel, rc);
+	}
+	chip->batt_temp_suspend = (int)result.physical;
+	read_soc_params_raw(chip, &raw);
+
+	fcc_uah = calculate_fcc_uah(chip,
+			chip->batt_temp_suspend, last_chargecycles);
+	pr_debug("FCC = %uuAh batt_temp = %d, cycles = %d\n",
+			fcc_uah, chip->batt_temp_suspend, last_chargecycles);
+	/* calculate remainging charge */
+	remaining_charge_uah = calculate_remaining_charge_uah(chip, &raw,
+					fcc_uah, chip->batt_temp_suspend,
+					last_chargecycles);
+	pr_debug("RC = %uuAh\n", remaining_charge_uah);
+
+	/* calculate cc micro_volt_hour */
+	calculate_cc_uah(chip, raw.cc, &cc_uah);
+	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %d\n",
+				cc_uah, raw.cc,
+				(int64_t)raw.cc - chip->cc_reading_at_100,
+				chip->cc_reading_at_100);
+	chip->soc_rbatt_suspend = ((remaining_charge_uah - cc_uah) * 100)
+						/ fcc_uah;
+	return 0;
+}
+
+#define DELTA_RBATT_PERCENT	10
+static int pm8921_bms_resume(struct device *dev)
+{
+	struct pm8921_rbatt_params raw;
+	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+	int rbatt;
+	int expected_rbatt;
+	int scalefactor;
+	int delta_rbatt;
+
+	read_rbatt_params_raw(chip, &raw);
+	rbatt = calculate_rbatt_resume(chip, &raw);
+
+	if (rbatt < 0)
+		return 0;
+
+	expected_rbatt
+		= (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+
+	if (chip->rbatt_sf_lut) {
+		scalefactor = interpolate_scalingfactor(chip,
+						chip->rbatt_sf_lut,
+						chip->batt_temp_suspend,
+						chip->soc_rbatt_suspend);
+		rbatt = rbatt * 100 / scalefactor;
+	}
+
+	delta_rbatt = expected_rbatt - rbatt;
+	if (delta_rbatt)
+		delta_rbatt = -delta_rbatt;
+	/*
+	 * only update last_rbatt if rbatt is within some
+	 * percent of expected_rbatt
+	 */
+	if (delta_rbatt * 100 <= DELTA_RBATT_PERCENT * expected_rbatt)
+		last_rbatt = rbatt;
+
+	return 0;
+}
+
+static const struct dev_pm_ops pm8921_pm_ops = {
+	.suspend	= pm8921_bms_suspend,
+	.resume		= pm8921_bms_resume,
+};
 #define EN_BMS_BIT	BIT(7)
 #define EN_PON_HS_BIT	BIT(0)
 static int __devinit pm8921_bms_hw_init(struct pm8921_bms_chip *chip)
@@ -1514,6 +1835,9 @@
 				BMS_CONTROL, rc);
 	}
 
+	/* The charger will call start charge later if usb is present */
+	pm_bms_masked_write(chip, BMS_TOLERANCES,
+				IBAT_TOL_MASK, IBAT_TOL_NOCHG);
 	return 0;
 }
 
@@ -1521,6 +1845,7 @@
 {
 	int ocv_uv, rc;
 	int16_t ocv_raw;
+	int usb_chg;
 
 	/*
 	 * Check if a ocv is available in bms hw,
@@ -1529,7 +1854,8 @@
 	 */
 	ocv_uv = 0;
 	pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
-	rc = convert_vbatt_raw_to_uv(chip, ocv_raw, &ocv_uv);
+	usb_chg = usb_chg_plugged_in();
+	rc = convert_vbatt_raw_to_uv(chip, usb_chg, ocv_raw, &ocv_uv);
 	if (rc || ocv_uv == 0) {
 		rc = adc_based_ocv(chip, &ocv_uv);
 		if (rc) {
@@ -1554,47 +1880,67 @@
 	}
 	pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
 						result.measurement);
-	return result.physical;
+	return result.adc_code;
 }
 
-#define PALLADIUM_ID_MIN  2500
-#define PALLADIUM_ID_MAX  4000
+#define PALLADIUM_ID_MIN	0x7F40
+#define PALLADIUM_ID_MAX	0x7F5A
+#define DESAY_5200_ID_MIN	0x7F7F
+#define DESAY_5200_ID_MAX	0x802F
 static int set_battery_data(struct pm8921_bms_chip *chip)
 {
 	int64_t battery_id;
 
-	battery_id = read_battery_id(chip);
+	if (chip->batt_type == BATT_DESAY)
+		goto desay;
+	else if (chip->batt_type == BATT_PALLADIUM)
+		goto palladium;
 
+	battery_id = read_battery_id(chip);
 	if (battery_id < 0) {
 		pr_err("cannot read battery id err = %lld\n", battery_id);
 		return battery_id;
 	}
 
 	if (is_between(PALLADIUM_ID_MIN, PALLADIUM_ID_MAX, battery_id)) {
-		chip->fcc = palladium_1500_data.fcc;
-		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
-		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
-		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
-		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
-		return 0;
+		goto palladium;
+	} else if (is_between(DESAY_5200_ID_MIN, DESAY_5200_ID_MAX,
+				battery_id)) {
+		goto desay;
 	} else {
-		pr_warn("invalid battery id, palladium 1500 assumed\n");
+		pr_warn("invalid battid, palladium 1500 assumed batt_id %llx\n",
+				battery_id);
+		goto palladium;
+	}
+
+palladium:
 		chip->fcc = palladium_1500_data.fcc;
 		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
 		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
 		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
 		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
+		chip->rbatt_sf_lut = palladium_1500_data.rbatt_sf_lut;
+		chip->default_rbatt_mohm
+				= palladium_1500_data.default_rbatt_mohm;
 		return 0;
-	}
+desay:
+		chip->fcc = desay_5200_data.fcc;
+		chip->fcc_temp_lut = desay_5200_data.fcc_temp_lut;
+		chip->pc_temp_ocv_lut = desay_5200_data.pc_temp_ocv_lut;
+		chip->pc_sf_lut = desay_5200_data.pc_sf_lut;
+		chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut;
+		chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
+		return 0;
 }
 
-enum {
+enum bms_request_operation {
 	CALC_RBATT,
 	CALC_FCC,
 	CALC_PC,
 	CALC_SOC,
 	CALIB_HKADC,
 	CALIB_CCADC,
+	GET_VBAT_VSENSE_SIMULTANEOUS,
 };
 
 static int test_batt_temp = 5;
@@ -1645,16 +1991,19 @@
 {
 	int param = (int)data;
 	int ret = 0;
+	int ibat_ua, vbat_uv;
 	struct pm8921_soc_params raw;
+	struct pm8921_rbatt_params rraw;
 
 	read_soc_params_raw(the_chip, &raw);
+	read_rbatt_params_raw(the_chip, &rraw);
 
 	*val = 0;
 
 	/* global irq number passed in via data */
 	switch (param) {
 	case CALC_RBATT:
-		*val = calculate_rbatt(the_chip, &raw);
+		*val = calculate_rbatt_resume(the_chip, &rraw);
 		break;
 	case CALC_FCC:
 		*val = calculate_fcc_uah(the_chip, test_batt_temp,
@@ -1678,6 +2027,13 @@
 		*val = 0;
 		pm8xxx_calib_ccadc();
 		break;
+	case GET_VBAT_VSENSE_SIMULTANEOUS:
+		/* reading this will call simultaneous vbat and vsense */
+		*val =
+		pm8921_bms_get_simultaneous_battery_voltage_and_current(
+			&ibat_ua,
+			&vbat_uv);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -1690,12 +2046,13 @@
 	int param = (int)data;
 	int ret = 0;
 	struct pm8921_soc_params raw;
+	struct pm8921_rbatt_params rraw;
 
 	read_soc_params_raw(the_chip, &raw);
+	read_rbatt_params_raw(the_chip, &rraw);
 
 	*val = 0;
 
-	/* global irq number passed in via data */
 	switch (param) {
 	case CC_MSB:
 	case CC_LSB:
@@ -1705,13 +2062,13 @@
 		*val = raw.last_good_ocv_uv;
 		break;
 	case VBATT_FOR_RBATT:
-		*val = raw.vbatt_for_rbatt_uv;
+		*val = rraw.vbatt_for_rbatt_uv;
 		break;
 	case VSENSE_FOR_RBATT:
-		*val = raw.vsense_for_rbatt_uv;
+		*val = rraw.vsense_for_rbatt_uv;
 		break;
 	case OCV_FOR_RBATT:
-		*val = raw.ocv_for_rbatt_uv;
+		*val = rraw.ocv_for_rbatt_uv;
 		break;
 	case VSENSE_AVG:
 		read_vsense_avg(the_chip, (uint *)val);
@@ -1821,6 +2178,9 @@
 	debugfs_create_file("calib_ccadc", 0644, chip->dent,
 				(void *)CALIB_CCADC, &calc_fops);
 
+	debugfs_create_file("simultaneous", 0644, chip->dent,
+			(void *)GET_VBAT_VSENSE_SIMULTANEOUS, &calc_fops);
+
 	for (i = 0; i < ARRAY_SIZE(bms_irq_data); i++) {
 		if (chip->pmic_bms_irq[bms_irq_data[i].irq_id])
 			debugfs_create_file(bms_irq_data[i].name, 0444,
@@ -1848,7 +2208,7 @@
 		pr_err("Cannot allocate pm_bms_chip\n");
 		return -ENOMEM;
 	}
-	spin_lock_init(&chip->bms_output_lock);
+	mutex_init(&chip->bms_output_lock);
 	spin_lock_init(&chip->bms_100_lock);
 	chip->dev = &pdev->dev;
 	chip->r_sense = pdata->r_sense;
@@ -1856,6 +2216,7 @@
 	chip->v_failure = pdata->v_failure;
 	chip->calib_delay_ms = pdata->calib_delay_ms;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
+	chip->batt_type = pdata->battery_type;
 	chip->start_percent = -EINVAL;
 	chip->end_percent = -EINVAL;
 	rc = set_battery_data(chip);
@@ -1864,6 +2225,16 @@
 		goto free_chip;
 	}
 
+	if (chip->pc_temp_ocv_lut == NULL) {
+		pr_err("temp ocv lut table is NULL\n");
+		rc = -EINVAL;
+		goto free_chip;
+	}
+
+	/* set defaults in the battery data */
+	if (chip->default_rbatt_mohm <= 0)
+		chip->default_rbatt_mohm = DEFAULT_RBATT_MOHMS;
+
 	chip->batt_temp_channel = pdata->bms_cdata.batt_temp_channel;
 	chip->vbat_channel = pdata->bms_cdata.vbat_channel;
 	chip->ref625mv_channel = pdata->bms_cdata.ref625mv_channel;
@@ -1932,6 +2303,7 @@
 	.driver	= {
 		.name	= PM8921_BMS_DEV_NAME,
 		.owner	= THIS_MODULE,
+		.pm	= &pm8921_pm_ops
 	},
 };
 
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index aca724a..1454ca9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -256,15 +256,24 @@
 	int				thermal_levels;
 	struct delayed_work		update_heartbeat_work;
 	struct delayed_work		eoc_work;
-	struct delayed_work		unplug_wrkarnd_restore_work;
+	struct work_struct		unplug_ovp_fet_open_work;
 	struct delayed_work		unplug_check_work;
-	struct wake_lock		unplug_wrkarnd_restore_wake_lock;
+	struct delayed_work		vin_collapse_check_work;
 	struct wake_lock		eoc_wake_lock;
 	enum pm8921_chg_cold_thr	cold_thr;
 	enum pm8921_chg_hot_thr		hot_thr;
+	int				rconn_mohm;
+	enum pm8921_chg_led_src_config	led_src_config;
 };
 
-static int usb_max_current;
+/* user space parameter to limit usb current */
+static unsigned int usb_max_current;
+/*
+ * usb_target_ma is used for wall charger
+ * adaptive input current limiting only. Use
+ * pm_iusbmax_get() to get current maximum usb current setting.
+ */
+static int usb_target_ma;
 static int charging_disabled;
 static int thermal_mitigation;
 
@@ -415,25 +424,37 @@
 				disable ? CHG_CHARGE_DIS_BIT : 0);
 }
 
+static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
+{
+	u8 temp;
+
+	pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
+	return  temp & CHG_CHARGE_DIS_BIT;
+}
 #define PM8921_CHG_V_MIN_MV	3240
 #define PM8921_CHG_V_STEP_MV	20
-#define PM8921_CHG_V_STEP_10_MV_BIT	BIT(7)
+#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT	BIT(7)
 #define PM8921_CHG_VDDMAX_MAX	4500
 #define PM8921_CHG_VDDMAX_MIN	3400
 #define PM8921_CHG_V_MASK	0x7F
 static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
 {
-	int remainder, voltage_20_step;
+	int remainder;
 	u8 temp = 0;
 
-	voltage_20_step = voltage;
-	remainder = voltage % 20;
-	if (remainder >= 10) {
-		voltage_20_step += 10;
-		temp = PM8921_CHG_V_STEP_10_MV_BIT;
+	if (voltage < PM8921_CHG_VDDMAX_MIN
+			|| voltage > PM8921_CHG_VDDMAX_MAX) {
+		pr_err("bad mV=%d asked to set\n", voltage);
+		return -EINVAL;
 	}
 
-	temp |= (voltage_20_step - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
+	temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
+
+	remainder = voltage % 20;
+	if (remainder >= 10) {
+		temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
+	}
+
 	pr_debug("voltage=%d setting %02x\n", voltage, temp);
 	return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
 }
@@ -449,10 +470,10 @@
 		*voltage = 0;
 		return rc;
 	}
-	temp &= PM8921_CHG_V_MASK;
-	*voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
-	if (temp & PM8921_CHG_V_STEP_10_MV_BIT)
-		*voltage = *voltage - 10;
+	*voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
+							+ PM8921_CHG_V_MIN_MV;
+	if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
+		*voltage =  *voltage + 10;
 	return 0;
 }
 
@@ -637,18 +658,17 @@
 
 struct usb_ma_limit_entry {
 	int usb_ma;
-	u8  chg_iusb_value;
 };
 
 static struct usb_ma_limit_entry usb_ma_table[] = {
-	{100, 0},
-	{500, 1},
-	{700, 2},
-	{850, 3},
-	{900, 4},
-	{1100, 5},
-	{1300, 6},
-	{1500, 7},
+	{100},
+	{500},
+	{700},
+	{850},
+	{900},
+	{1100},
+	{1300},
+	{1500},
 };
 
 #define PM8921_CHG_IUSB_MASK 0x1C
@@ -670,7 +690,7 @@
 static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
 {
 	u8 temp;
-	int i, rc;
+	int rc;
 
 	*mA = 0;
 	rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
@@ -680,10 +700,7 @@
 	}
 	temp &= PM8921_CHG_IUSB_MASK;
 	temp = temp >> 2;
-	for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
-		if (usb_ma_table[i].chg_iusb_value == temp)
-			*mA = usb_ma_table[i].usb_ma;
-	}
+	*mA = usb_ma_table[temp].usb_ma;
 	return rc;
 }
 
@@ -841,6 +858,76 @@
 					 temp);
 }
 
+#define PM8921_CHG_LED_SRC_CONFIG_SHIFT	4
+#define PM8921_CHG_LED_SRC_CONFIG_MASK	0x30
+static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
+				enum pm8921_chg_led_src_config led_src_config)
+{
+	u8 temp;
+
+	if (led_src_config < LED_SRC_GND ||
+			led_src_config > LED_SRC_BYPASS)
+		return -EINVAL;
+
+	if (led_src_config == LED_SRC_BYPASS)
+		return 0;
+
+	temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
+
+	return pm_chg_masked_write(chip, CHG_CNTRL_3,
+					PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
+}
+
+static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
+{
+	u8 temp;
+	int rc;
+
+	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
+	if (rc) {
+		pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
+		return;
+	}
+	rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
+	if (rc) {
+		pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
+		return;
+	}
+	/* set the input voltage disable bit and the write bit */
+	temp |= 0x81;
+	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
+	if (rc) {
+		pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
+		return;
+	}
+}
+
+static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
+{
+	u8 temp;
+	int rc;
+
+	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
+	if (rc) {
+		pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
+		return;
+	}
+	rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
+	if (rc) {
+		pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
+		return;
+	}
+	/* unset the input voltage disable bit */
+	temp &= 0xFE;
+	/* set the write bit */
+	temp |= 0x80;
+	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
+	if (rc) {
+		pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
+		return;
+	}
+}
+
 static int64_t read_battery_id(struct pm8921_chg_chip *chip)
 {
 	int rc;
@@ -989,7 +1076,13 @@
 	}
 }
 
-static enum power_supply_property pm_power_props[] = {
+static enum power_supply_property pm_power_props_usb[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static enum power_supply_property pm_power_props_mains[] = {
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
 };
@@ -999,7 +1092,50 @@
 };
 
 #define USB_WALL_THRESHOLD_MA	500
-static int pm_power_get_property(struct power_supply *psy,
+static int pm_power_get_property_mains(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  union power_supply_propval *val)
+{
+	/* Check if called before init */
+	if (!the_chip)
+		return -EINVAL;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = 0;
+		if (charging_disabled)
+			return 0;
+
+		/* check external charger first before the dc path */
+		if (is_ext_charging(the_chip)) {
+			val->intval = 1;
+			return 0;
+		}
+
+		if (pm_is_chg_charge_dis(the_chip)) {
+			val->intval = 0;
+			return 0;
+		}
+
+		if (the_chip->dc_present) {
+			val->intval = 1;
+			return 0;
+		}
+
+		/* USB with max current greater than 500 mA connected */
+		if (usb_target_ma > USB_WALL_THRESHOLD_MA)
+			val->intval = is_usb_chg_plugged_in(the_chip);
+			return 0;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int pm_power_get_property_usb(struct power_supply *psy,
 				  enum power_supply_property psp,
 				  union power_supply_propval *val)
 {
@@ -1011,8 +1147,12 @@
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_CURRENT_MAX:
-		pm_chg_iusbmax_get(the_chip, &current_max);
-		val->intval = current_max;
+		if (pm_is_chg_charge_dis(the_chip)) {
+			val->intval = 0;
+		} else {
+			pm_chg_iusbmax_get(the_chip, &current_max);
+			val->intval = current_max;
+		}
 		break;
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_ONLINE:
@@ -1020,30 +1160,15 @@
 		if (charging_disabled)
 			return 0;
 
+		/*
+		 * if drawing any current from usb is disabled behave
+		 * as if no usb cable is connected
+		 */
+		if (pm_is_chg_charge_dis(the_chip))
+			return 0;
+
 		/* USB charging */
-		if (psy->type == POWER_SUPPLY_TYPE_USB ||
-				psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
-				psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
-				psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
-			val->intval = is_usb_chg_plugged_in(the_chip);
-			return 0;
-		}
-
-		/* DC charging */
-		if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
-			/* external charger is connected */
-			if (the_chip->dc_present || is_ext_charging(the_chip)) {
-				val->intval = 1;
-				return 0;
-			}
-			/* USB with max current greater than 500 mA connected */
-			pm_chg_iusbmax_get(the_chip, &current_max);
-			if (current_max > USB_WALL_THRESHOLD_MA)
-				val->intval = is_usb_chg_plugged_in(the_chip);
-			return 0;
-		}
-
-		pr_err("Unkown POWER_SUPPLY_TYPE %d\n", psy->type);
+		val->intval = is_usb_chg_plugged_in(the_chip);
 		break;
 	default:
 		return -EINVAL;
@@ -1318,19 +1443,11 @@
 {
 	int i, rc;
 
-	if (usb_max_current && mA > usb_max_current) {
-		pr_warn("restricting usb current to %d instead of %d\n",
-					usb_max_current, mA);
-		mA = usb_max_current;
-	}
-
 	if (mA > 0 && mA <= 2) {
 		usb_chg_current = 0;
-		rc = pm_chg_iusbmax_set(the_chip,
-				usb_ma_table[0].chg_iusb_value);
+		rc = pm_chg_iusbmax_set(the_chip, 0);
 		if (rc) {
-			pr_err("unable to set iusb to %d rc = %d\n",
-				usb_ma_table[0].chg_iusb_value, rc);
+			pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
 		}
 		rc = pm_chg_usb_suspend_enable(the_chip, 1);
 		if (rc)
@@ -1345,11 +1462,9 @@
 		}
 		if (i < 0)
 			i = 0;
-		rc = pm_chg_iusbmax_set(the_chip,
-				usb_ma_table[i].chg_iusb_value);
+		rc = pm_chg_iusbmax_set(the_chip, i);
 		if (rc) {
-			pr_err("unable to set iusb to %d rc = %d\n",
-				usb_ma_table[i].chg_iusb_value, rc);
+			pr_err("unable to set iusb to %d rc = %d\n", i, rc);
 		}
 	}
 }
@@ -1360,15 +1475,30 @@
 	unsigned long flags;
 
 	pr_debug("Enter charge=%d\n", mA);
+
+	if (usb_max_current && mA > usb_max_current) {
+		pr_warn("restricting usb current to %d instead of %d\n",
+					usb_max_current, mA);
+		mA = usb_max_current;
+	}
+	if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
+		usb_target_ma = mA;
+
 	spin_lock_irqsave(&vbus_lock, flags);
 	if (the_chip) {
-		__pm8921_charger_vbus_draw(mA);
+		if (mA > USB_WALL_THRESHOLD_MA)
+			__pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
+		else
+			__pm8921_charger_vbus_draw(mA);
 	} else {
 		/*
 		 * called before pmic initialized,
 		 * save this value and use it at probe
 		 */
-		usb_chg_current = mA;
+		if (mA > USB_WALL_THRESHOLD_MA)
+			usb_chg_current = USB_WALL_THRESHOLD_MA;
+		else
+			usb_chg_current = mA;
 	}
 	spin_unlock_irqrestore(&vbus_lock, flags);
 }
@@ -1582,23 +1712,6 @@
 }
 EXPORT_SYMBOL(pm8921_is_battery_charging);
 
-int pm8921_set_usb_power_supply_type(enum power_supply_type type)
-{
-	if (!the_chip) {
-		pr_err("called before init\n");
-		return -EINVAL;
-	}
-
-	if (type < POWER_SUPPLY_TYPE_USB)
-		return -EINVAL;
-
-	the_chip->usb_psy.type = type;
-	power_supply_changed(&the_chip->usb_psy);
-	power_supply_changed(&the_chip->dc_psy);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
-
 int pm8921_batt_temperature(void)
 {
 	if (!the_chip) {
@@ -1612,18 +1725,26 @@
 {
 	int usb_present;
 
+	pm_chg_failed_clear(chip, 1);
 	usb_present = is_usb_chg_plugged_in(chip);
 	if (chip->usb_present ^ usb_present) {
 		notify_usb_of_the_plugin_event(usb_present);
 		chip->usb_present = usb_present;
 		power_supply_changed(&chip->usb_psy);
 		power_supply_changed(&chip->batt_psy);
+		pm8921_bms_calibrate_hkadc();
 	}
 	if (usb_present) {
 		schedule_delayed_work(&chip->unplug_check_work,
 			round_jiffies_relative(msecs_to_jiffies
 				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+		pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
+	} else {
+		/* USB unplugged reset target current */
+		usb_target_ma = 0;
+		pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
 	}
+	enable_input_voltage_regulation(chip);
 	bms_notify_check(chip);
 }
 
@@ -1702,30 +1823,163 @@
 	wake_lock(&chip->eoc_wake_lock);
 }
 
-#define WRITE_BANK_4		0xC0
-static void unplug_wrkarnd_restore_worker(struct work_struct *work)
+static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
 {
 	u8 temp;
 	int rc;
+
+	rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
+	if (rc) {
+		pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
+		return;
+	}
+	rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
+	if (rc) {
+		pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
+		return;
+	}
+	/* set ovp fet disable bit and the write bit */
+	temp |= 0x81;
+	rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
+	if (rc) {
+		pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
+		return;
+	}
+}
+
+static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
+{
+	u8 temp;
+	int rc;
+
+	rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
+	if (rc) {
+		pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
+		return;
+	}
+	rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
+	if (rc) {
+		pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
+		return;
+	}
+	/* unset ovp fet disable bit and set the write bit */
+	temp &= 0xFE;
+	temp |= 0x80;
+	rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
+	if (rc) {
+		pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
+								temp, rc);
+		return;
+	}
+}
+
+static int param_open_ovp_counter = 10;
+module_param(param_open_ovp_counter, int, 0644);
+
+#define WRITE_BANK_4		0xC0
+#define USB_OVP_DEBOUNCE_TIME 0x06
+static void unplug_ovp_fet_open_worker(struct work_struct *work)
+{
+	struct pm8921_chg_chip *chip = container_of(work,
+				struct pm8921_chg_chip,
+				unplug_ovp_fet_open_work);
+	int chg_gone, usb_chg_plugged_in;
+	int count = 0;
+
+	while (count++ < param_open_ovp_counter) {
+		pm_chg_masked_write(chip, USB_OVP_CONTROL,
+						USB_OVP_DEBOUNCE_TIME, 0x0);
+		usleep(10);
+		usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
+		chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
+		pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
+					count, chg_gone, usb_chg_plugged_in);
+
+		/* note usb_chg_plugged_in=0 => chg_gone=1 */
+		if (chg_gone == 1 && usb_chg_plugged_in == 1) {
+			pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
+			turn_off_usb_ovp_fet(chip);
+
+			msleep(20);
+
+			turn_on_usb_ovp_fet(chip);
+		} else {
+			break;
+		}
+	}
+	pm_chg_masked_write(chip, USB_OVP_CONTROL,
+		USB_OVP_DEBOUNCE_TIME, 0x2);
+	pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
+		count, chg_gone, usb_chg_plugged_in);
+	return;
+}
+
+static int find_usb_ma_value(int value)
+{
+	int i;
+
+	for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
+		if (value >= usb_ma_table[i].usb_ma)
+			break;
+	}
+
+	return i;
+}
+
+static void decrease_usb_ma_value(int *value)
+{
+	int i;
+
+	if (value) {
+		i = find_usb_ma_value(*value);
+		if (i > 0)
+			i--;
+		*value = usb_ma_table[i].usb_ma;
+	}
+}
+
+static void increase_usb_ma_value(int *value)
+{
+	int i;
+
+	if (value) {
+		i = find_usb_ma_value(*value);
+
+		if (i < (ARRAY_SIZE(usb_ma_table) - 1))
+			i++;
+		*value = usb_ma_table[i].usb_ma;
+	}
+}
+
+static void vin_collapse_check_worker(struct work_struct *work)
+{
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct pm8921_chg_chip *chip = container_of(dwork,
-				struct pm8921_chg_chip,
-				unplug_wrkarnd_restore_work);
+			struct pm8921_chg_chip, vin_collapse_check_work);
 
-	pr_debug("restoring vin_min to %d mV\n", chip->vin_min);
-	rc = pm_chg_vinmin_set(the_chip, chip->vin_min);
-
-	temp = WRITE_BANK_4 | 0xA;
-	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
-	if (rc) {
-		pr_err("Error %d writing %d to addr %d\n", rc,
-					temp, CHG_BUCK_CTRL_TEST3);
+	/* AICL only for wall-chargers */
+	if (is_usb_chg_plugged_in(chip) &&
+		usb_target_ma > USB_WALL_THRESHOLD_MA) {
+		/* decrease usb_target_ma */
+		decrease_usb_ma_value(&usb_target_ma);
+		/* reset here, increase in unplug_check_worker */
+		__pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
+		pr_debug("usb_now=%d, usb_target = %d\n",
+				USB_WALL_THRESHOLD_MA, usb_target_ma);
+	} else {
+		handle_usb_insertion_removal(chip);
 	}
-	wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock);
 }
+
+#define VIN_MIN_COLLAPSE_CHECK_MS	50
 static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
 {
-	handle_usb_insertion_removal(data);
+	if (usb_target_ma)
+		schedule_delayed_work(&the_chip->vin_collapse_check_work,
+				      round_jiffies_relative(msecs_to_jiffies
+						(VIN_MIN_COLLAPSE_CHECK_MS)));
+	else
+	    handle_usb_insertion_removal(data);
 	return IRQ_HANDLED;
 }
 
@@ -1799,8 +2053,7 @@
 
 static irqreturn_t vcp_irq_handler(int irq, void *data)
 {
-	pr_warning("VCP triggered BATDET forced on\n");
-	pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
+	pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
 	return IRQ_HANDLED;
 }
 
@@ -1867,6 +2120,29 @@
 	return IRQ_HANDLED;
 }
 
+static int param_vin_disable_counter = 5;
+module_param(param_vin_disable_counter, int, 0644);
+
+static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
+							int count, int usb_ma)
+{
+	__pm8921_charger_vbus_draw(500);
+	pr_debug("count = %d iusb=500mA\n", count);
+	disable_input_voltage_regulation(chip);
+	pr_debug("count = %d disable_input_regulation\n", count);
+
+	msleep(20);
+
+	pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
+				count,
+				pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
+				is_usb_chg_plugged_in(chip));
+	pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
+		 count, usb_ma);
+	enable_input_voltage_regulation(chip);
+	__pm8921_charger_vbus_draw(usb_ma);
+}
+
 #define VIN_ACTIVE_BIT BIT(0)
 #define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
 #define VIN_MIN_INCREASE_MV 100
@@ -1876,8 +2152,10 @@
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, unplug_check_work);
 	u8 reg_loop;
-	int ibat, usb_chg_plugged_in;
+	int ibat, usb_chg_plugged_in, usb_ma;
+	int chg_gone = 0;
 
+	reg_loop = 0;
 	usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
 	if (!usb_chg_plugged_in) {
 		pr_debug("Stopping Unplug Check Worker since USB is removed"
@@ -1888,8 +2166,37 @@
 			);
 		return;
 	}
+
+	pm_chg_iusbmax_get(chip, &usb_ma);
+	if (usb_ma == 500 && !usb_target_ma) {
+		pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
+		disable_input_voltage_regulation(chip);
+		return;
+	}
+
+	if (usb_ma <= 100) {
+		pr_debug(
+			"Unenumerated yet or suspended usb_ma = %d skipping\n",
+			usb_ma);
+		goto check_again_later;
+	}
+	if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
+		pr_debug("chg gone irq is enabled\n");
+
 	reg_loop = pm_chg_get_regulation_loop(chip);
-	pr_debug("reg_loop=0x%x\n", reg_loop);
+	pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
+
+	if (reg_loop & VIN_ACTIVE_BIT) {
+		decrease_usb_ma_value(&usb_ma);
+		usb_target_ma = usb_ma;
+		/* end AICL here */
+		__pm8921_charger_vbus_draw(usb_ma);
+		pr_debug("usb_now=%d, usb_target = %d\n",
+			usb_ma, usb_target_ma);
+	}
+
+	reg_loop = pm_chg_get_regulation_loop(chip);
+	pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
 
 	if (reg_loop & VIN_ACTIVE_BIT) {
 		ibat = get_prop_batt_current(chip);
@@ -1897,28 +2204,40 @@
 		pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
 				ibat, pm_chg_get_fsm_state(chip), reg_loop);
 		if (ibat > 0) {
-			int err;
-			u8 temp;
+			int count = 0;
 
-			temp = WRITE_BANK_4 | 0xE;
-			err = pm8xxx_writeb(chip->dev->parent,
-						CHG_BUCK_CTRL_TEST3, temp);
-			if (err) {
-				pr_err("Error %d writing %d to addr %d\n", err,
-						temp, CHG_BUCK_CTRL_TEST3);
+			while (count++ < param_vin_disable_counter
+					&& usb_chg_plugged_in == 1) {
+				attempt_reverse_boost_fix(chip, count, usb_ma);
+				usb_chg_plugged_in
+					= is_usb_chg_plugged_in(chip);
 			}
-
-			pm_chg_vinmin_set(chip,
-					chip->vin_min + VIN_MIN_INCREASE_MV);
-
-			wake_lock(&chip->unplug_wrkarnd_restore_wake_lock);
-			schedule_delayed_work(
-				&chip->unplug_wrkarnd_restore_work,
-				round_jiffies_relative(usecs_to_jiffies
-				(UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US)));
 		}
 	}
 
+	usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
+	chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
+
+	if (chg_gone == 1  && usb_chg_plugged_in == 1) {
+		/* run the worker directly */
+		pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
+						chg_gone, usb_chg_plugged_in);
+		schedule_work(&chip->unplug_ovp_fet_open_work);
+	}
+
+	if (!(reg_loop & VIN_ACTIVE_BIT)) {
+		/* only increase iusb_max if vin loop not active */
+		if (usb_ma < usb_target_ma) {
+			increase_usb_ma_value(&usb_ma);
+			__pm8921_charger_vbus_draw(usb_ma);
+			pr_debug("usb_now=%d, usb_target = %d\n",
+					usb_ma, usb_target_ma);
+		} else {
+			usb_target_ma = usb_ma;
+		}
+	}
+check_again_later:
+	/* schedule to check again later */
 	schedule_delayed_work(&chip->unplug_check_work,
 		      round_jiffies_relative(msecs_to_jiffies
 				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
@@ -1931,7 +2250,7 @@
 	pr_debug("fsm_state=%d reg_loop=0x%x\n",
 		pm_chg_get_fsm_state(data),
 		pm_chg_get_regulation_loop(data));
-	unplug_check_worker(&(chip->unplug_check_work.work));
+	schedule_work(&chip->unplug_check_work.work);
 	return IRQ_HANDLED;
 }
 
@@ -2008,8 +2327,23 @@
 static irqreturn_t chg_gone_irq_handler(int irq, void *data)
 {
 	struct pm8921_chg_chip *chip = data;
+	u8 reg;
+	int rc, chg_gone, usb_chg_plugged_in;
 
+	usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
+	chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
+
+	pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
 	pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
+
+	rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL_3, &reg);
+	if (rc)
+		pr_err("Failed to read CHG_CNTRL_3 rc=%d\n", rc);
+
+	if (reg & CHG_USB_SUSPEND_BIT)
+		return IRQ_HANDLED;
+	schedule_work(&chip->unplug_ovp_fet_open_work);
+
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
 	return IRQ_HANDLED;
@@ -2153,11 +2487,86 @@
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, update_heartbeat_work);
 
+	pm_chg_failed_clear(chip, 1);
 	power_supply_changed(&chip->batt_psy);
 	schedule_delayed_work(&chip->update_heartbeat_work,
 			      round_jiffies_relative(msecs_to_jiffies
 						     (chip->update_time)));
 }
+#define VDD_LOOP_ACTIVE_BIT	BIT(3)
+#define VDD_MAX_INCREASE_MV	400
+static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
+module_param(vdd_max_increase_mv, int, 0644);
+
+static int ichg_threshold_ua = -400000;
+module_param(ichg_threshold_ua, int, 0644);
+static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
+{
+	int ichg_meas_ua, vbat_uv;
+	int ichg_meas_ma;
+	int adj_vdd_max_mv, programmed_vdd_max;
+	int vbat_batt_terminal_uv;
+	int vbat_batt_terminal_mv;
+	int reg_loop;
+	int delta_mv = 0;
+
+	if (chip->rconn_mohm == 0) {
+		pr_debug("Exiting as rconn_mohm is 0\n");
+		return;
+	}
+	/* adjust vdd_max only in normal temperature zone */
+	if (chip->is_bat_cool || chip->is_bat_warm) {
+		pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
+				chip->is_bat_cool, chip->is_bat_warm);
+		return;
+	}
+
+	reg_loop = pm_chg_get_regulation_loop(chip);
+	if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
+		pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
+			reg_loop);
+		return;
+	}
+
+	pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
+								&vbat_uv);
+	if (ichg_meas_ua >= 0) {
+		pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
+		return;
+	}
+	if (ichg_meas_ua <= ichg_threshold_ua) {
+		pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
+					ichg_meas_ua, ichg_threshold_ua);
+		return;
+	}
+	ichg_meas_ma = ichg_meas_ua / 1000;
+
+	/* rconn_mohm is in milliOhms */
+	vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
+	vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
+	pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
+
+	delta_mv =  chip->max_voltage_mv - vbat_batt_terminal_mv;
+
+	adj_vdd_max_mv = programmed_vdd_max + delta_mv;
+	pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
+			delta_mv,
+			programmed_vdd_max,
+			adj_vdd_max_mv);
+
+	if (adj_vdd_max_mv < chip->max_voltage_mv) {
+		pr_debug("adj vdd_max lower than default max voltage\n");
+		return;
+	}
+
+	if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
+		adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
+
+	pr_debug("adjusting vdd_max_mv to %d to make "
+		"vbat_batt_termial_uv = %d to %d\n",
+		adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
+	pm_chg_vddmax_set(chip, adj_vdd_max_mv);
+}
 
 enum {
 	CHG_IN_PROGRESS,
@@ -2211,8 +2620,6 @@
 		}
 		pr_debug("vddmax = %d vbat_meas_mv=%d\n",
 			 vbat_programmed, vbat_meas_mv);
-		if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
-			return CHG_IN_PROGRESS;
 
 		if (last_vbat_programmed == -EINVAL)
 			last_vbat_programmed = vbat_programmed;
@@ -2224,10 +2631,6 @@
 			return CHG_IN_PROGRESS;
 		}
 
-		/*
-		 * TODO if charging from an external charger
-		 * check SOC instead of regulation loop
-		 */
 		regulation_loop = pm_chg_get_regulation_loop(chip);
 		if (regulation_loop < 0) {
 			pr_err("couldnt read the regulation loop err=%d\n",
@@ -2281,13 +2684,15 @@
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, eoc_work);
 	static int count;
-	int end = is_charging_finished(chip);
+	int end;
+
+	pm_chg_failed_clear(chip, 1);
+	end = is_charging_finished(chip);
 
 	if (end == CHG_NOT_IN_PROGRESS) {
-			/* enable fastchg irq */
-			count = 0;
-			wake_unlock(&chip->eoc_wake_lock);
-			return;
+		count = 0;
+		wake_unlock(&chip->eoc_wake_lock);
+		return;
 	}
 
 	if (end == CHG_FINISHED) {
@@ -2313,6 +2718,7 @@
 		chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
 		wake_unlock(&chip->eoc_wake_lock);
 	} else {
+		adjust_vdd_max_for_fastchg(chip);
 		pr_debug("EOC count = %d\n", count);
 		schedule_delayed_work(&chip->eoc_work,
 			      round_jiffies_relative(msecs_to_jiffies
@@ -2453,6 +2859,23 @@
 module_param_call(disabled, set_disable_status_param, param_get_uint,
 					&charging_disabled, 0644);
 
+static int rconn_mohm;
+static int set_rconn_mohm(const char *val, struct kernel_param *kp)
+{
+	int ret;
+	struct pm8921_chg_chip *chip = the_chip;
+
+	ret = param_set_int(val, kp);
+	if (ret) {
+		pr_err("error setting value %d\n", ret);
+		return ret;
+	}
+	if (chip)
+		chip->rconn_mohm = rconn_mohm;
+	return 0;
+}
+module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
+					&rconn_mohm, 0644);
 /**
  * set_thermal_mitigation_level -
  *
@@ -2512,8 +2935,8 @@
 	}
 	return -EINVAL;
 }
-module_param_call(usb_max_current, set_usb_max_current, param_get_uint,
-					&usb_max_current, 0644);
+module_param_call(usb_max_current, set_usb_max_current,
+	param_get_uint, &usb_max_current, 0644);
 
 static void free_irqs(struct pm8921_chg_chip *chip)
 {
@@ -2540,6 +2963,7 @@
 		schedule_delayed_work(&chip->unplug_check_work,
 			round_jiffies_relative(msecs_to_jiffies
 				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+		pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
 	}
 
 	pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
@@ -2621,7 +3045,8 @@
 	CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
 	CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
 						batttemp_cold_irq_handler),
-	CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING, chg_gone_irq_handler),
+	CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+						chg_gone_irq_handler),
 	CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 						bat_temp_ok_irq_handler),
 	CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
@@ -2768,6 +3193,7 @@
 static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
 {
 	int rc;
+	int vdd_safe;
 
 	rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
 					BOOT_DONE_BIT, BOOT_DONE_BIT);
@@ -2776,7 +3202,13 @@
 		return rc;
 	}
 
-	rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
+	vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
+
+	if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
+		vdd_safe = PM8921_CHG_VDDSAFE_MAX;
+
+	rc = pm_chg_vddsafe_set(chip, vdd_safe);
+
 	if (rc) {
 		pr_err("Failed to set safe voltage to %d rc=%d\n",
 						chip->max_voltage_mv, rc);
@@ -2826,10 +3258,9 @@
 	}
 
 	/* init with the lowest USB current */
-	rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
+	rc = pm_chg_iusbmax_set(chip, 0);
 	if (rc) {
-		pr_err("Failed to set usb max to %d rc=%d\n",
-					usb_ma_table[0].chg_iusb_value, rc);
+		pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
 		return rc;
 	}
 
@@ -2929,6 +3360,12 @@
 						chip->hot_thr, rc);
 	}
 
+	rc = pm_chg_led_src_config(chip, chip->led_src_config);
+	if (rc) {
+		pr_err("Failed to set charger LED src config %d  rc=%d\n",
+						chip->led_src_config, rc);
+	}
+
 	/* Workarounds for die 1.1 and 1.0 */
 	if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
 		pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
@@ -3269,6 +3706,8 @@
 
 	chip->cold_thr = pdata->cold_thr;
 	chip->hot_thr = pdata->hot_thr;
+	chip->rconn_mohm = pdata->rconn_mohm;
+	chip->led_src_config = pdata->led_src_config;
 
 	rc = pm8921_chg_hw_init(chip);
 	if (rc) {
@@ -3280,17 +3719,17 @@
 	chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
 	chip->usb_psy.supplied_to = pm_power_supplied_to,
 	chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
-	chip->usb_psy.properties = pm_power_props,
-	chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
-	chip->usb_psy.get_property = pm_power_get_property,
+	chip->usb_psy.properties = pm_power_props_usb,
+	chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
+	chip->usb_psy.get_property = pm_power_get_property_usb,
 
 	chip->dc_psy.name = "pm8921-dc",
 	chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
 	chip->dc_psy.supplied_to = pm_power_supplied_to,
 	chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
-	chip->dc_psy.properties = pm_power_props,
-	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
-	chip->dc_psy.get_property = pm_power_get_property,
+	chip->dc_psy.properties = pm_power_props_mains,
+	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
+	chip->dc_psy.get_property = pm_power_get_property_mains,
 
 	chip->batt_psy.name = "battery",
 	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
@@ -3320,11 +3759,11 @@
 	the_chip = chip;
 
 	wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
-	wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock,
-			WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
 	INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
-	INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work,
-					unplug_wrkarnd_restore_worker);
+	INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
+						vin_collapse_check_worker);
+	INIT_WORK(&chip->unplug_ovp_fet_open_work,
+					unplug_ovp_fet_open_worker);
 	INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
 
 	rc = request_irqs(chip, pdev);
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index c95fd93..65bc654 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -549,7 +549,7 @@
 
 int pm8xxx_ccadc_get_battery_current(int *bat_current_ua)
 {
-	int voltage_uv, rc;
+	int voltage_uv = 0, rc;
 
 	rc = ccadc_get_rsense_voltage(&voltage_uv);
 	if (rc) {
diff --git a/drivers/power/smb349.c b/drivers/power/smb349.c
new file mode 100644
index 0000000..148f188
--- /dev/null
+++ b/drivers/power/smb349.c
@@ -0,0 +1,700 @@
+/* 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/i2c.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/i2c/smb349.h>
+#include <linux/power_supply.h>
+
+#define SMB349_MASK(BITS, POS)  ((unsigned char)(((1 << BITS) - 1) << POS))
+
+/* Register definitions */
+#define CHG_CURRENT_REG			0x00
+#define CHG_OTHER_CURRENT_REG	0x01
+#define VAR_FUNC_REG			0x02
+#define FLOAT_VOLTAGE_REG		0x03
+#define CHG_CTRL_REG			0x04
+#define STAT_TIMER_REG			0x05
+#define PIN_ENABLE_CTRL_REG		0x06
+#define THERM_CTRL_A_REG		0x07
+#define SYSOK_USB3_SELECT_REG	0x08
+#define CTRL_FUNCTIONS_REG		0x09
+#define OTG_TLIM_THERM_CNTRL_REG	0x0A
+#define HARD_SOFT_LIMIT_CELL_TEMP_MONITOR_REG 0x0B
+#define FAULT_IRQ_REG	0x0C
+#define STATUS_IRQ_REG	0x0D
+#define SYSOK_REG		0x0E
+#define CMD_A_REG		0x30
+#define CMD_B_REG		0x31
+#define CMD_C_REG		0x33
+#define IRQ_A_REG		0x35
+#define IRQ_B_REG		0x36
+#define IRQ_C_REG		0x37
+#define IRQ_D_REG		0x38
+#define IRQ_E_REG		0x39
+#define IRQ_F_REG		0x3A
+#define STATUS_A_REG	0x3B
+#define STATUS_B_REG	0x3C
+#define STATUS_C_REG	0x3D
+#define STATUS_D_REG	0x3E
+#define STATUS_E_REG	0x3F
+
+/* Status bits and masks */
+#define CHG_STATUS_MASK		SMB349_MASK(2, 1)
+#define CHG_ENABLE_STATUS_BIT		BIT(0)
+
+/* Control bits and masks */
+#define FAST_CHG_CURRENT_MASK			SMB349_MASK(4, 4)
+#define AC_INPUT_CURRENT_LIMIT_MASK		SMB349_MASK(4, 0)
+#define PRE_CHG_CURRENT_MASK			SMB349_MASK(3, 5)
+#define TERMINATION_CURRENT_MASK		SMB349_MASK(3, 2)
+#define PRE_CHG_TO_FAST_CHG_THRESH_MASK	SMB349_MASK(2, 6)
+#define FLOAT_VOLTAGE_MASK				SMB349_MASK(6, 0)
+#define CHG_ENABLE_BIT			BIT(1)
+#define VOLATILE_W_PERM_BIT		BIT(7)
+#define USB_SELECTION_BIT		BIT(1)
+#define SYSTEM_FET_ENABLE_BIT	BIT(7)
+#define AUTOMATIC_INPUT_CURR_LIMIT_BIT			BIT(4)
+#define AUTOMATIC_POWER_SOURCE_DETECTION_BIT	BIT(2)
+#define BATT_OV_END_CHG_BIT		BIT(1)
+#define VCHG_FUNCTION			BIT(0)
+#define CURR_TERM_END_CHG_BIT	BIT(6)
+
+struct smb349_struct {
+	struct			i2c_client *client;
+	bool			charging;
+	bool			present;
+	int			chg_current_ma;
+
+	int			en_n_gpio;
+	int			chg_susp_gpio;
+	struct dentry			*dent;
+	spinlock_t			lock;
+	struct work_struct			hwinit_work;
+
+	struct power_supply			dc_psy;
+};
+
+struct chg_ma_limit_entry {
+	int fast_chg_ma_limit;
+	int ac_input_ma_limit;
+	u8  chg_current_value;
+};
+
+static struct smb349_struct *the_smb349_chg;
+
+static int smb349_read_reg(struct i2c_client *client, int reg,
+				u8 *val)
+{
+	s32 ret;
+	struct smb349_struct *smb349_chg;
+
+	smb349_chg = i2c_get_clientdata(client);
+	ret = i2c_smbus_read_byte_data(smb349_chg->client, reg);
+	if (ret < 0) {
+		dev_err(&smb349_chg->client->dev,
+			"i2c read fail: can't read from %02x: %d\n", reg, ret);
+		return ret;
+	} else {
+		*val = ret;
+	}
+
+	return 0;
+}
+
+static int smb349_write_reg(struct i2c_client *client, int reg,
+						u8 val)
+{
+	s32 ret;
+	struct smb349_struct *smb349_chg;
+
+	smb349_chg = i2c_get_clientdata(client);
+	ret = i2c_smbus_write_byte_data(smb349_chg->client, reg, val);
+	if (ret < 0) {
+		dev_err(&smb349_chg->client->dev,
+			"i2c write fail: can't write %02x to %02x: %d\n",
+			val, reg, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int smb349_masked_write(struct i2c_client *client, int reg,
+		u8 mask, u8 val)
+{
+	s32 rc;
+	u8 temp;
+
+	rc = smb349_read_reg(client, reg, &temp);
+	if (rc) {
+		pr_err("smb349_read_reg failed: reg=%03X, rc=%d\n", reg, rc);
+		return rc;
+	}
+	temp &= ~mask;
+	temp |= val & mask;
+	rc = smb349_write_reg(client, reg, temp);
+	if (rc) {
+		pr_err("smb349_write failed: reg=%03X, rc=%d\n", reg, rc);
+		return rc;
+	}
+	return 0;
+}
+
+static enum power_supply_property pm_power_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+};
+
+static char *pm_power_supplied_to[] = {
+	"battery",
+};
+
+static int get_prop_charge_type(struct smb349_struct *smb349_chg)
+{
+	if (smb349_chg->charging)
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+
+	return POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+
+static int pm_power_get_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  union power_supply_propval *val)
+{
+	struct smb349_struct *smb349_chg = container_of(psy,
+						struct smb349_struct,
+						dc_psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = smb349_chg->chg_current_ma;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = (int)smb349_chg->present;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		val->intval = get_prop_charge_type(smb349_chg);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#define SMB349_FAST_CHG_MIN_MA	1000
+#define SMB349_FAST_CHG_STEP_MA	200
+#define SMB349_FAST_CHG_MAX_MA	4000
+#define SMB349_FAST_CHG_SHIFT	4
+static int chg_current_set(struct smb349_struct *smb349_chg)
+{
+	u8 temp;
+
+	if ((smb349_chg->chg_current_ma < SMB349_FAST_CHG_MIN_MA) ||
+		(smb349_chg->chg_current_ma >  SMB349_FAST_CHG_MAX_MA)) {
+		pr_err("bad mA=%d asked to set\n", smb349_chg->chg_current_ma);
+		return -EINVAL;
+	}
+
+	temp = (smb349_chg->chg_current_ma - SMB349_FAST_CHG_MIN_MA)
+			/ SMB349_FAST_CHG_STEP_MA;
+
+	temp = temp << SMB349_FAST_CHG_SHIFT;
+	pr_debug("fastchg limit=%d setting %02x\n",
+				smb349_chg->chg_current_ma, temp);
+	return smb349_masked_write(smb349_chg->client, CHG_CURRENT_REG,
+			FAST_CHG_CURRENT_MASK, temp);
+}
+
+static int set_reg(void *data, u64 val)
+{
+	int addr = (int)data;
+	int ret;
+	u8 temp;
+
+	temp = (u16) val;
+	ret = smb349_write_reg(the_smb349_chg->client, addr, temp);
+
+	if (ret) {
+		pr_err("smb349_write_reg to %x value =%d errored = %d\n",
+			addr, temp, ret);
+		return -EAGAIN;
+	}
+	return 0;
+}
+static int get_reg(void *data, u64 *val)
+{
+	int addr = (int)data;
+	int ret;
+	u8 temp;
+
+	ret = smb349_read_reg(the_smb349_chg->client, addr, &temp);
+	if (ret) {
+		pr_err("smb349_read_reg to %x value =%d errored = %d\n",
+			addr, temp, ret);
+		return -EAGAIN;
+	}
+
+	*val = temp;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+
+static void create_debugfs_entries(struct smb349_struct *smb349_chg)
+{
+	struct dentry *file;
+	smb349_chg->dent = debugfs_create_dir(SMB349_NAME, NULL);
+	if (IS_ERR(smb349_chg->dent)) {
+		pr_err("smb349 driver couldn't create debugfs dir\n");
+		return;
+	}
+
+	file = debugfs_create_file("CHG_CURRENT_REG", 0644, smb349_chg->dent,
+				(void *) CHG_CURRENT_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("CHG_OTHER_CURRENT_REG", 0644,
+		smb349_chg->dent, (void *) CHG_OTHER_CURRENT_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("VAR_FUNC_REG", 0644, smb349_chg->dent,
+				(void *) VAR_FUNC_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("FLOAT_VOLTAGE_REG", 0644, smb349_chg->dent,
+				(void *) FLOAT_VOLTAGE_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("CHG_CTRL_REG", 0644, smb349_chg->dent,
+				(void *) CHG_CTRL_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("STAT_TIMER_REG", 0644, smb349_chg->dent,
+				(void *) STAT_TIMER_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("PIN_ENABLE_CTRL_REG", 0644,
+		smb349_chg->dent, (void *) PIN_ENABLE_CTRL_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("PIN_ENABLE_CTRL_REG", 0644,
+		smb349_chg->dent, (void *) PIN_ENABLE_CTRL_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("PIN_ENABLE_CTRL_REG", 0644,
+		smb349_chg->dent, (void *) PIN_ENABLE_CTRL_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("THERM_CTRL_A_REG", 0644, smb349_chg->dent,
+				(void *) THERM_CTRL_A_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("SYSOK_USB3_SELECT_REG", 0644,
+		smb349_chg->dent, (void *) SYSOK_USB3_SELECT_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("CTRL_FUNCTIONS_REG", 0644,
+		smb349_chg->dent, (void *) CTRL_FUNCTIONS_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("OTG_TLIM_THERM_CNTRL_REG", 0644,
+		smb349_chg->dent, (void *) OTG_TLIM_THERM_CNTRL_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("HARD_SOFT_LIMIT_CELL_TEMP_MONITOR_REG",
+		0644, smb349_chg->dent,
+		(void *) HARD_SOFT_LIMIT_CELL_TEMP_MONITOR_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("SYSOK_REG", 0644, smb349_chg->dent,
+				(void *) SYSOK_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("CMD_A_REG", 0644, smb349_chg->dent,
+				(void *) CMD_A_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("CMD_B_REG", 0644, smb349_chg->dent,
+				(void *) CMD_B_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("CMD_C_REG", 0644, smb349_chg->dent,
+				(void *) CMD_C_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("STATUS_A_REG", 0644, smb349_chg->dent,
+				(void *) STATUS_A_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("STATUS_B_REG", 0644, smb349_chg->dent,
+				(void *) STATUS_B_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("STATUS_C_REG", 0644, smb349_chg->dent,
+				(void *) STATUS_C_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("STATUS_D_REG", 0644, smb349_chg->dent,
+				(void *) STATUS_D_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+	file = debugfs_create_file("STATUS_E_REG", 0644, smb349_chg->dent,
+				(void *) STATUS_E_REG, &reg_fops);
+	if (IS_ERR(file)) {
+		pr_err("smb349 driver couldn't create debugfs files\n");
+		return;
+	}
+}
+
+static void remove_debugfs_entries(struct smb349_struct *smb349_chg)
+{
+	if (smb349_chg->dent)
+		debugfs_remove_recursive(smb349_chg->dent);
+}
+
+static int __devinit smb349_hwinit(struct smb349_struct *smb349_chg)
+{
+	int ret;
+
+	ret = smb349_write_reg(smb349_chg->client, CMD_A_REG,
+			VOLATILE_W_PERM_BIT);
+	if (ret) {
+		pr_err("Failed to set VOLATILE_W_PERM_BIT rc=%d\n", ret);
+		return ret;
+	}
+
+	ret = smb349_masked_write(smb349_chg->client, CHG_CTRL_REG,
+				CURR_TERM_END_CHG_BIT, CURR_TERM_END_CHG_BIT);
+	if (ret) {
+		pr_err("Failed to set CURR_TERM_END_CHG_BIT rc=%d\n", ret);
+		return ret;
+	}
+
+	ret = chg_current_set(smb349_chg);
+	if (ret) {
+		pr_err("Failed to set FAST_CHG_CURRENT rc=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int smb349_stop_charging(struct smb349_struct *smb349_chg)
+{
+	unsigned long flags;
+
+	if (smb349_chg->charging)
+		gpio_set_value_cansleep(smb349_chg->en_n_gpio, 0);
+
+	spin_lock_irqsave(&smb349_chg->lock, flags);
+	pr_debug("stop charging %d\n", smb349_chg->charging);
+	smb349_chg->charging = 0;
+	spin_unlock_irqrestore(&smb349_chg->lock, flags);
+	power_supply_changed(&smb349_chg->dc_psy);
+	return 0;
+}
+
+static int smb349_start_charging(struct smb349_struct *smb349_chg)
+{
+	unsigned long flags;
+	int rc;
+
+	rc = 0;
+	if (!smb349_chg->charging) {
+		gpio_set_value_cansleep(smb349_chg->en_n_gpio, 1);
+		/*
+		 * Write non-default values, charger chip reloads from
+		 * non-volatile memory if it was in suspend mode
+		 *
+		 */
+		rc = schedule_work(&smb349_chg->hwinit_work);
+	}
+
+	spin_lock_irqsave(&smb349_chg->lock, flags);
+	pr_debug("start charging %d\n", smb349_chg->charging);
+	smb349_chg->charging = 1;
+	spin_unlock_irqrestore(&smb349_chg->lock, flags);
+	power_supply_changed(&smb349_chg->dc_psy);
+	return rc;
+}
+
+static int pm_power_set_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  const union power_supply_propval *val)
+{
+	struct smb349_struct *smb349_chg = container_of(psy,
+						struct smb349_struct,
+						dc_psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (val->intval) {
+			smb349_chg->present = val->intval;
+		} else {
+			smb349_chg->present = 0;
+			if (smb349_chg->charging)
+				return smb349_stop_charging(smb349_chg);
+		}
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		if (val->intval) {
+			if (smb349_chg->chg_current_ma != val->intval)
+				return -EINVAL;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		if (val->intval && smb349_chg->present) {
+			if (val->intval == POWER_SUPPLY_CHARGE_TYPE_FAST)
+				return smb349_start_charging(smb349_chg);
+			if (val->intval == POWER_SUPPLY_CHARGE_TYPE_NONE)
+				return smb349_stop_charging(smb349_chg);
+		} else {
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	power_supply_changed(&smb349_chg->dc_psy);
+	return 0;
+}
+
+static void hwinit_worker(struct work_struct *work)
+{
+	int ret;
+	struct smb349_struct *smb349_chg = container_of(work,
+				struct smb349_struct, hwinit_work);
+
+	ret = smb349_hwinit(smb349_chg);
+	if (ret)
+		pr_err("Failed to re-initilaze registers\n");
+}
+
+static int __devinit smb349_init_ext_chg(struct smb349_struct *smb349_chg)
+{
+	int ret;
+
+	smb349_chg->dc_psy.name = "dc";
+	smb349_chg->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+	smb349_chg->dc_psy.supplied_to = pm_power_supplied_to;
+	smb349_chg->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+	smb349_chg->dc_psy.properties = pm_power_props;
+	smb349_chg->dc_psy.num_properties = ARRAY_SIZE(pm_power_props);
+	smb349_chg->dc_psy.get_property = pm_power_get_property;
+	smb349_chg->dc_psy.set_property = pm_power_set_property;
+
+	ret = power_supply_register(&smb349_chg->client->dev,
+				&smb349_chg->dc_psy);
+	if (ret) {
+		pr_err("failed to register power_supply. ret=%d.\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit smb349_probe(struct i2c_client *client,
+				    const struct i2c_device_id *id)
+{
+	const struct smb349_platform_data *pdata;
+	struct smb349_struct *smb349_chg;
+	int ret = 0;
+
+	pdata = client->dev.platform_data;
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "%s no platform data\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!i2c_check_functionality(client->adapter,
+				I2C_FUNC_SMBUS_BYTE_DATA)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	smb349_chg = kzalloc(sizeof(*smb349_chg), GFP_KERNEL);
+	if (!smb349_chg) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	smb349_chg->client = client;
+	smb349_chg->chg_current_ma = pdata->chg_current_ma;
+	ret = gpio_request(pdata->chg_susp_gpio, "smb349_suspend");
+	if (ret) {
+		dev_err(&client->dev, "%s gpio_request failed for %d ret=%d\n",
+			__func__, pdata->chg_susp_gpio, ret);
+		goto free_smb349_chg;
+	}
+	smb349_chg->chg_susp_gpio = pdata->chg_susp_gpio;
+
+	ret = gpio_request(pdata->en_n_gpio, "smb349_charger_enable");
+	if (ret) {
+		dev_err(&client->dev, "%s gpio_request failed for %d ret=%d\n",
+			__func__, pdata->en_n_gpio, ret);
+		goto chg_susp_gpio_fail;
+	}
+	smb349_chg->en_n_gpio = pdata->en_n_gpio;
+
+	i2c_set_clientdata(client, smb349_chg);
+
+	ret = smb349_hwinit(smb349_chg);
+	if (ret)
+		goto free_smb349_chg;
+
+	ret = smb349_init_ext_chg(smb349_chg);
+	if (ret)
+		goto chg_en_gpio_fail;
+
+	the_smb349_chg = smb349_chg;
+
+	create_debugfs_entries(smb349_chg);
+	INIT_WORK(&smb349_chg->hwinit_work, hwinit_worker);
+
+	pr_info("OK connector present = %d\n", smb349_chg->present);
+	return 0;
+
+chg_en_gpio_fail:
+	gpio_free(smb349_chg->en_n_gpio);
+chg_susp_gpio_fail:
+	gpio_free(smb349_chg->chg_susp_gpio);
+free_smb349_chg:
+	kfree(smb349_chg);
+out:
+	return ret;
+}
+
+static int __devexit smb349_remove(struct i2c_client *client)
+{
+	const struct smb349_platform_data *pdata;
+	struct smb349_struct *smb349_chg = i2c_get_clientdata(client);
+
+	flush_work(&smb349_chg->hwinit_work);
+	pdata = client->dev.platform_data;
+	power_supply_unregister(&smb349_chg->dc_psy);
+	gpio_free(pdata->en_n_gpio);
+	gpio_free(pdata->chg_susp_gpio);
+	remove_debugfs_entries(smb349_chg);
+	kfree(smb349_chg);
+	return 0;
+}
+
+static int smb349_suspend(struct device *dev)
+{
+	struct smb349_struct *smb349_chg = dev_get_drvdata(dev);
+
+	pr_debug("suspend\n");
+	if (smb349_chg->charging)
+		return -EBUSY;
+	return 0;
+}
+
+static int smb349_resume(struct device *dev)
+{
+	pr_debug("resume\n");
+
+	return 0;
+}
+
+static const struct dev_pm_ops smb349_pm_ops = {
+	.suspend	= smb349_suspend,
+	.resume		= smb349_resume,
+};
+
+static const struct i2c_device_id smb349_id[] = {
+	{SMB349_NAME, 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, smb349_id);
+
+static struct i2c_driver smb349_driver = {
+	.driver	= {
+		   .name	= SMB349_NAME,
+		   .owner	= THIS_MODULE,
+		   .pm		= &smb349_pm_ops,
+	},
+	.probe		= smb349_probe,
+	.remove		= __devexit_p(smb349_remove),
+	.id_table	= smb349_id,
+};
+
+static int __init smb349_init(void)
+{
+	return i2c_add_driver(&smb349_driver);
+}
+module_init(smb349_init);
+
+static void __exit smb349_exit(void)
+{
+	return i2c_del_driver(&smb349_driver);
+}
+module_exit(smb349_exit);
+
+MODULE_DESCRIPTION("Driver for SMB349 charger chip");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:" SMB349_NAME);
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index cf3f999..10451a1 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -101,7 +101,9 @@
 
 static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp)
 {
-	return 1; /* always round timer functions to one nanosecond */
+	tp->tv_sec = 0;
+	tp->tv_nsec = 1;
+	return 0;
 }
 
 static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp)
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index d63fddb..443f2df 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -426,7 +426,7 @@
 
 	/* replace driver_data with info */
 	info->regulator = regulator_register(&info->desc, &pdev->dev,
-					     pdata, info);
+					     pdata, info, NULL);
 	if (IS_ERR(info->regulator)) {
 		dev_err(&pdev->dev, "failed to register regulator %s\n",
 			info->desc.name);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 49e0d0e..fb1a99f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -344,5 +344,14 @@
 	  chip. It is only supposed to be used when Linux on application
 	  processor is the master in control of XO buffers.
 
+config REGULATOR_STUB
+	tristate "Stub Regulator"
+	help
+	  This driver adds stub regulator support. The driver is absent of any
+	  real hardware based implementation. It allows for clients to register
+	  their regulator device constraints and use all of the standard
+	  regulator interfaces. This is useful for bringing up new platforms
+	  when the real hardware based implementation may not be yet available.
+	  Clients can use the real regulator device names with proper
+	  constraint checking while the real driver is being developed.
 endif
-
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 5318cff..7e529c7 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,6 +4,7 @@
 
 
 obj-$(CONFIG_REGULATOR) += core.o dummy.o
+obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
@@ -48,5 +49,6 @@
 obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_PM8058_XO) += pm8058-xo.o
 obj-$(CONFIG_REGULATOR_PM8XXX) += pm8xxx-regulator.o
+obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 585e494..042271a 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -634,7 +634,7 @@
 		rdev = regulator_register(&ab3100_regulator_desc[i],
 					  &pdev->dev,
 					  &plfdata->reg_constraints[i],
-					  reg);
+					  reg, NULL);
 
 		if (IS_ERR(rdev)) {
 			err = PTR_ERR(rdev);
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index 02f3c23..8b13b0e 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -821,7 +821,7 @@
 
 		/* register regulator with framework */
 		info->regulator = regulator_register(&info->desc, &pdev->dev,
-				&pdata->regulator[i], info);
+				&pdata->regulator[i], info, NULL);
 		if (IS_ERR(info->regulator)) {
 			err = PTR_ERR(info->regulator);
 			dev_err(&pdev->dev, "failed to register regulator %s\n",
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index a4be416..483c809 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -233,7 +233,7 @@
 	chip->current_mask = (chip->current_level - 1) << chip->current_offset;
 
 	chip->rdev = regulator_register(&ad5398_reg, &client->dev,
-					init_data, chip);
+					init_data, chip, NULL);
 	if (IS_ERR(chip->rdev)) {
 		ret = PTR_ERR(chip->rdev);
 		dev_err(&client->dev, "failed to register %s %s\n",
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
index 068d488..dc4a8e6 100644
--- a/drivers/regulator/bq24022.c
+++ b/drivers/regulator/bq24022.c
@@ -106,7 +106,7 @@
 	ret = gpio_direction_output(pdata->gpio_nce, 1);
 
 	bq24022 = regulator_register(&bq24022_desc, &pdev->dev,
-				     pdata->init_data, pdata);
+				     pdata->init_data, pdata, NULL);
 	if (IS_ERR(bq24022)) {
 		dev_dbg(&pdev->dev, "couldn't register regulator\n");
 		ret = PTR_ERR(bq24022);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 2b58215..3f9beaa4 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -27,6 +27,8 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
@@ -128,6 +130,33 @@
 	return NULL;
 }
 
+/**
+ * of_get_regulator - get a regulator device node based on supply name
+ * @dev: Device pointer for the consumer (of regulator) device
+ * @supply: regulator supply name
+ *
+ * Extract the regulator device node corresponding to the supply name.
+ * retruns the device node corresponding to the regulator if found, else
+ * returns NULL.
+ */
+static struct device_node *of_get_regulator(struct device *dev, const char *supply)
+{
+	struct device_node *regnode = NULL;
+	char prop_name[32]; /* 32 is max size of property name */
+
+	dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);
+
+	snprintf(prop_name, 32, "%s-supply", supply);
+	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+	if (!regnode) {
+		dev_warn(dev, "%s property in node %s references invalid phandle",
+				prop_name, dev->of_node->full_name);
+		return NULL;
+	}
+	return regnode;
+}
+
 /* Platform voltage constraint check */
 static int regulator_check_voltage(struct regulator_dev *rdev,
 				   int *min_uV, int *max_uV)
@@ -1208,6 +1237,30 @@
 	return rdev->desc->ops->enable_time(rdev);
 }
 
+static struct regulator_dev *regulator_dev_lookup(struct device *dev,
+							 const char *supply)
+{
+	struct regulator_dev *r;
+	struct device_node *node;
+
+	/* first do a dt based lookup */
+	if (dev && dev->of_node) {
+		node = of_get_regulator(dev, supply);
+		if (node)
+			list_for_each_entry(r, &regulator_list, list)
+				if (r->dev.parent &&
+					node == r->dev.of_node)
+					return r;
+	}
+
+	/* if not found, try doing it non-dt way */
+	list_for_each_entry(r, &regulator_list, list)
+		if (strcmp(rdev_get_name(r), supply) == 0)
+			return r;
+
+	return NULL;
+}
+
 /* Internal regulator request function */
 static struct regulator *_regulator_get(struct device *dev, const char *id,
 					int exclusive)
@@ -1228,6 +1281,10 @@
 
 	mutex_lock(&regulator_list_mutex);
 
+	rdev = regulator_dev_lookup(dev, id);
+	if (rdev)
+		goto found;
+
 	list_for_each_entry(map, &regulator_map_list, list) {
 		/* If the mapping has a device set up it must match */
 		if (map->dev_name &&
@@ -3080,11 +3137,12 @@
  */
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
 	struct device *dev, const struct regulator_init_data *init_data,
-	void *driver_data)
+	void *driver_data, struct device_node *of_node)
 {
 	static atomic_t regulator_no = ATOMIC_INIT(0);
 	struct regulator_dev *rdev;
 	int ret, i;
+	const char *supply = NULL;
 
 	if (regulator_desc == NULL)
 		return ERR_PTR(-EINVAL);
@@ -3140,6 +3198,7 @@
 
 	/* register with sysfs */
 	rdev->dev.class = &regulator_class;
+	rdev->dev.of_node = of_node;
 	rdev->dev.parent = dev;
 	dev_set_name(&rdev->dev, "regulator.%d",
 		     atomic_inc_return(&regulator_no) - 1);
@@ -3161,21 +3220,18 @@
 	if (ret < 0)
 		goto scrub;
 
-	if (init_data->supply_regulator) {
+	if (init_data->supply_regulator)
+		supply = init_data->supply_regulator;
+	else if (regulator_desc->supply_name)
+		supply = regulator_desc->supply_name;
+
+	if (supply) {
 		struct regulator_dev *r;
-		int found = 0;
 
-		list_for_each_entry(r, &regulator_list, list) {
-			if (strcmp(rdev_get_name(r),
-				   init_data->supply_regulator) == 0) {
-				found = 1;
-				break;
-			}
-		}
+		r = regulator_dev_lookup(dev, supply);
 
-		if (!found) {
-			dev_err(dev, "Failed to find supply %s\n",
-				init_data->supply_regulator);
+		if (!r) {
+			dev_err(dev, "Failed to find supply %s\n", supply);
 			ret = -ENODEV;
 			goto scrub;
 		}
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index 362e082..f3064fe 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -536,7 +536,7 @@
 		ri->desc.ops = &da9030_regulator_ldo1_15_ops;
 
 	rdev = regulator_register(&ri->desc, &pdev->dev,
-				  pdev->dev.platform_data, ri);
+				  pdev->dev.platform_data, ri, NULL);
 	if (IS_ERR(rdev)) {
 		dev_err(&pdev->dev, "failed to register regulator %s\n",
 				ri->desc.name);
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index 2bb8f45..f88b13d 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -485,7 +485,7 @@
 
 		/* register with the regulator framework */
 		info->rdev = regulator_register(&info->desc, &pdev->dev,
-				init_data, info);
+				init_data, info, NULL);
 		if (IS_ERR(info->rdev)) {
 			err = PTR_ERR(info->rdev);
 			dev_err(&pdev->dev, "failed to register %s: err %i\n",
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index c7410bd..910583f 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -36,6 +36,29 @@
 	.ops = &dummy_ops,
 };
 
+static int __devinit dummy_regulator_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
+						  &dummy_initdata, NULL, NULL);
+	if (IS_ERR(dummy_regulator_rdev)) {
+		ret = PTR_ERR(dummy_regulator_rdev);
+		pr_err("Failed to register regulator: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver dummy_regulator_driver = {
+	.probe		= dummy_regulator_probe,
+	.driver		= {
+		.name		= "reg-dummy",
+		.owner		= THIS_MODULE,
+	},
+};
+
 static struct platform_device *dummy_pdev;
 
 void __init regulator_dummy_init(void)
@@ -55,12 +78,9 @@
 		return;
 	}
 
-	dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
-						  &dummy_initdata, NULL);
-	if (IS_ERR(dummy_regulator_rdev)) {
-		ret = PTR_ERR(dummy_regulator_rdev);
-		pr_err("Failed to register regulator: %d\n", ret);
+	ret = platform_driver_register(&dummy_regulator_driver);
+	if (ret != 0) {
+		pr_err("Failed to register dummy regulator driver: %d\n", ret);
 		platform_device_unregister(dummy_pdev);
-		return;
 	}
 }
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 2fe9d99c..906b265 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -26,6 +26,10 @@
 #include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
 
 struct fixed_voltage_data {
 	struct regulator_desc desc;
@@ -37,6 +41,53 @@
 	bool is_enabled;
 };
 
+
+/**
+ * of_get_fixed_voltage_config - extract fixed_voltage_config structure info
+ * @dev: device requesting for fixed_voltage_config
+ *
+ * Populates fixed_voltage_config structure by extracting data from device
+ * tree node, returns a pointer to the populated structure of NULL if memory
+ * alloc fails.
+ */
+struct fixed_voltage_config *of_get_fixed_voltage_config(struct device *dev)
+{
+	struct fixed_voltage_config *config;
+	struct device_node *np = dev->of_node;
+	const __be32 *delay;
+	struct regulator_init_data *init_data;
+
+	config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
+								 GFP_KERNEL);
+	if (!config)
+		return NULL;
+
+	config->init_data = of_get_regulator_init_data(dev);
+	init_data = config->init_data;
+
+	config->supply_name = init_data->constraints.name;
+	if (init_data->constraints.min_uV == init_data->constraints.max_uV) {
+		config->microvolts = init_data->constraints.min_uV;
+	} else {
+		dev_err(dev,
+			 "Fixed regulator specified with variable voltages\n");
+		return NULL;
+	}
+
+	if (init_data->constraints.boot_on)
+		config->enabled_at_boot = true;
+
+	config->gpio = of_get_named_gpio(np, "gpio", 0);
+	delay = of_get_property(np, "startup-delay-us", NULL);
+	if (delay)
+		config->startup_delay = be32_to_cpu(*delay);
+
+	if (of_find_property(np, "enable-active-high", NULL))
+		config->enable_high = true;
+
+	return config;
+}
+
 static int fixed_voltage_is_enabled(struct regulator_dev *dev)
 {
 	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
@@ -108,6 +159,9 @@
 	struct fixed_voltage_data *drvdata;
 	int ret;
 
+	if (pdev->dev.of_node)
+		config = of_get_fixed_voltage_config(&pdev->dev);
+
 	drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
 	if (drvdata == NULL) {
 		dev_err(&pdev->dev, "Failed to allocate device data\n");
@@ -179,7 +233,7 @@
 	}
 
 	drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
-					  config->init_data, drvdata);
+					  config->init_data, drvdata, NULL);
 	if (IS_ERR(drvdata->dev)) {
 		ret = PTR_ERR(drvdata->dev);
 		dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
@@ -216,12 +270,23 @@
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id fixed_of_match[] __devinitconst = {
+	{ .compatible = "regulator-fixed", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, fixed_of_match);
+#else
+#define fixed_of_match NULL
+#endif
+
 static struct platform_driver regulator_fixed_voltage_driver = {
 	.probe		= reg_fixed_voltage_probe,
 	.remove		= __devexit_p(reg_fixed_voltage_remove),
 	.driver		= {
 		.name		= "reg-fixed-voltage",
 		.owner		= THIS_MODULE,
+		.of_match_table = fixed_of_match,
 	},
 };
 
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index b91e32f..1fd390c 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -152,7 +152,7 @@
 	vreg->desc.owner	= THIS_MODULE;
 
 	vreg->rdev = regulator_register(&vreg->desc, &pdev->dev,
-					&pdata->init_data, vreg);
+					&pdata->init_data, vreg, NULL);
 	if (IS_ERR(vreg->rdev)) {
 		rc = PTR_ERR(vreg->rdev);
 		pr_err("%s: regulator_register failed, rc=%d.\n", vreg->name,
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index e4b3592..c1a456c 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -170,7 +170,7 @@
 
 	for (i = 0; i < 3; i++) {
 		pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev,
-						init_data, pmic);
+						init_data, pmic, NULL);
 		if (IS_ERR(pmic->rdev[i])) {
 			dev_err(&i2c->dev, "failed to register %s\n", id->name);
 			err = PTR_ERR(pmic->rdev[i]);
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 0f22ef1..42b1a30 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -450,7 +450,7 @@
 	for (i = 0; i < pdata->num_regulators; i++) {
 		struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
 		lp3971->rdev[i] = regulator_register(&regulators[reg->id],
-					lp3971->dev, reg->initdata, lp3971);
+				lp3971->dev, reg->initdata, lp3971, NULL);
 
 		if (IS_ERR(lp3971->rdev[i])) {
 			err = PTR_ERR(lp3971->rdev[i]);
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 6aa1b50..939e7f4 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -554,7 +554,7 @@
 	for (i = 0; i < pdata->num_regulators; i++) {
 		struct lp3972_regulator_subdev *reg = &pdata->regulators[i];
 		lp3972->rdev[i] = regulator_register(&regulators[reg->id],
-					lp3972->dev, reg->initdata, lp3972);
+				lp3972->dev, reg->initdata, lp3972, NULL);
 
 		if (IS_ERR(lp3972->rdev[i])) {
 			err = PTR_ERR(lp3972->rdev[i]);
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 3f49512..40e7a4d 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -214,7 +214,7 @@
 		}
 		rdev[i] = regulator_register(&max1586_reg[id], &client->dev,
 					     pdata->subdevs[i].platform_data,
-					     max1586);
+					     max1586, NULL);
 		if (IS_ERR(rdev[i])) {
 			ret = PTR_ERR(rdev[i]);
 			dev_err(&client->dev, "failed to register %s\n",
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 30eb9e5..14d6d28 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -347,7 +347,7 @@
 	}
 
 	info->regulator = regulator_register(&dcdc_desc, &client->dev,
-					     pdata->regulator, info);
+					     pdata->regulator, info, NULL);
 	if (IS_ERR(info->regulator)) {
 		dev_err(info->dev, "failed to register regulator %s\n",
 			dcdc_desc.name);
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index 33f5d9a..a838e66 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -449,7 +449,7 @@
 
 		rdev[i] = regulator_register(&max8660_reg[id], &client->dev,
 					     pdata->subdevs[i].platform_data,
-					     max8660);
+					     max8660, NULL);
 		if (IS_ERR(rdev[i])) {
 			ret = PTR_ERR(rdev[i]);
 			dev_err(&client->dev, "failed to register %s\n",
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index e4dbd66..dd5fae9 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -265,7 +265,7 @@
 	ri->chip = chip;
 
 	rdev = regulator_register(&ri->desc, &pdev->dev,
-				  pdata->regulator[pdev->id], ri);
+				  pdata->regulator[pdev->id], ri, NULL);
 	if (IS_ERR(rdev)) {
 		dev_err(&pdev->dev, "failed to register regulator %s\n",
 				ri->desc.name);
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 486ed81..c4bfd4d 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -211,7 +211,7 @@
 	mutex_init(&max8952->mutex);
 
 	max8952->rdev = regulator_register(&regulator, max8952->dev,
-			&pdata->reg_data, max8952);
+			&pdata->reg_data, max8952, NULL);
 
 	if (IS_ERR(max8952->rdev)) {
 		ret = PTR_ERR(max8952->rdev);
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index ad6628c..f701ca5 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -1145,7 +1145,7 @@
 			regulators[id].n_voltages = 16;
 
 		rdev[i] = regulator_register(&regulators[id], max8997->dev,
-				pdata->regulators[i].initdata, max8997);
+				pdata->regulators[i].initdata, max8997, NULL);
 		if (IS_ERR(rdev[i])) {
 			ret = PTR_ERR(rdev[i]);
 			dev_err(max8997->dev, "regulator init failed for %d\n",
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 41a1495..2d38c24 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -847,7 +847,7 @@
 			regulators[index].n_voltages = count;
 		}
 		rdev[i] = regulator_register(&regulators[index], max8998->dev,
-				pdata->regulators[i].initdata, max8998);
+				pdata->regulators[i].initdata, max8998, NULL);
 		if (IS_ERR(rdev[i])) {
 			ret = PTR_ERR(rdev[i]);
 			dev_err(max8998->dev, "regulator init failed\n");
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 730f43a..8d5822b 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -356,7 +356,7 @@
 		init_data = &pdata->regulators[i];
 		priv->regulators[i] = regulator_register(
 				&mc13783_regulators[init_data->id].desc,
-				&pdev->dev, init_data->init_data, priv);
+				&pdev->dev, init_data->init_data, priv, NULL);
 
 		if (IS_ERR(priv->regulators[i])) {
 			dev_err(&pdev->dev, "failed to register regulator %s\n",
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 3285d41..9d82b5c 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -572,7 +572,7 @@
 		init_data = &pdata->regulators[i];
 		priv->regulators[i] = regulator_register(
 			&mc13892_regulators[init_data->id].desc,
-			&pdev->dev, init_data->init_data, priv);
+			&pdev->dev, init_data->init_data, priv, NULL);
 
 		if (IS_ERR(priv->regulators[i])) {
 			dev_err(&pdev->dev, "failed to register regulator %s\n",
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
new file mode 100644
index 0000000..76673c7
--- /dev/null
+++ b/drivers/regulator/of_regulator.c
@@ -0,0 +1,81 @@
+/*
+ * OF helpers for regulator framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/regulator/machine.h>
+
+static void of_get_regulation_constraints(struct device_node *np,
+					struct regulator_init_data **init_data)
+{
+	const __be32 *min_uV, *max_uV, *uV_offset;
+	const __be32 *min_uA, *max_uA;
+	struct regulation_constraints *constraints = &(*init_data)->constraints;
+
+	constraints->name = of_get_property(np, "regulator-name", NULL);
+
+	min_uV = of_get_property(np, "regulator-min-microvolt", NULL);
+	if (min_uV)
+		constraints->min_uV = be32_to_cpu(*min_uV);
+	max_uV = of_get_property(np, "regulator-max-microvolt", NULL);
+	if (max_uV)
+		constraints->max_uV = be32_to_cpu(*max_uV);
+
+	/* Voltage change possible? */
+	if (constraints->min_uV != constraints->max_uV)
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
+
+	uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL);
+	if (uV_offset)
+		constraints->uV_offset = be32_to_cpu(*uV_offset);
+	min_uA = of_get_property(np, "regulator-min-microamp", NULL);
+	if (min_uA)
+		constraints->min_uA = be32_to_cpu(*min_uA);
+	max_uA = of_get_property(np, "regulator-max-microamp", NULL);
+	if (max_uA)
+		constraints->max_uA = be32_to_cpu(*max_uA);
+
+	/* Current change possible? */
+	if (constraints->min_uA != constraints->max_uA)
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
+
+	if (of_find_property(np, "regulator-boot-on", NULL))
+		constraints->boot_on = true;
+
+	if (of_find_property(np, "regulator-always-on", NULL))
+		constraints->always_on = true;
+	else /* status change should be possible if not always on. */
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+}
+
+/**
+ * of_get_regulator_init_data - extract regulator_init_data structure info
+ * @dev: device requesting for regulator_init_data
+ *
+ * Populates regulator_init_data structure by extracting data from device
+ * tree node, returns a pointer to the populated struture or NULL if memory
+ * alloc fails.
+ */
+struct regulator_init_data *of_get_regulator_init_data(struct device *dev)
+{
+	struct regulator_init_data *init_data;
+
+	if (!dev->of_node)
+		return NULL;
+
+	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
+	if (!init_data)
+		return NULL; /* Out of memory? */
+
+	of_get_regulation_constraints(dev->of_node, &init_data);
+	return init_data;
+}
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index 31f6e11..a5aab1b 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -277,7 +277,7 @@
 	void *pcap = dev_get_drvdata(pdev->dev.parent);
 
 	rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev,
-				pdev->dev.platform_data, pcap);
+				pdev->dev.platform_data, pcap, NULL);
 	if (IS_ERR(rdev))
 		return PTR_ERR(rdev);
 
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 69a11d9..1d1c310 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -320,7 +320,7 @@
 	pcf = dev_to_pcf50633(pdev->dev.parent);
 
 	rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
-				  pdev->dev.platform_data, pcf);
+				  pdev->dev.platform_data, pcf, NULL);
 	if (IS_ERR(rdev))
 		return PTR_ERR(rdev);
 
diff --git a/drivers/regulator/pm8058-xo.c b/drivers/regulator/pm8058-xo.c
index b778660..90093dd 100644
--- a/drivers/regulator/pm8058-xo.c
+++ b/drivers/regulator/pm8058-xo.c
@@ -162,7 +162,7 @@
 			goto bail;
 
 		xo->rdev = regulator_register(rdesc, &pdev->dev,
-					&xo->pdata->init_data, xo);
+					&xo->pdata->init_data, xo, NULL);
 		if (IS_ERR(xo->rdev)) {
 			rc = PTR_ERR(xo->rdev);
 			pr_err("FAIL: regulator_register(%s): rc=%d\n",
diff --git a/drivers/regulator/pm8xxx-regulator.c b/drivers/regulator/pm8xxx-regulator.c
index 94b028d..833c513 100644
--- a/drivers/regulator/pm8xxx-regulator.c
+++ b/drivers/regulator/pm8xxx-regulator.c
@@ -401,6 +401,19 @@
 #define NCP_SET_POINTS			((NCP_UV_MAX - NCP_UV_MIN) \
 						/ NCP_UV_STEP + 1)
 
+/* Boost masks and values */
+#define BOOST_ENABLE_MASK		0x80
+#define BOOST_DISABLE			0x00
+#define BOOST_ENABLE			0x80
+#define BOOST_VPROG_MASK		0x1F
+
+#define BOOST_UV_MIN			4000000
+#define BOOST_UV_MAX			5550000
+#define BOOST_UV_STEP			50000
+
+#define BOOST_SET_POINTS		((BOOST_UV_MAX - BOOST_UV_MIN) \
+						/ BOOST_UV_STEP + 1)
+
 #define vreg_err(vreg, fmt, ...) \
 	pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
 
@@ -1424,6 +1437,64 @@
 	return rc;
 }
 
+static int pm8xxx_boost_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	u8 vprog;
+
+	vprog = vreg->ctrl_reg & BOOST_VPROG_MASK;
+
+	return BOOST_UV_STEP * vprog + BOOST_UV_MIN;
+}
+
+static int pm8xxx_boost_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	if (selector >= BOOST_SET_POINTS)
+		return 0;
+
+	return selector * BOOST_UV_STEP + BOOST_UV_MIN;
+}
+
+static int pm8xxx_boost_set_voltage(struct regulator_dev *rdev, int min_uV,
+				   int max_uV, unsigned *selector)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+	int uV = min_uV;
+	u8 val;
+
+	if (uV < BOOST_UV_MIN && max_uV >= BOOST_UV_MIN)
+		uV = BOOST_UV_MIN;
+
+	if (uV < BOOST_UV_MIN || uV > BOOST_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, BOOST_UV_MIN, BOOST_UV_MAX);
+		return -EINVAL;
+	}
+
+	val = (uV - BOOST_UV_MIN + BOOST_UV_STEP - 1) / BOOST_UV_STEP;
+	uV = val * BOOST_UV_STEP + BOOST_UV_MIN;
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	/* voltage setting */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+			BOOST_VPROG_MASK, &vreg->ctrl_reg);
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+	return rc;
+}
+
 static unsigned int pm8xxx_ldo_get_mode(struct regulator_dev *rdev)
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
@@ -2066,6 +2137,38 @@
 	return rc;
 }
 
+static int pm8xxx_boost_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, BOOST_ENABLE,
+		BOOST_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_boost_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, BOOST_DISABLE,
+		BOOST_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
 static int pm8xxx_ldo_pin_control_enable(struct regulator_dev *rdev)
 {
 	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
@@ -2506,6 +2609,11 @@
 		pr_info("%s %-9s: %s, v=%7d uV\n",
 			action_label, vreg->rdesc.name, enable_label, uV);
 		break;
+	case PM8XXX_REGULATOR_TYPE_BOOST:
+		uV = pm8xxx_boost_get_voltage(rdev);
+		pr_info("%s %-9s: %s, v=%7d uV\n",
+			action_label, vreg->rdesc.name, enable_label, uV);
+		break;
 	default:
 		break;
 	}
@@ -2601,6 +2709,16 @@
 	.enable_time		= pm8xxx_enable_time,
 };
 
+static struct regulator_ops pm8xxx_boost_ops = {
+	.enable			= pm8xxx_boost_enable,
+	.disable		= pm8xxx_boost_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.set_voltage		= pm8xxx_boost_set_voltage,
+	.get_voltage		= pm8xxx_boost_get_voltage,
+	.list_voltage		= pm8xxx_boost_list_voltage,
+	.enable_time		= pm8xxx_enable_time,
+};
+
 /* Pin control regulator operations. */
 static struct regulator_ops pm8xxx_ldo_pc_ops = {
 	.enable			= pm8xxx_ldo_pin_control_enable,
@@ -2629,6 +2747,7 @@
 	[PM8XXX_REGULATOR_TYPE_VS]		= &pm8xxx_vs_ops,
 	[PM8XXX_REGULATOR_TYPE_VS300]		= &pm8xxx_vs300_ops,
 	[PM8XXX_REGULATOR_TYPE_NCP]		= &pm8xxx_ncp_ops,
+	[PM8XXX_REGULATOR_TYPE_BOOST]		= &pm8xxx_boost_ops,
 };
 
 static struct regulator_ops *pm8xxx_reg_pc_ops[PM8XXX_REGULATOR_TYPE_MAX] = {
@@ -2647,6 +2766,7 @@
 	[PM8XXX_REGULATOR_TYPE_VS]		= 0,
 	[PM8XXX_REGULATOR_TYPE_VS300]		= 0,
 	[PM8XXX_REGULATOR_TYPE_NCP]		= NCP_SET_POINTS,
+	[PM8XXX_REGULATOR_TYPE_BOOST]		= BOOST_SET_POINTS,
 };
 
 static int pm8xxx_init_ldo(struct pm8xxx_vreg *vreg, bool is_real)
@@ -2937,6 +3057,20 @@
 	return rc;
 }
 
+static int pm8xxx_init_boost(struct pm8xxx_vreg *vreg)
+{
+	int rc;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc) {
+		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
 static int __devinit pm8xxx_vreg_probe(struct platform_device *pdev)
 {
 	struct pm8xxx_regulator_core_platform_data *core_data;
@@ -2971,7 +3105,7 @@
 	if (vreg->rdesc.name == NULL) {
 		pr_err("regulator name missing\n");
 		return -EINVAL;
-	} else if (vreg->type < 0 || vreg->type > PM8XXX_REGULATOR_TYPE_MAX) {
+	} else if (vreg->type < 0 || vreg->type >= PM8XXX_REGULATOR_TYPE_MAX) {
 		pr_err("%s: regulator type=%d is invalid\n", vreg->rdesc.name,
 			vreg->type);
 		return -EINVAL;
@@ -3058,6 +3192,9 @@
 	case PM8XXX_REGULATOR_TYPE_NCP:
 		rc = pm8xxx_init_ncp(vreg);
 		break;
+	case PM8XXX_REGULATOR_TYPE_BOOST:
+		rc = pm8xxx_init_boost(vreg);
+		break;
 	default:
 		break;
 	}
@@ -3069,7 +3206,7 @@
 
 	if (!core_data->is_pin_controlled) {
 		vreg->rdev = regulator_register(rdesc, &pdev->dev,
-				&(pdata->init_data), vreg);
+				&(pdata->init_data), vreg, NULL);
 		if (IS_ERR(vreg->rdev)) {
 			rc = PTR_ERR(vreg->rdev);
 			vreg->rdev = NULL;
@@ -3078,7 +3215,7 @@
 		}
 	} else {
 		vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
-				&(pdata->init_data), vreg);
+				&(pdata->init_data), vreg, NULL);
 		if (IS_ERR(vreg->rdev_pc)) {
 			rc = PTR_ERR(vreg->rdev_pc);
 			vreg->rdev_pc = NULL;
diff --git a/drivers/regulator/pmic8058-regulator.c b/drivers/regulator/pmic8058-regulator.c
index e137b0f..01f4abf 100644
--- a/drivers/regulator/pmic8058-regulator.c
+++ b/drivers/regulator/pmic8058-regulator.c
@@ -1692,7 +1692,7 @@
 			      &= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
 
 		vreg->rdev = regulator_register(rdesc, &pdev->dev,
-				&vreg->pdata->init_data, vreg);
+				&vreg->pdata->init_data, vreg, NULL);
 		if (IS_ERR(vreg->rdev)) {
 			rc = PTR_ERR(vreg->rdev);
 			pr_err("%s: regulator_register failed for %s, rc=%d\n",
diff --git a/drivers/regulator/pmic8901-regulator.c b/drivers/regulator/pmic8901-regulator.c
index 6fd0a05..72894ba 100644
--- a/drivers/regulator/pmic8901-regulator.c
+++ b/drivers/regulator/pmic8901-regulator.c
@@ -954,7 +954,7 @@
 			      &= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
 
 		vreg->rdev = regulator_register(rdesc, &pdev->dev,
-				&vreg->pdata->init_data, vreg);
+				&vreg->pdata->init_data, vreg, NULL);
 		if (IS_ERR(vreg->rdev)) {
 			rc = PTR_ERR(vreg->rdev);
 			pr_err("%s: regulator_register failed for %s, rc=%d\n",
diff --git a/drivers/regulator/stub-regulator.c b/drivers/regulator/stub-regulator.c
new file mode 100644
index 0000000..1c4b935
--- /dev/null
+++ b/drivers/regulator/stub-regulator.c
@@ -0,0 +1,240 @@
+/*
+ * 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/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/stub-regulator.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define STUB_REGULATOR_MAX_NAME 40
+
+struct regulator_stub {
+	struct regulator_desc	rdesc;
+	struct regulator_dev	*rdev;
+	int			voltage;
+	bool			enabled;
+	int			mode;
+	int			hpm_min_load;
+	int			system_uA;
+	char			name[STUB_REGULATOR_MAX_NAME];
+};
+
+static int regulator_stub_set_voltage(struct regulator_dev *rdev, int min_uV,
+				  int max_uV, unsigned *selector)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	vreg_priv->voltage = min_uV;
+	return 0;
+}
+
+static int regulator_stub_get_voltage(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	return vreg_priv->voltage;
+}
+
+static int regulator_stub_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	struct regulation_constraints *constraints = rdev->constraints;
+
+	if (selector >= 2)
+		return -EINVAL;
+	else if (selector == 0)
+		return constraints->min_uV;
+	else
+		return constraints->max_uV;
+}
+
+static unsigned int regulator_stub_get_mode(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	return vreg_priv->mode;
+}
+
+static int regulator_stub_set_mode(struct regulator_dev *rdev,
+				   unsigned int mode)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+
+	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+		dev_err(&rdev->dev, "%s: invalid mode requested %u\n",
+							__func__, mode);
+		return -EINVAL;
+	}
+	vreg_priv->mode = mode;
+	return 0;
+}
+
+static unsigned int regulator_stub_get_optimum_mode(struct regulator_dev *rdev,
+		int input_uV, int output_uV, int load_uA)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	unsigned int mode;
+
+	if (load_uA + vreg_priv->system_uA >= vreg_priv->hpm_min_load)
+		mode = REGULATOR_MODE_NORMAL;
+	else
+		mode = REGULATOR_MODE_IDLE;
+
+	return mode;
+}
+
+static int regulator_stub_enable(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	vreg_priv->enabled = true;
+	return 0;
+}
+
+static int regulator_stub_disable(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	vreg_priv->enabled = false;
+	return 0;
+}
+
+static int regulator_stub_is_enabled(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	return vreg_priv->enabled;
+}
+
+/* Real regulator operations. */
+static struct regulator_ops regulator_stub_ops = {
+	.enable			= regulator_stub_enable,
+	.disable		= regulator_stub_disable,
+	.is_enabled		= regulator_stub_is_enabled,
+	.set_voltage		= regulator_stub_set_voltage,
+	.get_voltage		= regulator_stub_get_voltage,
+	.list_voltage		= regulator_stub_list_voltage,
+	.set_mode		= regulator_stub_set_mode,
+	.get_mode		= regulator_stub_get_mode,
+	.get_optimum_mode	= regulator_stub_get_optimum_mode,
+};
+
+static void regulator_stub_cleanup(struct regulator_stub *vreg_priv)
+{
+	if (vreg_priv && vreg_priv->rdev)
+		regulator_unregister(vreg_priv->rdev);
+	kfree(vreg_priv);
+}
+
+static int __devinit regulator_stub_probe(struct platform_device *pdev)
+{
+	struct stub_regulator_pdata *vreg_pdata;
+	struct regulator_desc *rdesc;
+	struct regulator_stub *vreg_priv;
+	int rc;
+
+	vreg_pdata = pdev->dev.platform_data;
+	if (!vreg_pdata) {
+		dev_err(&pdev->dev, "%s: no platform data\n", __func__);
+		return -EINVAL;
+	}
+
+	vreg_priv = kzalloc(sizeof(*vreg_priv), GFP_KERNEL);
+	if (!vreg_priv) {
+		dev_err(&pdev->dev, "%s: Unable to allocate memory\n",
+				__func__);
+		return -ENOMEM;
+	}
+	dev_set_drvdata(&pdev->dev, vreg_priv);
+
+	rdesc = &vreg_priv->rdesc;
+	strncpy(vreg_priv->name, vreg_pdata->init_data.constraints.name,
+						   STUB_REGULATOR_MAX_NAME);
+	rdesc->name = vreg_priv->name;
+	rdesc->ops = &regulator_stub_ops;
+
+	/*
+	 * Ensure that voltage set points are handled correctly for regulators
+	 * which have a specified voltage constraint range, as well as those
+	 * that do not.
+	 */
+	if (vreg_pdata->init_data.constraints.min_uV == 0 &&
+	    vreg_pdata->init_data.constraints.max_uV == 0)
+		rdesc->n_voltages = 0;
+	else
+		rdesc->n_voltages = 2;
+
+	rdesc->id    = pdev->id;
+	rdesc->owner = THIS_MODULE;
+	rdesc->type  = REGULATOR_VOLTAGE;
+	vreg_priv->system_uA = vreg_pdata->system_uA;
+	vreg_priv->hpm_min_load = vreg_pdata->hpm_min_load;
+	vreg_priv->voltage = vreg_pdata->init_data.constraints.min_uV;
+
+	vreg_priv->rdev = regulator_register(rdesc, &pdev->dev,
+			&(vreg_pdata->init_data), vreg_priv, NULL);
+	if (IS_ERR(vreg_priv->rdev)) {
+		rc = PTR_ERR(vreg_priv->rdev);
+		vreg_priv->rdev = NULL;
+		dev_err(&pdev->dev, "%s: regulator_register failed\n",
+				__func__);
+		goto err_probe;
+	}
+
+	return 0;
+
+err_probe:
+	regulator_stub_cleanup(vreg_priv);
+	return rc;
+}
+
+static int __devexit regulator_stub_remove(struct platform_device *pdev)
+{
+	struct regulator_stub *vreg_priv = dev_get_drvdata(&pdev->dev);
+
+	regulator_stub_cleanup(vreg_priv);
+	return 0;
+}
+
+static struct platform_driver regulator_stub_driver = {
+	.probe	= regulator_stub_probe,
+	.remove	= __devexit_p(regulator_stub_remove),
+	.driver	= {
+		.name	= STUB_REGULATOR_DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+int __init regulator_stub_init(void)
+{
+	static int registered;
+
+	if (registered)
+		return 0;
+	else
+		registered = 1;
+	return platform_driver_register(&regulator_stub_driver);
+}
+postcore_initcall(regulator_stub_init);
+EXPORT_SYMBOL(regulator_stub_init);
+
+static void __exit regulator_stub_exit(void)
+{
+	platform_driver_unregister(&regulator_stub_driver);
+}
+module_exit(regulator_stub_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("stub regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform: " STUB_REGULATOR_DRIVER_NAME);
diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c
index 1011873..d9278da 100644
--- a/drivers/regulator/tps6105x-regulator.c
+++ b/drivers/regulator/tps6105x-regulator.c
@@ -151,7 +151,8 @@
 	/* Register regulator with framework */
 	tps6105x->regulator = regulator_register(&tps6105x_regulator_desc,
 					     &tps6105x->client->dev,
-					     pdata->regulator_data, tps6105x);
+					     pdata->regulator_data, tps6105x,
+					     NULL);
 	if (IS_ERR(tps6105x->regulator)) {
 		ret = PTR_ERR(tps6105x->regulator);
 		dev_err(&tps6105x->client->dev,
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index fbddc15..8efb772 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -507,7 +507,7 @@
 
 		/* Register the regulators */
 		rdev = regulator_register(&tps->desc[i], &client->dev,
-					  init_data, tps);
+					  init_data, tps, NULL);
 		if (IS_ERR(rdev)) {
 			dev_err(&client->dev, "failed to register %s\n",
 				id->name);
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index bfffabc..0f86e56 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -605,7 +605,7 @@
 		tps->desc[i].owner = THIS_MODULE;
 
 		rdev = regulator_register(&tps->desc[i],
-					tps6507x_dev->dev, init_data, tps);
+					tps6507x_dev->dev, init_data, tps, NULL);
 		if (IS_ERR(rdev)) {
 			dev_err(tps6507x_dev->dev,
 				"failed to register %s regulator\n",
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 9166aa0..70b7b1f 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -651,7 +651,7 @@
 			hw->desc[i].n_voltages = 1;
 
 		hw->rdev[i] = regulator_register(&hw->desc[i], dev,
-						 init_data, hw);
+						 init_data, hw, NULL);
 		if (IS_ERR(hw->rdev[i])) {
 			ret = PTR_ERR(hw->rdev[i]);
 			hw->rdev[i] = NULL;
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index bb04a75..6a35c3a 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -365,7 +365,7 @@
 		return err;
 
 	rdev = regulator_register(&ri->desc, &pdev->dev,
-				  pdev->dev.platform_data, ri);
+				  pdev->dev.platform_data, ri, NULL);
 	if (IS_ERR(rdev)) {
 		dev_err(&pdev->dev, "failed to register regulator %s\n",
 				ri->desc.name);
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 425aab3..e436dcd 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -939,7 +939,7 @@
 		pmic->desc[i].owner = THIS_MODULE;
 
 		rdev = regulator_register(&pmic->desc[i],
-				tps65910->dev, reg_data, pmic);
+				tps65910->dev, reg_data, pmic, NULL);
 		if (IS_ERR(rdev)) {
 			dev_err(tps65910->dev,
 				"failed to register %s regulator\n",
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 87fe0f7..1c12070 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -1074,7 +1074,7 @@
 		break;
 	}
 
-	rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
+	rdev = regulator_register(&info->desc, &pdev->dev, initdata, info, NULL);
 	if (IS_ERR(rdev)) {
 		dev_err(&pdev->dev, "can't register %s, %ld\n",
 				info->desc.name, PTR_ERR(rdev));
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index a0982e8..38bb80d 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -556,7 +556,7 @@
 		wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data);
 
 	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
-					     pdata->dcdc[id], dcdc);
+					     pdata->dcdc[id], dcdc, NULL);
 	if (IS_ERR(dcdc->regulator)) {
 		ret = PTR_ERR(dcdc->regulator);
 		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -744,7 +744,7 @@
 	dcdc->desc.owner = THIS_MODULE;
 
 	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
-					     pdata->dcdc[id], dcdc);
+					     pdata->dcdc[id], dcdc, NULL);
 	if (IS_ERR(dcdc->regulator)) {
 		ret = PTR_ERR(dcdc->regulator);
 		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -871,7 +871,7 @@
 	dcdc->desc.owner = THIS_MODULE;
 
 	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
-					     pdata->dcdc[id], dcdc);
+					     pdata->dcdc[id], dcdc, NULL);
 	if (IS_ERR(dcdc->regulator)) {
 		ret = PTR_ERR(dcdc->regulator);
 		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -970,7 +970,7 @@
 	dcdc->desc.owner = THIS_MODULE;
 
 	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
-					     pdata->epe[id], dcdc);
+					     pdata->epe[id], dcdc, NULL);
 	if (IS_ERR(dcdc->regulator)) {
 		ret = PTR_ERR(dcdc->regulator);
 		dev_err(wm831x->dev, "Failed to register EPE%d: %d\n",
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 01f27c7..d3ad3f5 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -189,7 +189,7 @@
 	isink->desc.owner = THIS_MODULE;
 
 	isink->regulator = regulator_register(&isink->desc, &pdev->dev,
-					     pdata->isink[id], isink);
+					     pdata->isink[id], isink, NULL);
 	if (IS_ERR(isink->regulator)) {
 		ret = PTR_ERR(isink->regulator);
 		dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n",
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 2220cf8..d0fe563 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -345,7 +345,7 @@
 	ldo->desc.owner = THIS_MODULE;
 
 	ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
-					     pdata->ldo[id], ldo);
+					     pdata->ldo[id], ldo, NULL);
 	if (IS_ERR(ldo->regulator)) {
 		ret = PTR_ERR(ldo->regulator);
 		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
@@ -609,7 +609,7 @@
 	ldo->desc.owner = THIS_MODULE;
 
 	ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
-					     pdata->ldo[id], ldo);
+					     pdata->ldo[id], ldo, NULL);
 	if (IS_ERR(ldo->regulator)) {
 		ret = PTR_ERR(ldo->regulator);
 		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
@@ -799,7 +799,7 @@
 	ldo->desc.owner = THIS_MODULE;
 
 	ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
-					     pdata->ldo[id], ldo);
+					     pdata->ldo[id], ldo, NULL);
 	if (IS_ERR(ldo->regulator)) {
 		ret = PTR_ERR(ldo->regulator);
 		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 1bcb22c..6894009 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1428,7 +1428,7 @@
 	/* register regulator */
 	rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
 				  pdev->dev.platform_data,
-				  dev_get_drvdata(&pdev->dev));
+				  dev_get_drvdata(&pdev->dev), NULL);
 	if (IS_ERR(rdev)) {
 		dev_err(&pdev->dev, "failed to register %s\n",
 			wm8350_reg[pdev->id].name);
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 0f12c70..f468f8a 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -325,7 +325,7 @@
 	struct regulator_dev *rdev;
 
 	rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
-				  pdev->dev.platform_data, wm8400);
+				  pdev->dev.platform_data, wm8400, NULL);
 
 	if (IS_ERR(rdev))
 		return PTR_ERR(rdev);
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 35b2958..6f3132c 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -256,7 +256,7 @@
 		ldo->is_enabled = true;
 
 	ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
-					     pdata->ldo[id].init_data, ldo);
+					     pdata->ldo[id].init_data, ldo, NULL);
 	if (IS_ERR(ldo->regulator)) {
 		ret = PTR_ERR(ldo->regulator);
 		dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 01a7df5..b82a155 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -66,7 +66,7 @@
 	 */
 	delta = timespec_sub(old_system, old_rtc);
 	delta_delta = timespec_sub(delta, old_delta);
-	if (abs(delta_delta.tv_sec)  >= 2) {
+	if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
 		/*
 		 * if delta_delta is too large, assume time correction
 		 * has occured and set old_delta to the current delta.
@@ -100,9 +100,8 @@
 	rtc_tm_to_time(&tm, &new_rtc.tv_sec);
 	new_rtc.tv_nsec = 0;
 
-	if (new_rtc.tv_sec <= old_rtc.tv_sec) {
-		if (new_rtc.tv_sec < old_rtc.tv_sec)
-			pr_debug("%s:  time travel!\n", dev_name(&rtc->dev));
+	if (new_rtc.tv_sec < old_rtc.tv_sec) {
+		pr_debug("%s:  time travel!\n", dev_name(&rtc->dev));
 		return 0;
 	}
 
@@ -119,7 +118,8 @@
 	sleep_time = timespec_sub(sleep_time,
 			timespec_sub(new_system, old_system));
 
-	timekeeping_inject_sleeptime(&sleep_time);
+	if (sleep_time.tv_sec >= 0)
+		timekeeping_inject_sleeptime(&sleep_time);
 	return 0;
 }
 
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index eb4c883..38d1dc7 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -227,11 +227,11 @@
 		alarm->time.tm_hour = now.tm_hour;
 
 	/* For simplicity, only support date rollover for now */
-	if (alarm->time.tm_mday == -1) {
+	if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) {
 		alarm->time.tm_mday = now.tm_mday;
 		missing = day;
 	}
-	if (alarm->time.tm_mon == -1) {
+	if ((unsigned)alarm->time.tm_mon >= 12) {
 		alarm->time.tm_mon = now.tm_mon;
 		if (missing == none)
 			missing = month;
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index eda128f..64aedd8 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -357,10 +357,19 @@
 static struct rtc_class_ops m41t80_rtc_ops = {
 	.read_time = m41t80_rtc_read_time,
 	.set_time = m41t80_rtc_set_time,
+	/*
+	 * XXX - m41t80 alarm functionality is reported broken.
+	 * until it is fixed, don't register alarm functions.
+	 *
 	.read_alarm = m41t80_rtc_read_alarm,
 	.set_alarm = m41t80_rtc_set_alarm,
+	*/
 	.proc = m41t80_rtc_proc,
+	/*
+	 * See above comment on broken alarm
+	 *
 	.alarm_irq_enable = m41t80_rtc_alarm_irq_enable,
+	*/
 };
 
 #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 5c56741..cda9bd6 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -87,6 +87,12 @@
 	}
 }
 
+static ssize_t ccwgroup_online_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count);
+static ssize_t ccwgroup_online_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf);
 /*
  * Provide an 'ungroup' attribute so the user can remove group devices no
  * longer needed or accidentially created. Saves memory :)
@@ -134,6 +140,20 @@
 }
 
 static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
+static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
+
+static struct attribute *ccwgroup_attrs[] = {
+	&dev_attr_online.attr,
+	&dev_attr_ungroup.attr,
+	NULL,
+};
+static struct attribute_group ccwgroup_attr_group = {
+	.attrs = ccwgroup_attrs,
+};
+static const struct attribute_group *ccwgroup_attr_groups[] = {
+	&ccwgroup_attr_group,
+	NULL,
+};
 
 static void
 ccwgroup_release (struct device *dev)
@@ -293,25 +313,17 @@
 	}
 
 	dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev));
-
+	gdev->dev.groups = ccwgroup_attr_groups;
 	rc = device_add(&gdev->dev);
 	if (rc)
 		goto error;
 	get_device(&gdev->dev);
-	rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
-
-	if (rc) {
-		device_unregister(&gdev->dev);
-		goto error;
-	}
-
 	rc = __ccwgroup_create_symlinks(gdev);
 	if (!rc) {
 		mutex_unlock(&gdev->reg_mutex);
 		put_device(&gdev->dev);
 		return 0;
 	}
-	device_remove_file(&gdev->dev, &dev_attr_ungroup);
 	device_unregister(&gdev->dev);
 error:
 	for (i = 0; i < num_devices; i++)
@@ -423,7 +435,7 @@
 	int ret;
 
 	if (!dev->driver)
-		return -ENODEV;
+		return -EINVAL;
 
 	gdev = to_ccwgroupdev(dev);
 	gdrv = to_ccwgroupdrv(dev->driver);
@@ -456,8 +468,6 @@
 	return sprintf(buf, online ? "1\n" : "0\n");
 }
 
-static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
-
 static int
 ccwgroup_probe (struct device *dev)
 {
@@ -469,12 +479,7 @@
 	gdev = to_ccwgroupdev(dev);
 	gdrv = to_ccwgroupdrv(dev->driver);
 
-	if ((ret = device_create_file(dev, &dev_attr_online)))
-		return ret;
-
 	ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV;
-	if (ret)
-		device_remove_file(dev, &dev_attr_online);
 
 	return ret;
 }
@@ -485,9 +490,6 @@
 	struct ccwgroup_device *gdev;
 	struct ccwgroup_driver *gdrv;
 
-	device_remove_file(dev, &dev_attr_online);
-	device_remove_file(dev, &dev_attr_ungroup);
-
 	if (!dev->driver)
 		return 0;
 
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index fd69da3..e2c9ac5 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2742,9 +2742,14 @@
 int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
 {
 	int cast_type = RTN_UNSPEC;
+	struct neighbour *n = NULL;
+	struct dst_entry *dst;
 
-	if (skb_dst(skb) && skb_dst(skb)->neighbour) {
-		cast_type = skb_dst(skb)->neighbour->type;
+	dst = skb_dst(skb);
+	if (dst)
+		n = dst_get_neighbour(dst);
+	if (n) {
+		cast_type = n->type;
 		if ((cast_type == RTN_BROADCAST) ||
 		    (cast_type == RTN_MULTICAST) ||
 		    (cast_type == RTN_ANYCAST))
@@ -2787,6 +2792,9 @@
 static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
 		struct sk_buff *skb, int ipv, int cast_type)
 {
+	struct neighbour *n = NULL;
+	struct dst_entry *dst;
+
 	memset(hdr, 0, sizeof(struct qeth_hdr));
 	hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
 	hdr->hdr.l3.ext_flags = 0;
@@ -2804,13 +2812,16 @@
 	}
 
 	hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr);
+	dst = skb_dst(skb);
+	if (dst)
+		n = dst_get_neighbour(dst);
 	if (ipv == 4) {
 		/* IPv4 */
 		hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type);
 		memset(hdr->hdr.l3.dest_addr, 0, 12);
-		if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
+		if (n) {
 			*((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
-			    *((u32 *) skb_dst(skb)->neighbour->primary_key);
+			    *((u32 *) n->primary_key);
 		} else {
 			/* fill in destination address used in ip header */
 			*((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
@@ -2821,9 +2832,9 @@
 		hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type);
 		if (card->info.type == QETH_CARD_TYPE_IQD)
 			hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU;
-		if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
+		if (n) {
 			memcpy(hdr->hdr.l3.dest_addr,
-			       skb_dst(skb)->neighbour->primary_key, 16);
+			       n->primary_key, 16);
 		} else {
 			/* fill in destination address used in ip header */
 			memcpy(hdr->hdr.l3.dest_addr,
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 2a4991d..3a417df 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -57,6 +57,10 @@
 {
 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
 
+	/* if previous slave_alloc returned early, there is nothing to do */
+	if (!zfcp_sdev->port)
+		return;
+
 	zfcp_erp_lun_shutdown_wait(sdev, "scssd_1");
 	put_device(&zfcp_sdev->port->dev);
 }
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 3382475..c7b6fed 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
@@ -1108,6 +1109,9 @@
 		unique_id++;
 	}
 
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+			       PCIE_LINK_STATE_CLKPM);
+
 	error = pci_enable_device(pdev);
 	if (error)
 		goto out;
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index b2d6611..143f268 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -985,7 +985,7 @@
 		csk->saddr.sin_addr.s_addr = chba->ipv4addr;
 
 	csk->rss_qid = 0;
-	csk->l2t = t3_l2t_get(t3dev, dst->neighbour, ndev);
+	csk->l2t = t3_l2t_get(t3dev, dst_get_neighbour(dst), ndev);
 	if (!csk->l2t) {
 		pr_err("NO l2t available.\n");
 		return -EINVAL;
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index f3a4cd7..ae13c49 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -1160,7 +1160,7 @@
 	cxgbi_sock_set_flag(csk, CTPF_HAS_ATID);
 	cxgbi_sock_get(csk);
 
-	csk->l2t = cxgb4_l2t_get(lldi->l2t, csk->dst->neighbour, ndev, 0);
+	csk->l2t = cxgb4_l2t_get(lldi->l2t, dst_get_neighbour(csk->dst), ndev, 0);
 	if (!csk->l2t) {
 		pr_err("%s, cannot alloc l2t.\n", ndev->name);
 		goto rel_resource;
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index a2a9c7c..77ac217 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -492,7 +492,7 @@
 		goto err_out;
 	}
 	dst = &rt->dst;
-	ndev = dst->neighbour->dev;
+	ndev = dst_get_neighbour(dst)->dev;
 
 	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
 		pr_info("multi-cast route %pI4, port %u, dev %s.\n",
@@ -506,7 +506,7 @@
 		ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr);
 		mtu = ndev->mtu;
 		pr_info("rt dev %s, loopback -> %s, mtu %u.\n",
-			dst->neighbour->dev->name, ndev->name, mtu);
+			dst_get_neighbour(dst)->dev->name, ndev->name, mtu);
 	}
 
 	cdev = cxgbi_device_find_by_netdev(ndev, &port);
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 0119b81..d973325 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -398,7 +398,15 @@
 
 	spin_lock_irqsave(q->queue_lock, flags);
 	sdev = q->queuedata;
-	if (sdev && sdev->scsi_dh_data)
+	if (!sdev) {
+		spin_unlock_irqrestore(q->queue_lock, flags);
+		err = SCSI_DH_NOSYS;
+		if (fn)
+			fn(data, err);
+		return err;
+	}
+
+	if (sdev->scsi_dh_data)
 		scsi_dh = sdev->scsi_dh_data->scsi_dh;
 	dev = get_device(&sdev->sdev_gendev);
 	if (!scsi_dh || !dev ||
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 8885b3e..f829adc 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1561,6 +1561,7 @@
 	stats->InvalidCRCCount++;
 	if (stats->InvalidCRCCount < 5)
 		printk(KERN_WARNING "fcoe: dropping frame with CRC error\n");
+	put_cpu();
 	return -EINVAL;
 }
 
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 4f7a582..351dc0b 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -286,6 +286,7 @@
 {
 	struct Scsi_Host *shost = dev_to_shost(dev);
 	struct device *parent = dev->parent;
+	struct request_queue *q;
 
 	scsi_proc_hostdir_rm(shost->hostt);
 
@@ -293,9 +294,11 @@
 		kthread_stop(shost->ehandler);
 	if (shost->work_q)
 		destroy_workqueue(shost->work_q);
-	if (shost->uspace_req_q) {
-		kfree(shost->uspace_req_q->queuedata);
-		scsi_free_queue(shost->uspace_req_q);
+	q = shost->uspace_req_q;
+	if (q) {
+		kfree(q->queuedata);
+		q->queuedata = NULL;
+		scsi_free_queue(q);
 	}
 
 	scsi_destroy_command_freelist(shost);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 78c2e20..56a9f3f 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -3300,6 +3301,13 @@
 		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
 		pmcsr |= PCI_D0;
 		pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+		/*
+		 * The P600 requires a small delay when changing states.
+		 * Otherwise we may think the board did not reset and we bail.
+		 * This for kdump only and is particular to the P600.
+		 */
+		msleep(500);
 	}
 	return 0;
 }
@@ -3880,6 +3888,10 @@
 		dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
 		return -ENODEV;
 	}
+
+	pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
+			       PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
+
 	err = pci_enable_device(h->pdev);
 	if (err) {
 		dev_warn(&h->pdev->dev, "unable to enable PCI device\n");
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 888086c..c5c7c3a 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -8812,7 +8812,7 @@
 	uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg32);
 	if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT))
 		ioa_cfg->needs_hard_reset = 1;
-	if (interrupts & IPR_PCII_ERROR_INTERRUPTS)
+	if ((interrupts & IPR_PCII_ERROR_INTERRUPTS) || reset_devices)
 		ioa_cfg->needs_hard_reset = 1;
 	if (interrupts & IPR_PCII_IOA_UNIT_CHECKED)
 		ioa_cfg->ioa_unit_checked = 1;
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h
index d1de633..8efeb6b 100644
--- a/drivers/scsi/isci/isci.h
+++ b/drivers/scsi/isci/isci.h
@@ -97,7 +97,7 @@
 #define SCU_MAX_COMPLETION_QUEUE_SHIFT	  (ilog2(SCU_MAX_COMPLETION_QUEUE_ENTRIES))
 
 #define SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES (4096)
-#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE   (1024)
+#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE   (1024U)
 #define SCU_INVALID_FRAME_INDEX             (0xFFFF)
 
 #define SCU_IO_REQUEST_MAX_SGE_SIZE         (0x00FFFFFF)
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index 486b113..38a99d2 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -678,7 +678,7 @@
 	configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask;
 
 	if (!configure_phy_mask)
-		return;
+		goto done;
 
 	for (index = 0; index < SCI_MAX_PHYS; index++) {
 		if ((configure_phy_mask & (1 << index)) == 0)
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index b5d3a8c..225b196 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -1490,29 +1490,30 @@
 		return SCI_SUCCESS;
 
 	case SCI_REQ_SMP_WAIT_RESP: {
-		struct smp_resp *rsp_hdr = &ireq->smp.rsp;
-		void *frame_header;
+		struct sas_task *task = isci_request_access_task(ireq);
+		struct scatterlist *sg = &task->smp_task.smp_resp;
+		void *frame_header, *kaddr;
+		u8 *rsp;
 
 		sci_unsolicited_frame_control_get_header(&ihost->uf_control,
-							      frame_index,
-							      &frame_header);
+							 frame_index,
+							 &frame_header);
+		kaddr = kmap_atomic(sg_page(sg), KM_IRQ0);
+		rsp = kaddr + sg->offset;
+		sci_swab32_cpy(rsp, frame_header, 1);
 
-		/* byte swap the header. */
-		word_cnt = SMP_RESP_HDR_SZ / sizeof(u32);
-		sci_swab32_cpy(rsp_hdr, frame_header, word_cnt);
-
-		if (rsp_hdr->frame_type == SMP_RESPONSE) {
+		if (rsp[0] == SMP_RESPONSE) {
 			void *smp_resp;
 
 			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
-								      frame_index,
-								      &smp_resp);
+								 frame_index,
+								 &smp_resp);
 
-			word_cnt = (sizeof(struct smp_resp) - SMP_RESP_HDR_SZ) /
-				sizeof(u32);
-
-			sci_swab32_cpy(((u8 *) rsp_hdr) + SMP_RESP_HDR_SZ,
-				       smp_resp, word_cnt);
+			word_cnt = (sg->length/4)-1;
+			if (word_cnt > 0)
+				word_cnt = min_t(unsigned int, word_cnt,
+						 SCU_UNSOLICITED_FRAME_BUFFER_SIZE/4);
+			sci_swab32_cpy(rsp + 4, smp_resp, word_cnt);
 
 			ireq->scu_status = SCU_TASK_DONE_GOOD;
 			ireq->sci_status = SCI_SUCCESS;
@@ -1528,12 +1529,13 @@
 				__func__,
 				ireq,
 				frame_index,
-				rsp_hdr->frame_type);
+				rsp[0]);
 
 			ireq->scu_status = SCU_TASK_DONE_SMP_FRM_TYPE_ERR;
 			ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
 		}
+		kunmap_atomic(kaddr, KM_IRQ0);
 
 		sci_controller_release_frame(ihost, frame_index);
 
@@ -2603,18 +2605,7 @@
 			status   = SAM_STAT_GOOD;
 			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 
-			if (task->task_proto == SAS_PROTOCOL_SMP) {
-				void *rsp = &request->smp.rsp;
-
-				dev_dbg(&ihost->pdev->dev,
-					"%s: SMP protocol completion\n",
-					__func__);
-
-				sg_copy_from_buffer(
-					&task->smp_task.smp_resp, 1,
-					rsp, sizeof(struct smp_resp));
-			} else if (completion_status
-				   == SCI_IO_SUCCESS_IO_DONE_EARLY) {
+			if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
 
 				/* This was an SSP / STP / SATA transfer.
 				 * There is a possibility that less data than
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 7a1d5a9..58d70b6 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -174,9 +174,6 @@
 			};
 		} ssp;
 		struct {
-			struct smp_resp rsp;
-		} smp;
-		struct {
 			struct isci_stp_request req;
 			struct host_to_dev_fis cmd;
 			struct dev_to_host_fis rsp;
diff --git a/drivers/scsi/isci/sas.h b/drivers/scsi/isci/sas.h
index 462b151..dc26b4a 100644
--- a/drivers/scsi/isci/sas.h
+++ b/drivers/scsi/isci/sas.h
@@ -204,8 +204,6 @@
 	u8 req_data[0];
 }  __packed;
 
-#define SMP_RESP_HDR_SZ	4
-
 /*
  * struct sci_sas_address - This structure depicts how a SAS address is
  *    represented by SCI.
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 16ad97d..37cbe4d 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -199,6 +199,8 @@
 	phy->virtual = dr->virtual;
 	phy->last_da_index = -1;
 
+	phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr);
+	phy->phy->identify.device_type = phy->attached_dev_type;
 	phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
 	phy->phy->identify.target_port_protocols = phy->attached_tproto;
 	phy->phy->identify.phy_identifier = phy_id;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 2d8cdce..e6e30f4 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1906,7 +1906,6 @@
 static enum
 blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
-	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
 	struct megasas_instance *instance;
 	unsigned long flags;
 
@@ -1915,7 +1914,7 @@
 		return BLK_EH_NOT_HANDLED;
 	}
 
-	instance = cmd->instance;
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
 	if (!(instance->flag & MEGASAS_FW_BUSY)) {
 		/* FW is busy, throttle IO */
 		spin_lock_irqsave(instance->host->host_lock, flags);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 83035bd..10f16a3 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -66,6 +66,8 @@
 
 #define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
 
+#define MAX_HBA_QUEUE_DEPTH	30000
+#define MAX_CHAIN_DEPTH		100000
 static int max_queue_depth = -1;
 module_param(max_queue_depth, int, 0);
 MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
@@ -1082,41 +1084,6 @@
 }
 
 /**
- * _base_save_msix_table - backup msix vector table
- * @ioc: per adapter object
- *
- * This address an errata where diag reset clears out the table
- */
-static void
-_base_save_msix_table(struct MPT2SAS_ADAPTER *ioc)
-{
-	int i;
-
-	if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
-		return;
-
-	for (i = 0; i < ioc->msix_vector_count; i++)
-		ioc->msix_table_backup[i] = ioc->msix_table[i];
-}
-
-/**
- * _base_restore_msix_table - this restores the msix vector table
- * @ioc: per adapter object
- *
- */
-static void
-_base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc)
-{
-	int i;
-
-	if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
-		return;
-
-	for (i = 0; i < ioc->msix_vector_count; i++)
-		ioc->msix_table[i] = ioc->msix_table_backup[i];
-}
-
-/**
  * _base_check_enable_msix - checks MSIX capabable.
  * @ioc: per adapter object
  *
@@ -1128,7 +1095,7 @@
 {
 	int base;
 	u16 message_control;
-	u32 msix_table_offset;
+
 
 	base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
 	if (!base) {
@@ -1141,14 +1108,8 @@
 	pci_read_config_word(ioc->pdev, base + 2, &message_control);
 	ioc->msix_vector_count = (message_control & 0x3FF) + 1;
 
-	/* get msix table  */
-	pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset);
-	msix_table_offset &= 0xFFFFFFF8;
-	ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset);
-
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
-	    "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name,
-	    ioc->msix_vector_count, msix_table_offset, ioc->msix_table));
+	    "vector_count(%d)\n", ioc->name, ioc->msix_vector_count));
 	return 0;
 }
 
@@ -1162,8 +1123,6 @@
 {
 	if (ioc->msix_enable) {
 		pci_disable_msix(ioc->pdev);
-		kfree(ioc->msix_table_backup);
-		ioc->msix_table_backup = NULL;
 		ioc->msix_enable = 0;
 	}
 }
@@ -1189,14 +1148,6 @@
 	if (_base_check_enable_msix(ioc) != 0)
 		goto try_ioapic;
 
-	ioc->msix_table_backup = kcalloc(ioc->msix_vector_count,
-	    sizeof(u32), GFP_KERNEL);
-	if (!ioc->msix_table_backup) {
-		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
-		    "msix_table_backup failed!!!\n", ioc->name));
-		goto try_ioapic;
-	}
-
 	memset(&entries, 0, sizeof(struct msix_entry));
 	r = pci_enable_msix(ioc->pdev, &entries, 1);
 	if (r) {
@@ -2149,8 +2100,6 @@
 		}
 		if (ioc->chain_dma_pool)
 			pci_pool_destroy(ioc->chain_dma_pool);
-	}
-	if (ioc->chain_lookup) {
 		free_pages((ulong)ioc->chain_lookup, ioc->chain_pages);
 		ioc->chain_lookup = NULL;
 	}
@@ -2168,9 +2117,7 @@
 _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
 {
 	struct mpt2sas_facts *facts;
-	u32 queue_size, queue_diff;
 	u16 max_sge_elements;
-	u16 num_of_reply_frames;
 	u16 chains_needed_per_io;
 	u32 sz, total_sz;
 	u32 retry_sz;
@@ -2197,7 +2144,8 @@
 		max_request_credit = (max_queue_depth < facts->RequestCredit)
 		    ? max_queue_depth : facts->RequestCredit;
 	else
-		max_request_credit = facts->RequestCredit;
+		max_request_credit = min_t(u16, facts->RequestCredit,
+		    MAX_HBA_QUEUE_DEPTH);
 
 	ioc->hba_queue_depth = max_request_credit;
 	ioc->hi_priority_depth = facts->HighPriorityCredit;
@@ -2238,50 +2186,25 @@
 	}
 	ioc->chains_needed_per_io = chains_needed_per_io;
 
-	/* reply free queue sizing - taking into account for events */
-	num_of_reply_frames = ioc->hba_queue_depth + 32;
+	/* reply free queue sizing - taking into account for 64 FW events */
+	ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
 
-	/* number of replies frames can't be a multiple of 16 */
-	/* decrease number of reply frames by 1 */
-	if (!(num_of_reply_frames % 16))
-		num_of_reply_frames--;
-
-	/* calculate number of reply free queue entries
-	 *  (must be multiple of 16)
-	 */
-
-	/* (we know reply_free_queue_depth is not a multiple of 16) */
-	queue_size = num_of_reply_frames;
-	queue_size += 16 - (queue_size % 16);
-	ioc->reply_free_queue_depth = queue_size;
-
-	/* reply descriptor post queue sizing */
-	/* this size should be the number of request frames + number of reply
-	 * frames
-	 */
-
-	queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1;
-	/* round up to 16 byte boundary */
-	if (queue_size % 16)
-		queue_size += 16 - (queue_size % 16);
-
-	/* check against IOC maximum reply post queue depth */
-	if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) {
-		queue_diff = queue_size -
-		    facts->MaxReplyDescriptorPostQueueDepth;
-
-		/* round queue_diff up to multiple of 16 */
-		if (queue_diff % 16)
-			queue_diff += 16 - (queue_diff % 16);
-
-		/* adjust hba_queue_depth, reply_free_queue_depth,
-		 * and queue_size
-		 */
-		ioc->hba_queue_depth -= (queue_diff / 2);
-		ioc->reply_free_queue_depth -= (queue_diff / 2);
-		queue_size = facts->MaxReplyDescriptorPostQueueDepth;
+	/* align the reply post queue on the next 16 count boundary */
+	if (!ioc->reply_free_queue_depth % 16)
+		ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + 16;
+	else
+		ioc->reply_post_queue_depth = ioc->reply_free_queue_depth +
+				32 - (ioc->reply_free_queue_depth % 16);
+	if (ioc->reply_post_queue_depth >
+	    facts->MaxReplyDescriptorPostQueueDepth) {
+		ioc->reply_post_queue_depth = min_t(u16,
+		    (facts->MaxReplyDescriptorPostQueueDepth -
+		    (facts->MaxReplyDescriptorPostQueueDepth % 16)),
+		    (ioc->hba_queue_depth - (ioc->hba_queue_depth % 16)));
+		ioc->reply_free_queue_depth = ioc->reply_post_queue_depth - 16;
+		ioc->hba_queue_depth = ioc->reply_free_queue_depth - 64;
 	}
-	ioc->reply_post_queue_depth = queue_size;
+
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
 	    "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
@@ -2367,15 +2290,12 @@
 	    "depth(%d)\n", ioc->name, ioc->request,
 	    ioc->scsiio_depth));
 
-	/* loop till the allocation succeeds */
-	do {
-		sz = ioc->chain_depth * sizeof(struct chain_tracker);
-		ioc->chain_pages = get_order(sz);
-		ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
-		    GFP_KERNEL, ioc->chain_pages);
-		if (ioc->chain_lookup == NULL)
-			ioc->chain_depth -= 100;
-	} while (ioc->chain_lookup == NULL);
+	ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH);
+	sz = ioc->chain_depth * sizeof(struct chain_tracker);
+	ioc->chain_pages = get_order(sz);
+
+	ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
+	    GFP_KERNEL, ioc->chain_pages);
 	ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
 	    ioc->request_sz, 16, 0);
 	if (!ioc->chain_dma_pool) {
@@ -3513,9 +3433,6 @@
 	u32 hcb_size;
 
 	printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
-
-	_base_save_msix_table(ioc);
-
 	drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
 	    ioc->name));
 
@@ -3611,7 +3528,6 @@
 		goto out;
 	}
 
-	_base_restore_msix_table(ioc);
 	printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
 	return 0;
 
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 41a57a7..e1735f9 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -626,8 +626,6 @@
  * @wait_for_port_enable_to_complete:
  * @msix_enable: flag indicating msix is enabled
  * @msix_vector_count: number msix vectors
- * @msix_table: virt address to the msix table
- * @msix_table_backup: backup msix table
  * @scsi_io_cb_idx: shost generated commands
  * @tm_cb_idx: task management commands
  * @scsih_cb_idx: scsih internal commands
@@ -768,8 +766,6 @@
 
 	u8		msix_enable;
 	u16		msix_vector_count;
-	u32		*msix_table;
-	u32		*msix_table_backup;
 	u32		ioc_reset_count;
 
 	/* internal commands, callback index */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 8dc2ad4..aa51195 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -974,8 +974,8 @@
 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
 	if (list_empty(&ioc->free_chain_list)) {
 		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-		printk(MPT2SAS_WARN_FMT "chain buffers not available\n",
-		    ioc->name);
+		dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not "
+			"available\n", ioc->name));
 		return NULL;
 	}
 	chain_req = list_entry(ioc->free_chain_list.next,
@@ -4145,7 +4145,7 @@
 	/* insert into event log */
 	sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
 	     sizeof(Mpi2EventDataSasDeviceStatusChange_t);
-	event_reply = kzalloc(sz, GFP_KERNEL);
+	event_reply = kzalloc(sz, GFP_ATOMIC);
 	if (!event_reply) {
 		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 		    ioc->name, __FILE__, __LINE__, __func__);
@@ -6425,6 +6425,7 @@
 			} else
 				sas_target_priv_data = NULL;
 			raid_device->responding = 1;
+			spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 			starget_printk(KERN_INFO, raid_device->starget,
 			    "handle(0x%04x), wwid(0x%016llx)\n", handle,
 			    (unsigned long long)raid_device->wwid);
@@ -6435,16 +6436,16 @@
 			 */
 			_scsih_init_warpdrive_properties(ioc, raid_device);
 			if (raid_device->handle == handle)
-				goto out;
+				return;
 			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
 			    raid_device->handle);
 			raid_device->handle = handle;
 			if (sas_target_priv_data)
 				sas_target_priv_data->handle = handle;
-			goto out;
+			return;
 		}
 	}
- out:
+
 	spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 }
 
@@ -7211,6 +7212,7 @@
 	}
 
 	sas_remove_host(shost);
+	mpt2sas_base_detach(ioc);
 	list_del(&ioc->list);
 	scsi_remove_host(shost);
 	scsi_host_put(shost);
@@ -7318,22 +7320,27 @@
 	/* SAS Device List */
 	list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
 	    list) {
-		spin_lock_irqsave(&ioc->sas_device_lock, flags);
-		list_move_tail(&sas_device->list, &ioc->sas_device_list);
-		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
 		if (ioc->hide_drives)
 			continue;
 
 		if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
 		    sas_device->sas_address_parent)) {
-			_scsih_sas_device_remove(ioc, sas_device);
+			list_del(&sas_device->list);
+			kfree(sas_device);
+			continue;
 		} else if (!sas_device->starget) {
 			mpt2sas_transport_port_remove(ioc,
 			    sas_device->sas_address,
 			    sas_device->sas_address_parent);
-			_scsih_sas_device_remove(ioc, sas_device);
+			list_del(&sas_device->list);
+			kfree(sas_device);
+			continue;
+
 		}
+		spin_lock_irqsave(&ioc->sas_device_lock, flags);
+		list_move_tail(&sas_device->list, &ioc->sas_device_list);
+		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 	}
 }
 
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 28d9c9d..72ab1e6 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1407,6 +1407,8 @@
 
 	blk_start_request(req);
 
+	scmd_printk(KERN_INFO, cmd, "killing request\n");
+
 	sdev = cmd->device;
 	starget = scsi_target(sdev);
 	shost = sdev->host;
@@ -1488,7 +1490,6 @@
 	struct request *req;
 
 	if (!sdev) {
-		printk("scsi: killing requests for dead queue\n");
 		while ((req = blk_peek_request(q)) != NULL)
 			scsi_kill_request(req, q);
 		return;
@@ -1697,6 +1698,15 @@
 
 void scsi_free_queue(struct request_queue *q)
 {
+	unsigned long flags;
+
+	WARN_ON(q->queuedata);
+
+	/* cause scsi_request_fn() to kill all non-finished requests */
+	spin_lock_irqsave(q->queue_lock, flags);
+	q->request_fn(q);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
 	blk_cleanup_queue(q);
 }
 
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 44e8ca3..b3c6d95 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -319,10 +319,7 @@
 	return sdev;
 
 out_device_destroy:
-	scsi_device_set_state(sdev, SDEV_DEL);
-	transport_destroy_device(&sdev->sdev_gendev);
-	put_device(&sdev->sdev_dev);
-	put_device(&sdev->sdev_gendev);
+	__scsi_remove_device(sdev);
 out:
 	if (display_failure_msg)
 		printk(ALLOC_FAILURE_MSG, __func__);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 953773c..7d8b5d8 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1073,6 +1073,10 @@
 	SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n",
 						disk->disk_name, cmd));
 
+	error = scsi_verify_blk_ioctl(bdev, cmd);
+	if (error < 0)
+		return error;
+
 	/*
 	 * If we are in the middle of error recovery, don't let anyone
 	 * else try and use this device.  Also, if error recovery fails, it
@@ -1095,7 +1099,7 @@
 			error = scsi_ioctl(sdp, cmd, p);
 			break;
 		default:
-			error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p);
+			error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
 			if (error != -ENOTTY)
 				break;
 			error = scsi_ioctl(sdp, cmd, p);
@@ -1265,6 +1269,11 @@
 			   unsigned int cmd, unsigned long arg)
 {
 	struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
+	int ret;
+
+	ret = scsi_verify_blk_ioctl(bdev, cmd);
+	if (ret < 0)
+		return -ENOIOCTLCMD;
 
 	/*
 	 * If we are in the middle of error recovery, don't let anyone
@@ -1276,8 +1285,6 @@
 		return -ENODEV;
 	       
 	if (sdev->host->hostt->compat_ioctl) {
-		int ret;
-
 		ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
 
 		return ret;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 1871b8a..9b28f39 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -462,14 +462,16 @@
 {
 	struct st_request *SRpnt = req->end_io_data;
 	struct scsi_tape *STp = SRpnt->stp;
+	struct bio *tmp;
 
 	STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
 	STp->buffer->cmdstat.residual = req->resid_len;
 
+	tmp = SRpnt->bio;
 	if (SRpnt->waiting)
 		complete(SRpnt->waiting);
 
-	blk_rq_unmap_user(SRpnt->bio);
+	blk_rq_unmap_user(tmp);
 	__blk_put_request(req->q, req);
 }
 
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index b4543f5..36d1ed7 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -839,6 +839,10 @@
 	struct sym_lcb *lp = sym_lp(tp, sdev->lun);
 	unsigned long flags;
 
+	/* if slave_alloc returned before allocating a sym_lcb, return */
+	if (!lp)
+		return;
+
 	spin_lock_irqsave(np->s.host->host_lock, flags);
 
 	if (lp->busy_itlq || lp->busy_itl) {
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index d053cd6..fa9d1df 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -22,6 +22,8 @@
 #include <linux/kthread.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_slimbus.h>
 #include <mach/sps.h>
 
 /* Per spec.max 40 bytes per received message */
@@ -86,10 +88,80 @@
 #define QC_DEVID_PGD	0x5
 #define QC_MSM_DEVS	5
 
+#define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
+#define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
+#define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r))
+
+#define PGD_THIS_EE_V2(r) (dev->base + (r ## _V2) + (dev->ee * 0x1000))
+#define PGD_PORT_V2(r, p) (dev->base + (r ## _V2) + ((p) * 0x1000))
+#define CFG_PORT_V2(r) ((r ## _V2))
 /* Component registers */
-enum comp_reg {
-	COMP_CFG	= 0,
-	COMP_TRUST_CFG	= 0x14,
+enum comp_reg_v2 {
+	COMP_CFG_V2		= 4,
+	COMP_TRUST_CFG_V2	= 0x3000,
+};
+
+/* Manager PGD registers */
+enum pgd_reg_v2 {
+	PGD_CFG_V2		= 0x800,
+	PGD_STAT_V2		= 0x804,
+	PGD_INT_EN_V2		= 0x810,
+	PGD_INT_STAT_V2		= 0x814,
+	PGD_INT_CLR_V2		= 0x818,
+	PGD_OWN_EEn_V2		= 0x300C,
+	PGD_PORT_INT_EN_EEn_V2	= 0x5000,
+	PGD_PORT_INT_ST_EEn_V2	= 0x5004,
+	PGD_PORT_INT_CL_EEn_V2	= 0x5008,
+	PGD_PORT_CFGn_V2	= 0x14000,
+	PGD_PORT_STATn_V2	= 0x14004,
+	PGD_PORT_PARAMn_V2	= 0x14008,
+	PGD_PORT_BLKn_V2	= 0x1400C,
+	PGD_PORT_TRANn_V2	= 0x14010,
+	PGD_PORT_MCHANn_V2	= 0x14014,
+	PGD_PORT_PSHPLLn_V2	= 0x14018,
+	PGD_PORT_PC_CFGn_V2	= 0x8000,
+	PGD_PORT_PC_VALn_V2	= 0x8004,
+	PGD_PORT_PC_VFR_TSn_V2	= 0x8008,
+	PGD_PORT_PC_VFR_STn_V2	= 0x800C,
+	PGD_PORT_PC_VFR_CLn_V2	= 0x8010,
+	PGD_IE_STAT_V2		= 0x820,
+	PGD_VE_STAT_V2		= 0x830,
+};
+
+#define PGD_THIS_EE_V1(r) (dev->base + (r ## _V1) + (dev->ee * 16))
+#define PGD_PORT_V1(r, p) (dev->base + (r ## _V1) + ((p) * 32))
+#define CFG_PORT_V1(r) ((r ## _V1))
+/* Component registers */
+enum comp_reg_v1 {
+	COMP_CFG_V1		= 0,
+	COMP_TRUST_CFG_V1	= 0x14,
+};
+
+/* Manager PGD registers */
+enum pgd_reg_v1 {
+	PGD_CFG_V1		= 0x1000,
+	PGD_STAT_V1		= 0x1004,
+	PGD_INT_EN_V1		= 0x1010,
+	PGD_INT_STAT_V1		= 0x1014,
+	PGD_INT_CLR_V1		= 0x1018,
+	PGD_OWN_EEn_V1		= 0x1020,
+	PGD_PORT_INT_EN_EEn_V1	= 0x1030,
+	PGD_PORT_INT_ST_EEn_V1	= 0x1034,
+	PGD_PORT_INT_CL_EEn_V1	= 0x1038,
+	PGD_PORT_CFGn_V1	= 0x1080,
+	PGD_PORT_STATn_V1	= 0x1084,
+	PGD_PORT_PARAMn_V1	= 0x1088,
+	PGD_PORT_BLKn_V1	= 0x108C,
+	PGD_PORT_TRANn_V1	= 0x1090,
+	PGD_PORT_MCHANn_V1	= 0x1094,
+	PGD_PORT_PSHPLLn_V1	= 0x1098,
+	PGD_PORT_PC_CFGn_V1	= 0x1600,
+	PGD_PORT_PC_VALn_V1	= 0x1604,
+	PGD_PORT_PC_VFR_TSn_V1	= 0x1608,
+	PGD_PORT_PC_VFR_STn_V1	= 0x160C,
+	PGD_PORT_PC_VFR_CLn_V1	= 0x1610,
+	PGD_IE_STAT_V1		= 0x1700,
+	PGD_VE_STAT_V1		= 0x1710,
 };
 
 /* Manager registers */
@@ -141,33 +213,6 @@
 	INTF_VE_STAT	= 0x640,
 };
 
-/* Manager PGD registers */
-enum pgd_reg {
-	PGD_CFG			= 0x1000,
-	PGD_STAT		= 0x1004,
-	PGD_INT_EN		= 0x1010,
-	PGD_INT_STAT		= 0x1014,
-	PGD_INT_CLR		= 0x1018,
-	PGD_OWN_EEn		= 0x1020,
-	PGD_PORT_INT_EN_EEn	= 0x1030,
-	PGD_PORT_INT_ST_EEn	= 0x1034,
-	PGD_PORT_INT_CL_EEn	= 0x1038,
-	PGD_PORT_CFGn		= 0x1080,
-	PGD_PORT_STATn		= 0x1084,
-	PGD_PORT_PARAMn		= 0x1088,
-	PGD_PORT_BLKn		= 0x108C,
-	PGD_PORT_TRANn		= 0x1090,
-	PGD_PORT_MCHANn		= 0x1094,
-	PGD_PORT_PSHPLLn	= 0x1098,
-	PGD_PORT_PC_CFGn	= 0x1600,
-	PGD_PORT_PC_VALn	= 0x1604,
-	PGD_PORT_PC_VFR_TSn	= 0x1608,
-	PGD_PORT_PC_VFR_STn	= 0x160C,
-	PGD_PORT_PC_VFR_CLn	= 0x1610,
-	PGD_IE_STAT		= 0x1700,
-	PGD_VE_STAT		= 0x1710,
-};
-
 enum rsc_grp {
 	EE_MGR_RSC_GRP	= 1 << 10,
 	EE_NGD_2	= 2 << 6,
@@ -243,6 +288,7 @@
 	bool			chan_active;
 	enum msm_ctrl_state	state;
 	int			nsats;
+	u32			ver;
 };
 
 struct msm_sat_chan {
@@ -507,13 +553,13 @@
 		mb();
 		complete(&dev->reconf);
 	}
-	pstat = readl_relaxed(dev->base + PGD_PORT_INT_ST_EEn + (16 * dev->ee));
+	pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
 	if (pstat != 0) {
 		int i = 0;
 		for (i = dev->pipe_b; i < MSM_SLIM_NPORTS; i++) {
 			if (pstat & 1 << i) {
-				u32 val = readl_relaxed(dev->base +
-						PGD_PORT_STATn + (i * 32));
+				u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn,
+							i, dev->ver));
 				if (val & (1 << 19)) {
 					dev->ctrl.ports[i].err =
 						SLIM_P_DISCONNECT;
@@ -530,8 +576,8 @@
 					dev->ctrl.ports[i].err =
 						SLIM_P_UNDERFLOW;
 			}
-			writel_relaxed(1, dev->base + PGD_PORT_INT_CL_EEn +
-				(dev->ee * 16));
+			writel_relaxed(1, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
+							dev->ver));
 		}
 		/*
 		 * Guarantee that port interrupt bit(s) clearing writes go
@@ -610,13 +656,13 @@
 static void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn)
 {
 	u32 set_cfg = DEF_WATERMARK | DEF_ALIGN | DEF_PACK | ENABLE_PORT;
-	u32 int_port = readl_relaxed(dev->base + PGD_PORT_INT_EN_EEn +
-					(dev->ee * 16));
-	writel_relaxed(set_cfg, dev->base + PGD_PORT_CFGn + (pn * 32));
-	writel_relaxed(DEF_BLKSZ, dev->base + PGD_PORT_BLKn + (pn * 32));
-	writel_relaxed(DEF_TRANSZ, dev->base + PGD_PORT_TRANn + (pn * 32));
-	writel_relaxed((int_port | 1 << pn) , dev->base + PGD_PORT_INT_EN_EEn +
-			(dev->ee * 16));
+	u32 int_port = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+					dev->ver));
+	writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_CFGn, pn, dev->ver));
+	writel_relaxed(DEF_BLKSZ, PGD_PORT(PGD_PORT_BLKn, pn, dev->ver));
+	writel_relaxed(DEF_TRANSZ, PGD_PORT(PGD_PORT_TRANn, pn, dev->ver));
+	writel_relaxed((int_port | 1 << pn) , PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+								dev->ver));
 	/* Make sure that port registers are updated before returning */
 	mb();
 }
@@ -643,8 +689,8 @@
 		}
 	}
 
-	stat = readl_relaxed(dev->base + PGD_PORT_STATn +
-				(32 * (pn + dev->pipe_b)));
+	stat = readl_relaxed(PGD_PORT(PGD_PORT_STATn, (pn + dev->pipe_b),
+					dev->ver));
 	if (dev->ctrl.ports[pn].flow == SLIM_SRC) {
 		cfg->destination = dev->bam.hdl;
 		cfg->source = SPS_DEV_HANDLE_MEM;
@@ -821,7 +867,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 +926,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();
@@ -1171,6 +1217,27 @@
 			}
 			slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
 			sat->satcl.laddr = laddr;
+			/*
+			 * Since capability message is already sent, present
+			 * message will indicate subsystem hosting this
+			 * satellite has restarted.
+			 * Remove all active channels of this satellite
+			 * when this is detected
+			 */
+			if (sat->sent_capability) {
+				for (i = 0; i < sat->nsatch; i++) {
+					enum slim_ch_state chs =
+						slim_get_ch_state(&sat->satcl,
+							sat->satch[i].chanh);
+					pr_err("Slim-SSR, sat:%d, rm chan:%d",
+							laddr,
+							sat->satch[i].chan);
+					if (chs == SLIM_CH_ACTIVE)
+						slim_control_ch(&sat->satcl,
+							sat->satch[i].chanh,
+							SLIM_CH_REMOVE, true);
+				}
+			}
 		} else if (mt != SLIM_MSG_MT_CORE &&
 				mc != SLIM_MSG_MC_REPORT_PRESENT) {
 			satv = msm_slim_get_ctrl(dev);
@@ -1539,6 +1606,10 @@
 	struct sps_register_event sps_error_event; /* SPS_ERROR */
 	struct sps_register_event sps_descr_event; /* DESCR_DONE */
 
+	init_completion(notify);
+	if (!dev->use_rx_msgqs)
+		goto rx_thread_create;
+
 	/* Allocate the endpoint */
 	ret = msm_slim_init_endpoint(dev, endpoint);
 	if (ret) {
@@ -1620,12 +1691,17 @@
 		}
 	}
 
+rx_thread_create:
 	/* Fire up the Rx message queue thread */
 	dev->rx_msgq_thread = kthread_run(msm_slim_rx_msgq_thread, dev,
 					MSM_SLIM_NAME "_rx_msgq_thread");
 	if (!dev->rx_msgq_thread) {
 		dev_err(dev->dev, "Failed to start Rx message queue thread\n");
-		ret = -EIO;
+		/* Tear-down BAMs or return? */
+		if (!dev->use_rx_msgqs)
+			return -EIO;
+		else
+			ret = -EIO;
 	} else
 		return 0;
 
@@ -1641,6 +1717,7 @@
 alloc_descr_failed:
 	msm_slim_free_endpoint(endpoint);
 sps_init_endpoint_failed:
+	dev->use_rx_msgqs = 0;
 	return ret;
 }
 
@@ -1669,6 +1746,9 @@
 		},
 	};
 
+	if (!dev->use_rx_msgqs)
+		goto init_rx_msgq;
+
 	bam_props.ee = dev->ee;
 	bam_props.virt_addr = dev->bam.base;
 	bam_props.phys_addr = bam_mem->start;
@@ -1693,22 +1773,21 @@
 	/* Register the BAM device with the SPS driver */
 	ret = sps_register_bam_device(&bam_props, &bam_handle);
 	if (ret) {
-		dev_err(dev->dev, "sps_register_bam_device failed 0x%x\n", ret);
-		return ret;
+		dev_err(dev->dev, "disabling BAM: reg-bam failed 0x%x\n", ret);
+		dev->use_rx_msgqs = 0;
+		goto init_rx_msgq;
 	}
 	dev->bam.hdl = bam_handle;
 	dev_dbg(dev->dev, "SLIM BAM registered, handle = 0x%x\n", bam_handle);
 
+init_rx_msgq:
 	ret = msm_slim_init_rx_msgq(dev);
-	if (ret) {
+	if (ret)
 		dev_err(dev->dev, "msm_slim_init_rx_msgq failed 0x%x\n", ret);
-		goto rx_msgq_init_failed;
+	if (!dev->use_rx_msgqs && bam_handle) {
+		sps_deregister_bam_device(bam_handle);
+		dev->bam.hdl = 0L;
 	}
-
-	return 0;
-rx_msgq_init_failed:
-	sps_deregister_bam_device(bam_handle);
-	dev->bam.hdl = 0L;
 	return ret;
 }
 
@@ -1726,8 +1805,8 @@
 		sps_disconnect(endpoint->sps);
 		msm_slim_sps_mem_free(dev, descr);
 		msm_slim_free_endpoint(endpoint);
+		sps_deregister_bam_device(dev->bam.hdl);
 	}
-	sps_deregister_bam_device(dev->bam.hdl);
 }
 
 static void msm_slim_prg_slew(struct platform_device *pdev,
@@ -1835,7 +1914,24 @@
 		ret = -ENOMEM;
 		goto err_ioremap_bam_failed;
 	}
-	dev->ctrl.nr = pdev->id;
+	if (pdev->dev.of_node) {
+
+		ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
+					&dev->ctrl.nr);
+		if (ret) {
+			dev_err(&pdev->dev, "Cell index not specified:%d", ret);
+			goto err_of_init_failed;
+		}
+		/* Optional properties */
+		ret = of_property_read_u32(pdev->dev.of_node,
+					"qcom,min-clk-gear", &dev->ctrl.min_cg);
+		ret = of_property_read_u32(pdev->dev.of_node,
+					"qcom,max-clk-gear", &dev->ctrl.max_cg);
+		pr_err("min_cg:%d, max_cg:%d, ret:%d", dev->ctrl.min_cg,
+					dev->ctrl.max_cg, ret);
+	} else {
+		dev->ctrl.nr = pdev->id;
+	}
 	dev->ctrl.nchans = MSM_SLIM_NCHANS;
 	dev->ctrl.nports = MSM_SLIM_NPORTS;
 	dev->ctrl.set_laddr = msm_set_laddr;
@@ -1868,6 +1964,7 @@
 	dev->ctrl.a_framer = &dev->framer;
 	dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
 	dev->ctrl.dev.parent = &pdev->dev;
+	dev->ctrl.dev.of_node = pdev->dev.of_node;
 
 	ret = request_irq(dev->irq, msm_slim_interrupt, IRQF_TRIGGER_HIGH,
 				"msm_slim_irq", dev);
@@ -1892,12 +1989,15 @@
 		goto err_clk_get_failed;
 	}
 	clk_set_rate(dev->rclk, SLIM_ROOT_FREQ);
-	clk_enable(dev->rclk);
+	clk_prepare_enable(dev->rclk);
 
+	dev->ver = readl_relaxed(dev->base);
+	/* Version info in 16 MSbits */
+	dev->ver >>= 16;
 	/* Component register initialization */
-	writel_relaxed(1, dev->base + COMP_CFG);
+	writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
 	writel_relaxed((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1),
-				dev->base + COMP_TRUST_CFG);
+				dev->base + CFG_PORT(COMP_TRUST_CFG, dev->ver));
 
 	/*
 	 * Manager register initialization
@@ -1948,20 +2048,24 @@
 	 * ported generic device inside MSM manager
 	 */
 	mb();
-	writel_relaxed(1, dev->base + PGD_CFG);
-	writel_relaxed(0x3F<<17, dev->base + (PGD_OWN_EEn + (4 * dev->ee)));
+	writel_relaxed(1, dev->base + CFG_PORT(PGD_CFG, dev->ver));
+	writel_relaxed(0x3F<<17, dev->base + CFG_PORT(PGD_OWN_EEn, dev->ver) +
+				(4 * dev->ee));
 	/*
 	 * Make sure that ported generic device is enabled and port-EE settings
 	 * are written through before finally enabling the component
 	 */
 	mb();
 
-	writel_relaxed(1, dev->base + COMP_CFG);
+	writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
 	/*
 	 * Make sure that all writes have gone through before exiting this
 	 * function
 	 */
 	mb();
+	if (pdev->dev.of_node)
+		of_register_slim_devices(&dev->ctrl);
+
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
 	pm_runtime_set_active(&pdev->dev);
@@ -1970,12 +2074,13 @@
 	return 0;
 
 err_ctrl_failed:
-	writel_relaxed(0, dev->base + COMP_CFG);
+	writel_relaxed(0, dev->base + CFG_PORT(COMP_CFG, dev->ver));
 err_clk_get_failed:
 	kfree(dev->satd);
 err_request_irq_failed:
 	msm_slim_sps_exit(dev);
 err_sps_init_failed:
+err_of_init_failed:
 	iounmap(dev->bam.base);
 err_ioremap_bam_failed:
 	iounmap(dev->base);
@@ -2129,6 +2234,13 @@
 	)
 };
 
+static struct of_device_id msm_slim_dt_match[] = {
+	{
+		.compatible = "qcom,slim-msm",
+	},
+	{}
+};
+
 static struct platform_driver msm_slim_driver = {
 	.probe = msm_slim_probe,
 	.remove = msm_slim_remove,
@@ -2136,6 +2248,7 @@
 		.name = MSM_SLIM_NAME,
 		.owner = THIS_MODULE,
 		.pm = &msm_slim_dev_pm_ops,
+		.of_match_table = msm_slim_dt_match,
 	},
 };
 
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 6733396..cc008ab 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2730,15 +2730,19 @@
  * -EXFULL is returned if there is no space in TDM to reserve the bandwidth.
  * -EISCONN/-ENOTCONN is returned if the channel is already connected or not
  * yet defined.
+ * -EINVAL is returned if individual control of a grouped-channel is attempted.
  */
 int slim_control_ch(struct slim_device *sb, u16 chanh,
 			enum slim_ch_control chctrl, bool commit)
 {
 	struct slim_controller *ctrl = sb->ctrl;
-	struct slim_ich *slc;
 	int ret = 0;
 	/* Get rid of the group flag in MSB if any */
 	u8 chan = SLIM_HDL_TO_CHIDX(chanh);
+	struct slim_ich *slc = &ctrl->chans[chan];
+	if (!(slc->nextgrp & SLIM_START_GRP))
+		return -EINVAL;
+
 	mutex_lock(&sb->sldev_reconf);
 	mutex_lock(&ctrl->m_ctrl);
 	do {
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index bda9e17..a434bbb 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -331,7 +331,7 @@
 				    enum msm_spi_state state);
 static void msm_spi_write_word_to_fifo(struct msm_spi *dd);
 static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd);
-static irqreturn_t msm_spi_qup_irq(int irq, void *dev_id);
+static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id);
 
 #if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
 static inline void msm_spi_disable_irqs(struct msm_spi *dd)
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 648d2e9..84fd462 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -19,4 +19,20 @@
 	  This is required for communicating with Qualcomm PMICs and
 	  other devices that have the SPMI interface.
 
+config MSM_QPNP
+	depends on ARCH_MSMCOPPER
+	depends on OF_SPMI
+	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
+	depends on MSM_QPNP
+	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 8406134..d59a610 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -3,3 +3,5 @@
 #
 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/qpnp.c b/drivers/spmi/qpnp.c
new file mode 100644
index 0000000..ddf9000
--- /dev/null
+++ b/drivers/spmi/qpnp.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ * 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.
+ *
+ * Resource handling based on platform.c.
+ */
+
+#include <mach/qpnp.h>
+
+/**
+ * qpnp_get_resource - get a resource for a device
+ * @dev: qpnp device
+ * @type: resource type
+ * @num: resource index
+ */
+struct resource *qpnp_get_resource(struct spmi_device *dev,
+				   unsigned int node_idx, unsigned int type,
+				   unsigned int res_num)
+{
+	int i;
+
+	for (i = 0; i < dev->dev_node[node_idx].num_resources; i++) {
+		struct resource *r = &dev->dev_node[node_idx].resource[i];
+
+		if (type == resource_type(r) && res_num-- == 0)
+			return r;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(qpnp_get_resource);
+
+/**
+ * qpnp_get_irq - get an IRQ for a device
+ * @dev: qpnp device
+ * @num: IRQ number index
+ */
+int qpnp_get_irq(struct spmi_device *dev, unsigned int node_idx,
+					  unsigned int res_num)
+{
+	struct resource *r = qpnp_get_resource(dev, node_idx,
+						IORESOURCE_IRQ, res_num);
+
+	return r ? r->start : -ENXIO;
+}
+EXPORT_SYMBOL_GPL(qpnp_get_irq);
+
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/spmi/spmi.c b/drivers/spmi/spmi.c
index 2842cd8..20a290a 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -233,9 +233,9 @@
 	spmidev->name = info->name;
 	spmidev->sid  = info->slave_id;
 	spmidev->dev.of_node = info->of_node;
-	spmidev->resource = info->resource;
-	spmidev->num_resources = info->num_resources;
 	spmidev->dev.platform_data = (void *)info->platform_data;
+	spmidev->num_dev_node = info->num_dev_node;
+	spmidev->dev_node = info->dev_node;
 
 	rc = spmi_add_device(spmidev);
 	if (rc < 0) {
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index d6620ad..c828151 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -516,10 +516,14 @@
 
 static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 {
-	ssb_pcicore_fix_sprom_core_index(pc);
+	struct ssb_device *pdev = pc->dev;
+	struct ssb_bus *bus = pdev->bus;
+
+	if (bus->bustype == SSB_BUSTYPE_PCI)
+		ssb_pcicore_fix_sprom_core_index(pc);
 
 	/* Disable PCI interrupts. */
-	ssb_write32(pc->dev, SSB_INTVEC, 0);
+	ssb_write32(pdev, SSB_INTVEC, 0);
 
 	/* Additional PCIe always once-executed workarounds */
 	if (pc->dev->id.coreid == SSB_DEV_PCIE) {
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index cb42d89..2b42d46 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -143,7 +143,7 @@
 static struct console ram_console = {
 	.name	= "ram",
 	.write	= ram_console_write,
-	.flags	= CON_PRINTBUFFER | CON_ENABLED,
+	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
 	.index	= -1,
 };
 
@@ -155,7 +155,7 @@
 		ram_console.flags &= ~CON_ENABLED;
 }
 
-static void __init
+static void __devinit
 ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo,
 	char *dest)
 {
@@ -239,7 +239,7 @@
 	}
 }
 
-static int __init ram_console_init(struct ram_console_buffer *buffer,
+static int __devinit ram_console_init(struct ram_console_buffer *buffer,
 				   size_t buffer_size, const char *bootinfo,
 				   char *old_buf)
 {
@@ -336,7 +336,7 @@
 		ram_console_old_log_init_buffer);
 }
 #else
-static int ram_console_driver_probe(struct platform_device *pdev)
+static int __devinit ram_console_driver_probe(struct platform_device *pdev)
 {
 	struct resource *res = pdev->resource;
 	size_t start;
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index 7bb7da7..63bafbb 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -355,7 +355,14 @@
 
 static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count)
 {
-	while (count-- > 0 && val) {
+	odev->last_val = val;
+
+	if (val == 0) {
+		odev->buf_offs += count;
+		return 0;
+	}
+
+	while (count-- > 0) {
 		size_t x = odev->buf_offs % odev->width;
 		size_t y = odev->buf_offs / odev->width;
 		size_t i;
@@ -406,7 +413,6 @@
 			;
 		}
 
-		odev->last_val = val;
 		odev->buf_offs++;
 	}
 
@@ -805,10 +811,9 @@
 
 static void __exit asus_oled_exit(void)
 {
+	usb_deregister(&oled_driver);
 	class_remove_file(oled_class, &class_attr_version.attr);
 	class_destroy(oled_class);
-
-	usb_deregister(&oled_driver);
 }
 
 module_init(asus_oled_init);
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index c20694e..63e50f7 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1432,7 +1432,21 @@
 	return ret;
 }
 
-static void comedi_unmap(struct vm_area_struct *area)
+
+static void comedi_vm_open(struct vm_area_struct *area)
+{
+	struct comedi_async *async;
+	struct comedi_device *dev;
+
+	async = area->vm_private_data;
+	dev = async->subdevice->device;
+
+	mutex_lock(&dev->mutex);
+	async->mmap_count++;
+	mutex_unlock(&dev->mutex);
+}
+
+static void comedi_vm_close(struct vm_area_struct *area)
 {
 	struct comedi_async *async;
 	struct comedi_device *dev;
@@ -1446,15 +1460,13 @@
 }
 
 static struct vm_operations_struct comedi_vm_ops = {
-	.close = comedi_unmap,
+	.open = comedi_vm_open,
+	.close = comedi_vm_close,
 };
 
 static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	const unsigned minor = iminor(file->f_dentry->d_inode);
-	struct comedi_device_file_info *dev_file_info =
-	    comedi_get_device_file_info(minor);
-	struct comedi_device *dev = dev_file_info->device;
 	struct comedi_async *async = NULL;
 	unsigned long start = vma->vm_start;
 	unsigned long size;
@@ -1462,6 +1474,15 @@
 	int i;
 	int retval;
 	struct comedi_subdevice *s;
+	struct comedi_device_file_info *dev_file_info;
+	struct comedi_device *dev;
+
+	dev_file_info = comedi_get_device_file_info(minor);
+	if (dev_file_info == NULL)
+	        return -ENODEV;
+	dev = dev_file_info->device;
+	if (dev == NULL)
+	        return -ENODEV;
 
 	mutex_lock(&dev->mutex);
 	if (!dev->attached) {
@@ -1528,11 +1549,17 @@
 {
 	unsigned int mask = 0;
 	const unsigned minor = iminor(file->f_dentry->d_inode);
-	struct comedi_device_file_info *dev_file_info =
-	    comedi_get_device_file_info(minor);
-	struct comedi_device *dev = dev_file_info->device;
 	struct comedi_subdevice *read_subdev;
 	struct comedi_subdevice *write_subdev;
+	struct comedi_device_file_info *dev_file_info;
+	struct comedi_device *dev;
+	dev_file_info = comedi_get_device_file_info(minor);
+
+	if (dev_file_info == NULL)
+	        return -ENODEV;
+	dev = dev_file_info->device;
+	if (dev == NULL)
+	        return -ENODEV;
 
 	mutex_lock(&dev->mutex);
 	if (!dev->attached) {
@@ -1578,9 +1605,15 @@
 	int n, m, count = 0, retval = 0;
 	DECLARE_WAITQUEUE(wait, current);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
-	struct comedi_device_file_info *dev_file_info =
-	    comedi_get_device_file_info(minor);
-	struct comedi_device *dev = dev_file_info->device;
+	struct comedi_device_file_info *dev_file_info;
+	struct comedi_device *dev;
+	dev_file_info = comedi_get_device_file_info(minor);
+
+	if (dev_file_info == NULL)
+	        return -ENODEV;
+	dev = dev_file_info->device;
+	if (dev == NULL)
+	        return -ENODEV;
 
 	if (!dev->attached) {
 		DPRINTK("no driver configured on comedi%i\n", dev->minor);
@@ -1640,11 +1673,11 @@
 				retval = -EAGAIN;
 				break;
 			}
+			schedule();
 			if (signal_pending(current)) {
 				retval = -ERESTARTSYS;
 				break;
 			}
-			schedule();
 			if (!s->busy)
 				break;
 			if (s->busy != file) {
@@ -1683,9 +1716,15 @@
 	int n, m, count = 0, retval = 0;
 	DECLARE_WAITQUEUE(wait, current);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
-	struct comedi_device_file_info *dev_file_info =
-	    comedi_get_device_file_info(minor);
-	struct comedi_device *dev = dev_file_info->device;
+	struct comedi_device_file_info *dev_file_info;
+	struct comedi_device *dev;
+	dev_file_info = comedi_get_device_file_info(minor);
+
+	if (dev_file_info == NULL)
+	        return -ENODEV;
+	dev = dev_file_info->device;
+	if (dev == NULL)
+	        return -ENODEV;
 
 	if (!dev->attached) {
 		DPRINTK("no driver configured on comedi%i\n", dev->minor);
@@ -1741,11 +1780,11 @@
 				retval = -EAGAIN;
 				break;
 			}
+			schedule();
 			if (signal_pending(current)) {
 				retval = -ERESTARTSYS;
 				break;
 			}
-			schedule();
 			if (!s->busy) {
 				retval = 0;
 				break;
@@ -1885,11 +1924,17 @@
 static int comedi_close(struct inode *inode, struct file *file)
 {
 	const unsigned minor = iminor(inode);
-	struct comedi_device_file_info *dev_file_info =
-	    comedi_get_device_file_info(minor);
-	struct comedi_device *dev = dev_file_info->device;
 	struct comedi_subdevice *s = NULL;
 	int i;
+	struct comedi_device_file_info *dev_file_info;
+	struct comedi_device *dev;
+	dev_file_info = comedi_get_device_file_info(minor);
+
+	if (dev_file_info == NULL)
+	        return -ENODEV;
+	dev = dev_file_info->device;
+	if (dev == NULL)
+	        return -ENODEV;
 
 	mutex_lock(&dev->mutex);
 
@@ -1923,10 +1968,15 @@
 static int comedi_fasync(int fd, struct file *file, int on)
 {
 	const unsigned minor = iminor(file->f_dentry->d_inode);
-	struct comedi_device_file_info *dev_file_info =
-	    comedi_get_device_file_info(minor);
+	struct comedi_device_file_info *dev_file_info;
+	struct comedi_device *dev;
+	dev_file_info = comedi_get_device_file_info(minor);
 
-	struct comedi_device *dev = dev_file_info->device;
+	if (dev_file_info == NULL)
+	        return -ENODEV;
+	dev = dev_file_info->device;
+	if (dev == NULL)
+	        return -ENODEV;
 
 	return fasync_helper(fd, file, on, &dev->async_queue);
 }
diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
index a01f9a0..5af82f4 100644
--- a/drivers/staging/hv/hyperv_storage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -218,6 +218,7 @@
 #define STORVSC_MAX_LUNS_PER_TARGET			64
 #define STORVSC_MAX_TARGETS				1
 #define STORVSC_MAX_CHANNELS				1
+#define STORVSC_MAX_CMD_LEN				16
 
 struct hv_storvsc_request;
 
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index cb4a25b..734076b 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -729,6 +729,8 @@
 	host->max_id = STORVSC_MAX_TARGETS;
 	/* max # of channels */
 	host->max_channel = STORVSC_MAX_CHANNELS - 1;
+	/* max cmd length */
+	host->max_cmd_len = STORVSC_MAX_CMD_LEN;
 
 	/* Register the HBA and start the scsi bus scan */
 	ret = scsi_add_host(host, &device->device);
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
index c900647..4250ff5 100644
--- a/drivers/staging/qcache/fmem.c
+++ b/drivers/staging/qcache/fmem.c
@@ -16,6 +16,10 @@
 #include <linux/fmem.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#ifdef CONFIG_MEMORY_HOTPLUG
+#include <linux/memory.h>
+#include <linux/memory_hotplug.h>
+#endif
 #include "tmem.h"
 #include <asm/mach/map.h>
 
@@ -23,6 +27,11 @@
 enum fmem_state fmem_state;
 static spinlock_t fmem_state_lock;
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+static unsigned int section_powered_off[NR_MEM_SECTIONS];
+static unsigned int fmem_section_start, fmem_section_end;
+#endif
+
 void *fmem_map_virtual_area(int cacheability)
 {
 	unsigned long addr;
@@ -51,6 +60,10 @@
 {
 	struct fmem_platform_data *pdata = pdev->dev.platform_data;
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+	fmem_section_start = pdata->phys >> PA_SECTION_SHIFT;
+	fmem_section_end = (pdata->phys - 1 + pdata->size) >> PA_SECTION_SHIFT;
+#endif
 	fmem_data.phys = pdata->phys + pdata->reserved_size_low;
 	fmem_data.size = pdata->size - pdata->reserved_size_low -
 					pdata->reserved_size_high;
@@ -96,6 +109,10 @@
 		return snprintf(buf, 3, "t\n");
 	else if (fmem_state == FMEM_C_STATE)
 		return snprintf(buf, 3, "c\n");
+#ifdef CONFIG_MEMORY_HOTPLUG
+	else if (fmem_state == FMEM_O_STATE)
+		return snprintf(buf, 3, "o\n");
+#endif
 	else if (fmem_state == FMEM_UNINITIALIZED)
 		return snprintf(buf, 15, "uninitialized\n");
 	return snprintf(buf, 3, "?\n");
@@ -111,6 +128,10 @@
 		ret = fmem_set_state(FMEM_T_STATE);
 	else if (!strncmp(buf, "c", 1))
 		ret = fmem_set_state(FMEM_C_STATE);
+#ifdef CONFIG_MEMORY_HOTPLUG
+	else if (!strncmp(buf, "o", 1))
+		ret = fmem_set_state(FMEM_O_STATE);
+#endif
 	if (ret)
 		return ret;
 	return 1;
@@ -144,8 +165,95 @@
 
 #endif
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+bool fmem_is_disjoint(unsigned long start_pfn, unsigned long nr_pages)
+{
+	unsigned long fmem_start_pfn, fmem_end_pfn;
+	unsigned long unstable_end_pfn;
+	unsigned long highest_start_pfn, lowest_end_pfn;
+
+	fmem_start_pfn = (fmem_data.phys - fmem_data.reserved_size_low)
+		>> PAGE_SHIFT;
+	fmem_end_pfn = (fmem_data.phys + fmem_data.size +
+		fmem_data.reserved_size_high - 1) >> PAGE_SHIFT;
+	unstable_end_pfn = start_pfn + nr_pages - 1;
+
+	highest_start_pfn = max(fmem_start_pfn, start_pfn);
+	lowest_end_pfn = min(fmem_end_pfn, unstable_end_pfn);
+
+	return lowest_end_pfn < highest_start_pfn;
+}
+
+static int fmem_mem_going_offline_callback(void *arg)
+{
+	struct memory_notify *marg = arg;
+
+	if (fmem_is_disjoint(marg->start_pfn, marg->nr_pages))
+		return 0;
+	return fmem_set_state(FMEM_O_STATE);
+}
+
+static void fmem_mem_online_callback(void *arg)
+{
+	struct memory_notify *marg = arg;
+	int i;
+
+	section_powered_off[marg->start_pfn >> PFN_SECTION_SHIFT] = 0;
+
+	if (fmem_state != FMEM_O_STATE)
+		return;
+
+	for (i = fmem_section_start; i <= fmem_section_end; i++) {
+		if (section_powered_off[i])
+			return;
+	}
+
+	fmem_set_state(FMEM_T_STATE);
+}
+
+static void fmem_mem_offline_callback(void *arg)
+{
+	struct memory_notify *marg = arg;
+
+	section_powered_off[marg->start_pfn >> PFN_SECTION_SHIFT] = 1;
+}
+
+static int fmem_memory_callback(struct notifier_block *self,
+				unsigned long action, void *arg)
+{
+	int ret = 0;
+
+	if (fmem_state == FMEM_UNINITIALIZED)
+		return NOTIFY_OK;
+
+	switch (action) {
+	case MEM_ONLINE:
+		fmem_mem_online_callback(arg);
+		break;
+	case MEM_GOING_OFFLINE:
+		ret = fmem_mem_going_offline_callback(arg);
+		break;
+	case MEM_OFFLINE:
+		fmem_mem_offline_callback(arg);
+		break;
+	case MEM_GOING_ONLINE:
+	case MEM_CANCEL_ONLINE:
+	case MEM_CANCEL_OFFLINE:
+		break;
+	}
+	if (ret)
+		ret = notifier_from_errno(ret);
+	else
+		ret = NOTIFY_OK;
+	return ret;
+}
+#endif
+
 static int __init fmem_init(void)
 {
+#ifdef CONFIG_MEMORY_HOTPLUG
+	hotplug_memory_notifier(fmem_memory_callback, 0);
+#endif
 	return platform_driver_register(&fmem_driver);
 }
 
@@ -184,13 +292,25 @@
 			tmem_enable();
 			create_sysfs = 1;
 			goto out_set;
-		}
-		if (new_state == FMEM_C_STATE) {
+		} else {
 			ret = -EINVAL;
 			goto out;
 		}
 	}
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+	if (fmem_state == FMEM_C_STATE && new_state == FMEM_O_STATE) {
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	if (fmem_state == FMEM_O_STATE && new_state == FMEM_C_STATE) {
+		pr_warn("attempting to use powered off memory as fmem\n");
+		ret = -EAGAIN;
+		goto out;
+	}
+#endif
+
 	if (new_state == FMEM_T_STATE) {
 		void *v;
 		v = fmem_map_virtual_area(MT_DEVICE_CACHED);
diff --git a/drivers/staging/qcache/qcache-main.c b/drivers/staging/qcache/qcache-main.c
index f6838d1..ea6635c 100644
--- a/drivers/staging/qcache/qcache-main.c
+++ b/drivers/staging/qcache/qcache-main.c
@@ -160,15 +160,18 @@
 
 	spin_lock_irqsave(&qc->lock, flags);
 	offset = bitmap_find_free_region(qc->bitmap, qc->pages, 0);
-	spin_unlock_irqrestore(&qc->lock, flags);
 
-	if (offset < 0)
+	if (offset < 0) {
+		spin_unlock_irqrestore(&qc->lock, flags);
 		return NULL;
+	}
 
-	addr = qc->addr + offset * PAGE_SIZE;
 	zcache_qc_allocated++;
 	zcache_qc_used++;
 	zcache_qc_max_used = max(zcache_qc_max_used, zcache_qc_used);
+	spin_unlock_irqrestore(&qc->lock, flags);
+
+	addr = qc->addr + offset * PAGE_SIZE;
 
 	return addr;
 }
@@ -183,10 +186,10 @@
 
 	spin_lock_irqsave(&qc->lock, flags);
 	bitmap_release_region(qc->bitmap, offset, 0);
-	spin_unlock_irqrestore(&qc->lock, flags);
 
 	zcache_qc_freed++;
 	zcache_qc_used--;
+	spin_unlock_irqrestore(&qc->lock, flags);
 }
 
 /*
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
index ca098ca..02fafec 100644
--- a/drivers/staging/quatech_usb2/quatech_usb2.c
+++ b/drivers/staging/quatech_usb2/quatech_usb2.c
@@ -916,9 +916,10 @@
 		dbg("%s() port %d, cmd == TIOCMIWAIT enter",
 			__func__, port->number);
 		prev_msr_value = port_extra->shadowMSR  & QT2_SERIAL_MSR_MASK;
+		barrier();
+		__set_current_state(TASK_INTERRUPTIBLE);
 		while (1) {
 			add_wait_queue(&port_extra->wait, &wait);
-			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			dbg("%s(): port %d, cmd == TIOCMIWAIT here\n",
 				__func__, port->number);
@@ -926,9 +927,12 @@
 			/* see if a signal woke us up */
 			if (signal_pending(current))
 				return -ERESTARTSYS;
+			set_current_state(TASK_INTERRUPTIBLE);
 			msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK;
-			if (msr_value == prev_msr_value)
+			if (msr_value == prev_msr_value) {
+				__set_current_state(TASK_RUNNING);
 				return -EIO;  /* no change - error */
+			}
 			if ((arg & TIOCM_RNG &&
 				((prev_msr_value & QT2_SERIAL_MSR_RI) ==
 					(msr_value & QT2_SERIAL_MSR_RI))) ||
@@ -941,6 +945,7 @@
 				(arg & TIOCM_CTS &&
 				((prev_msr_value & QT2_SERIAL_MSR_CTS) ==
 					(msr_value & QT2_SERIAL_MSR_CTS)))) {
+				__set_current_state(TASK_RUNNING);
 				return 0;
 			}
 		} /* end inifinite while */
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 21ce2af..6d88d1a 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -86,6 +86,8 @@
 	{USB_DEVICE(0x0DF6, 0x0045)},
 	{USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */
 	{USB_DEVICE(0x0DF6, 0x004B)},
+	{USB_DEVICE(0x0DF6, 0x005B)},
+	{USB_DEVICE(0x0DF6, 0x005D)},
 	{USB_DEVICE(0x0DF6, 0x0063)},
 	/* Sweex */
 	{USB_DEVICE(0x177F, 0x0154)},
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index 12f5eba..48aa61e 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -24,7 +24,6 @@
 #define DRIVER_DESC "Quatech USB to Serial Driver"
 
 #define	USB_VENDOR_ID_QUATECH			0x061d	/* Quatech VID */
-#define QUATECH_SSU100	0xC020	/* SSU100 */
 #define QUATECH_SSU200	0xC030	/* SSU200 */
 #define QUATECH_DSU100	0xC040	/* DSU100 */
 #define QUATECH_DSU200	0xC050	/* DSU200 */
@@ -127,7 +126,6 @@
 #define RS232_MODE          0x00
 
 static const struct usb_device_id serqt_id_table[] = {
-	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)},
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)},
 	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU200)},
@@ -775,7 +773,6 @@
 	}
 
 	switch (serial->dev->descriptor.idProduct) {
-	case QUATECH_SSU100:
 	case QUATECH_DSU100:
 	case QUATECH_QSU100:
 	case QUATECH_ESU100A:
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index e42ce9d..5c4b5d9 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -68,6 +68,7 @@
 {
 	struct usbip_device *ud = &vdev->ud;
 	struct urb *urb;
+	unsigned long flags;
 
 	spin_lock(&vdev->priv_lock);
 	urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
@@ -101,9 +102,9 @@
 
 	usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
 
-	spin_lock(&the_controller->lock);
+	spin_lock_irqsave(&the_controller->lock, flags);
 	usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-	spin_unlock(&the_controller->lock);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
 
@@ -141,6 +142,7 @@
 {
 	struct vhci_unlink *unlink;
 	struct urb *urb;
+	unsigned long flags;
 
 	usbip_dump_header(pdu);
 
@@ -170,9 +172,9 @@
 		urb->status = pdu->u.ret_unlink.status;
 		pr_info("urb->status %d\n", urb->status);
 
-		spin_lock(&the_controller->lock);
+		spin_lock_irqsave(&the_controller->lock, flags);
 		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-		spin_unlock(&the_controller->lock);
+		spin_unlock_irqrestore(&the_controller->lock, flags);
 
 		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
 				     urb->status);
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/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 70c2e7f..4b5421b 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -127,6 +127,24 @@
 		set_host_byte(sc, DID_NO_CONNECT);
 		return NULL;
 	}
+	/*
+	 * Because some userspace code via scsi-generic do not memset their
+	 * associated read buffers, go ahead and do that here for type
+	 * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
+	 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
+	 * by target core in transport_generic_allocate_tasks() ->
+	 * transport_generic_cmd_sequencer().
+	 */
+	if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
+	    se_cmd->data_direction == DMA_FROM_DEVICE) {
+		struct scatterlist *sg = scsi_sglist(sc);
+		unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
+
+		if (buf != NULL) {
+			memset(buf, 0, sg->length);
+			kunmap(sg_page(sg));
+		}
+	}
 
 	transport_device_setup_cmd(se_cmd);
 	return se_cmd;
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 47abb42..86b3660 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -60,11 +60,31 @@
 	unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
 	u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
 				    Target port group descriptor */
+	/*
+	 * Need at least 4 bytes of response data or else we can't
+	 * even fit the return data length.
+	 */
+	if (cmd->data_length < 4) {
+		pr_warn("REPORT TARGET PORT GROUPS allocation length %u"
+			" too small\n", cmd->data_length);
+		return -EINVAL;
+	}
 
 	spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
 	list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list,
 			tg_pt_gp_list) {
 		/*
+		 * Check if the Target port group and Target port descriptor list
+		 * based on tg_pt_gp_members count will fit into the response payload.
+		 * Otherwise, bump rd_len to let the initiator know we have exceeded
+		 * the allocation length and the response is truncated.
+		 */
+		if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) >
+		     cmd->data_length) {
+			rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4);
+			continue;
+		}
+		/*
 		 * PREF: Preferred target port bit, determine if this
 		 * bit should be set for port group.
 		 */
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index 7f19c8b..f044d45 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -84,6 +84,18 @@
 	buf[2] = dev->transport->get_device_rev(dev);
 
 	/*
+	 * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2
+	 *
+	 * SPC4 says:
+	 *   A RESPONSE DATA FORMAT field set to 2h indicates that the
+	 *   standard INQUIRY data is in the format defined in this
+	 *   standard. Response data format values less than 2h are
+	 *   obsolete. Response data format values greater than 2h are
+	 *   reserved.
+	 */
+	buf[3] = 2;
+
+	/*
 	 * Enable SCCS and TPGS fields for Emulated ALUA
 	 */
 	if (T10_ALUA(dev->se_sub_dev)->alua_type == SPC3_ALUA_EMULATED)
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index b662db3..98e12d3 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -471,6 +471,7 @@
 	case READ_MEDIA_SERIAL_NUMBER:
 	case REPORT_LUNS:
 	case REQUEST_SENSE:
+	case PERSISTENT_RESERVE_IN:
 		ret = 0; /*/ Allowed CDBs */
 		break;
 	default:
@@ -3079,7 +3080,7 @@
 			if (!(calling_it_nexus))
 				core_scsi3_ua_allocate(pr_reg_nacl,
 					pr_res_mapped_lun, 0x2A,
-					ASCQ_2AH_RESERVATIONS_PREEMPTED);
+					ASCQ_2AH_REGISTRATIONS_PREEMPTED);
 		}
 		spin_unlock(&pr_tmpl->registration_lock);
 		/*
@@ -3191,7 +3192,7 @@
 		 *    additional sense code set to REGISTRATIONS PREEMPTED;
 		 */
 		core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A,
-				ASCQ_2AH_RESERVATIONS_PREEMPTED);
+				ASCQ_2AH_REGISTRATIONS_PREEMPTED);
 	}
 	spin_unlock(&pr_tmpl->registration_lock);
 	/*
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 4b9b716..d3a7342 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2777,10 +2777,15 @@
 
 	/*
 	 * Everything else assume TYPE_DISK Sector CDB location.
-	 * Use 8-bit sector value.
+	 * Use 8-bit sector value.  SBC-3 says:
+	 *
+	 *   A TRANSFER LENGTH field set to zero specifies that 256
+	 *   logical blocks shall be written.  Any other value
+	 *   specifies the number of logical blocks that shall be
+	 *   written.
 	 */
 type_disk:
-	return (u32)cdb[4];
+	return cdb[4] ? : 256;
 }
 
 static inline u32 transport_get_sectors_10(
@@ -5663,6 +5668,8 @@
 	case TCM_SECTOR_COUNT_TOO_MANY:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ILLEGAL REQUEST */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* INVALID COMMAND OPERATION CODE */
@@ -5671,6 +5678,7 @@
 	case TCM_UNKNOWN_MODE_PAGE:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ILLEGAL REQUEST */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* INVALID FIELD IN CDB */
@@ -5679,6 +5687,7 @@
 	case TCM_CHECK_CONDITION_ABORT_CMD:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* BUS DEVICE RESET FUNCTION OCCURRED */
@@ -5688,6 +5697,7 @@
 	case TCM_INCORRECT_AMOUNT_OF_DATA:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* WRITE ERROR */
@@ -5698,22 +5708,25 @@
 	case TCM_INVALID_CDB_FIELD:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
-		/* ABORTED COMMAND */
-		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+		/* ILLEGAL REQUEST */
+		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* INVALID FIELD IN CDB */
 		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
 		break;
 	case TCM_INVALID_PARAMETER_LIST:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
-		/* ABORTED COMMAND */
-		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+		/* ILLEGAL REQUEST */
+		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* INVALID FIELD IN PARAMETER LIST */
 		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26;
 		break;
 	case TCM_UNEXPECTED_UNSOLICITED_DATA:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* WRITE ERROR */
@@ -5724,6 +5737,7 @@
 	case TCM_SERVICE_CRC_ERROR:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* PROTOCOL SERVICE CRC ERROR */
@@ -5734,6 +5748,7 @@
 	case TCM_SNACK_REJECTED:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* READ ERROR */
@@ -5744,6 +5759,7 @@
 	case TCM_WRITE_PROTECTED:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* DATA PROTECT */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
 		/* WRITE PROTECTED */
@@ -5752,6 +5768,7 @@
 	case TCM_CHECK_CONDITION_UNIT_ATTENTION:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* UNIT ATTENTION */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
 		core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
@@ -5761,6 +5778,7 @@
 	case TCM_CHECK_CONDITION_NOT_READY:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* Not Ready */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY;
 		transport_get_sense_codes(cmd, &asc, &ascq);
@@ -5771,6 +5789,7 @@
 	default:
 		/* CURRENT ERROR */
 		buffer[offset] = 0x70;
+		buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
 		/* ILLEGAL REQUEST */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* LOGICAL UNIT COMMUNICATION FAILURE */
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 0e279b8..71df297 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -278,7 +278,7 @@
 			}
 			writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
 			if (tmdev->hw_type == MSM_8960 ||
-				tmdev->hw_type == MSM_9615 ||
+				tmdev->hw_type == MDM_9615 ||
 				tmdev->hw_type == APQ_8064)
 				reg |= mask | TSENS_8960_SLP_CLK_ENA
 							| TSENS_EN;
@@ -294,7 +294,7 @@
 						TSENS_8960_SLP_CLK_ENA |
 						TSENS_EN);
 				else if (tmdev->hw_type == MSM_8960 ||
-						tmdev->hw_type == MSM_9615)
+						tmdev->hw_type == MDM_9615)
 					reg &= ~(SENSORS_EN |
 						TSENS_8960_SLP_CLK_ENA |
 						TSENS_EN);
@@ -677,7 +677,7 @@
 	unsigned int reg_cntl = 0;
 
 	reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
-	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
+	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
 			tmdev->hw_type == APQ_8064) {
 		writel_relaxed(reg_cntl &
 				~((((1 << tmdev->tsens_num_sensor) - 1) >> 1)
@@ -691,7 +691,7 @@
 	unsigned int reg_cntl = 0;
 
 	reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
-	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
+	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
 			tmdev->hw_type == APQ_8064)
 		writel_relaxed(reg_cntl &
 				~((((1 << tmdev->tsens_num_sensor) - 1) <<
@@ -712,7 +712,7 @@
 	reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
 	writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
 
-	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615) {
+	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
 		reg_cntl |= TSENS_8960_SLP_CLK_ENA |
 			(TSENS_MEASURE_PERIOD << 18) |
 			TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
@@ -853,7 +853,7 @@
 
 	if (tmdev->hw_type == MSM_8660)
 		rc = tsens_calib_sensors8660();
-	else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
+	else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
 		tmdev->hw_type == APQ_8064)
 		rc = tsens_calib_sensors8960();
 
@@ -920,7 +920,7 @@
 	}
 
 	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
-		char name[17];
+		char name[18];
 		snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
 		tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
 		tmdev->sensor[i].sensor_num = i;
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index ef28844..c6ba24e 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -18,6 +18,7 @@
 #include <linux/mutex.h>
 #include <linux/msm_tsens.h>
 #include <linux/workqueue.h>
+#include <linux/cpu.h>
 
 #define DEF_TEMP_SENSOR      0
 #define DEF_THERMAL_CHECK_MS 1000
@@ -34,13 +35,11 @@
 module_param(allowed_max_freq, int, 0);
 module_param(check_interval_ms, int, 0);
 
-static DEFINE_PER_CPU(struct cpufreq_policy*, policy);
-static struct mutex policy_mutex;
 static struct delayed_work check_temp_work;
 
-static int update_cpu_max_freq(int cpu, int max_freq)
+static int update_cpu_max_freq(struct cpufreq_policy *cpu_policy,
+			       int cpu, int max_freq)
 {
-	struct cpufreq_policy *cpu_policy = per_cpu(policy, cpu);
 	int ret = 0;
 
 	if (!cpu_policy)
@@ -68,7 +67,6 @@
 	int cpu = 0;
 	int ret = 0;
 
-	mutex_lock(&policy_mutex);
 	tsens_dev.sensor_num = DEF_TEMP_SENSOR;
 	ret = tsens_get_temp(&tsens_dev, &temp);
 	if (ret) {
@@ -78,70 +76,57 @@
 	}
 
 	for_each_possible_cpu(cpu) {
-		cpu_policy = per_cpu(policy, cpu);
+		update_policy = 0;
+		cpu_policy = cpufreq_cpu_get(cpu);
 		if (!cpu_policy) {
-			pr_debug("msm_thermal: No CPUFreq policy found for "
-				"cpu %d\n", cpu);
+			pr_debug("msm_thermal: NULL policy on cpu %d\n", cpu);
 			continue;
 		}
 		if (temp >= allowed_max_high) {
 			if (cpu_policy->max > allowed_max_freq) {
 				update_policy = 1;
 				max_freq = allowed_max_freq;
+			} else {
+				pr_debug("msm_thermal: policy max for cpu %d "
+					 "already < allowed_max_freq\n", cpu);
 			}
 		} else if (temp < allowed_max_low) {
 			if (cpu_policy->max < cpu_policy->cpuinfo.max_freq) {
 				max_freq = cpu_policy->cpuinfo.max_freq;
 				update_policy = 1;
+			} else {
+				pr_debug("msm_thermal: policy max for cpu %d "
+					 "already at max allowed\n", cpu);
 			}
 		}
 
 		if (update_policy)
-			update_cpu_max_freq(cpu, max_freq);
+			update_cpu_max_freq(cpu_policy, cpu, max_freq);
+
+		cpufreq_cpu_put(cpu_policy);
 	}
 
 reschedule:
 	if (enabled)
 		schedule_delayed_work(&check_temp_work,
 				msecs_to_jiffies(check_interval_ms));
-
-	mutex_unlock(&policy_mutex);
 }
 
-static int msm_thermal_notifier(struct notifier_block *nb,
-		unsigned long event, void *data)
-{
-	if (event == CPUFREQ_START) {
-		struct cpufreq_policy *cpu_policy = data;
-		mutex_lock(&policy_mutex);
-		per_cpu(policy, cpu_policy->cpu) = cpu_policy;
-		mutex_unlock(&policy_mutex);
-	}
-
-	return 0;
-}
-
-static struct notifier_block msm_thermal_notifier_block = {
-	.notifier_call = msm_thermal_notifier,
-};
-
 static void disable_msm_thermal(void)
 {
 	int cpu = 0;
 	struct cpufreq_policy *cpu_policy = NULL;
 
-	cpufreq_unregister_notifier(&msm_thermal_notifier_block,
-			CPUFREQ_POLICY_NOTIFIER);
-	cancel_delayed_work(&check_temp_work);
-
-	mutex_lock(&policy_mutex);
 	for_each_possible_cpu(cpu) {
-		cpu_policy = per_cpu(policy, cpu);
-		if (cpu_policy &&
-			cpu_policy->max < cpu_policy->cpuinfo.max_freq)
-			update_cpu_max_freq(cpu, cpu_policy->cpuinfo.max_freq);
+		cpu_policy = cpufreq_cpu_get(cpu);
+		if (cpu_policy) {
+			if (cpu_policy->max < cpu_policy->cpuinfo.max_freq)
+				update_cpu_max_freq(cpu_policy, cpu,
+						    cpu_policy->
+						    cpuinfo.max_freq);
+			cpufreq_cpu_put(cpu_policy);
+		}
 	}
-	mutex_unlock(&policy_mutex);
 }
 
 static int set_enabled(const char *val, const struct kernel_param *kp)
@@ -172,12 +157,8 @@
 	int ret = 0;
 
 	enabled = 1;
-	mutex_init(&policy_mutex);
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
 
-	ret = cpufreq_register_notifier(&msm_thermal_notifier_block,
-			CPUFREQ_POLICY_NOTIFIER);
-
 	schedule_delayed_work(&check_temp_work, 0);
 
 	return ret;
diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c
index 7ff1312..81429c2 100644
--- a/drivers/tty/hvc/hvc_dcc.c
+++ b/drivers/tty/hvc/hvc_dcc.c
@@ -41,6 +41,7 @@
 
 	asm volatile("mrc p14, 0, %0, c0, c5, 0	@ read comms data reg"
 		: "=r" (__c));
+	isb();
 
 	return __c;
 }
@@ -50,6 +51,7 @@
 	asm volatile("mcr p14, 0, %0, c0, c5, 0	@ write a char"
 		: /* no output register */
 		: "r" (c));
+	isb();
 }
 
 static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index e809e9d..e18604b 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -670,12 +670,18 @@
 
 	nonseekable_open(inode, filp);
 
+	retval = tty_alloc_file(filp);
+	if (retval)
+		return retval;
+
 	/* find a device that is not in use. */
 	tty_lock();
 	index = devpts_new_index(inode);
 	tty_unlock();
-	if (index < 0)
-		return index;
+	if (index < 0) {
+		retval = index;
+		goto err_file;
+	}
 
 	mutex_lock(&tty_mutex);
 	tty_lock();
@@ -689,27 +695,27 @@
 
 	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 
-	retval = tty_add_file(tty, filp);
-	if (retval)
-		goto out;
+	tty_add_file(tty, filp);
 
 	retval = devpts_pty_new(inode, tty->link);
 	if (retval)
-		goto out1;
+		goto err_release;
 
 	retval = ptm_driver->ops->open(tty, filp);
 	if (retval)
-		goto out2;
-out1:
+		goto err_release;
+
 	tty_unlock();
-	return retval;
-out2:
+	return 0;
+err_release:
 	tty_unlock();
 	tty_release(inode, filp);
 	return retval;
 out:
 	devpts_kill_index(inode, index);
 	tty_unlock();
+err_file:
+	tty_free_file(filp);
 	return retval;
 }
 
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 852cff5..cbb9fb2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1623,7 +1623,7 @@
 	  Support for the IFX6x60 modem devices on Intel MID platforms.
 
 config SERIAL_PCH_UART
-	tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) UART"
+	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
 	depends on PCI
 	select SERIAL_CORE
 	help
@@ -1631,12 +1631,12 @@
 	  which is an IOH(Input/Output Hub) for x86 embedded processor.
 	  Enabling PCH_DMA, this PCH UART works as DMA mode.
 
-	  This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
-	  Output Hub), ML7213 and ML7223.
-	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
-	  for MP(Media Phone) use.
-	  ML7213/ML7223 is companion chip for Intel Atom E6xx series.
-	  ML7213/ML7223 is completely compatible for Intel EG20T PCH.
+	  This driver also can be used for LAPIS Semiconductor IOH(Input/
+	  Output Hub), ML7213, ML7223 and ML7831.
+	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+	  for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+	  ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+	  ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
 
 config SERIAL_MSM_SMD
 	bool "Enable tty device interface for some SMD ports"
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index f5f6831..4a4733e 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1733,9 +1733,19 @@
 {
 	struct uart_amba_port *uap = amba_ports[co->index];
 	unsigned int status, old_cr, new_cr;
+	unsigned long flags;
+	int locked = 1;
 
 	clk_enable(uap->clk);
 
+	local_irq_save(flags);
+	if (uap->port.sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&uap->port.lock);
+	else
+		spin_lock(&uap->port.lock);
+
 	/*
 	 *	First save the CR then disable the interrupts
 	 */
@@ -1755,6 +1765,10 @@
 	} while (status & UART01x_FR_BUSY);
 	writew(old_cr, uap->port.membase + UART011_CR);
 
+	if (locked)
+		spin_unlock(&uap->port.lock);
+	local_irq_restore(flags);
+
 	clk_disable(uap->clk);
 }
 
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index af9b781..b989495 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -199,8 +199,9 @@
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	unsigned int mode;
+	unsigned long flags;
 
-	spin_lock(&port->lock);
+	spin_lock_irqsave(&port->lock, flags);
 
 	/* Disable interrupts */
 	UART_PUT_IDR(port, atmel_port->tx_done_mask);
@@ -231,7 +232,7 @@
 	/* Enable interrupts */
 	UART_PUT_IER(port, atmel_port->tx_done_mask);
 
-	spin_unlock(&port->lock);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 }
 
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 225123b..58be715 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -4450,7 +4450,7 @@
 
 #if defined(CONFIG_ETRAX_RS485)
 #if defined(CONFIG_ETRAX_RS485_ON_PA)
-	if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit,
+	if (cris_io_interface_allocate_pins(if_serial_0, 'a', rs485_pa_bit,
 			rs485_pa_bit)) {
 		printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
 			"RS485 pin\n");
@@ -4459,7 +4459,7 @@
 	}
 #endif
 #if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-	if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit,
+	if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit,
 			rs485_port_g_bit)) {
 		printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
 			"RS485 pin\n");
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
index b704c8c..5b837e7 100644
--- a/drivers/tty/serial/jsm/jsm.h
+++ b/drivers/tty/serial/jsm/jsm.h
@@ -183,10 +183,8 @@
 /* Our Read/Error/Write queue sizes */
 #define RQUEUEMASK	0x1FFF		/* 8 K - 1 */
 #define EQUEUEMASK	0x1FFF		/* 8 K - 1 */
-#define WQUEUEMASK	0x0FFF		/* 4 K - 1 */
 #define RQUEUESIZE	(RQUEUEMASK + 1)
 #define EQUEUESIZE	RQUEUESIZE
-#define WQUEUESIZE	(WQUEUEMASK + 1)
 
 
 /************************************************************************
@@ -226,10 +224,6 @@
 	u16		ch_e_head;	/* Head location of the error queue */
 	u16		ch_e_tail;	/* Tail location of the error queue */
 
-	u8		*ch_wqueue;	/* Our write queue buffer - malloc'ed */
-	u16		ch_w_head;	/* Head location of the write queue */
-	u16		ch_w_tail;	/* Tail location of the write queue */
-
 	u64		ch_rxcount;	/* total of data received so far */
 	u64		ch_txcount;	/* total of data transmitted so far */
 
@@ -378,7 +372,6 @@
  * Prototypes for non-static functions used in more than one module
  *
  *************************************************************************/
-int jsm_tty_write(struct uart_port *port);
 int jsm_tty_init(struct jsm_board *);
 int jsm_uart_port_init(struct jsm_board *);
 int jsm_remove_uart_port(struct jsm_board *);
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 96da178..6c12d94 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -211,7 +211,6 @@
 		if (brd->channels[i]) {
 			kfree(brd->channels[i]->ch_rqueue);
 			kfree(brd->channels[i]->ch_equeue);
-			kfree(brd->channels[i]->ch_wqueue);
 			kfree(brd->channels[i]);
 		}
 	}
@@ -270,6 +269,7 @@
 	struct jsm_board *brd = pci_get_drvdata(pdev);
 
 	pci_restore_state(pdev);
+	pci_save_state(pdev);
 
 	jsm_uart_port_init(brd);
 }
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 4538c3e..bd6e846 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -496,12 +496,15 @@
 	int s;
 	int qlen;
 	u32 len_written = 0;
+	struct circ_buf *circ;
 
 	if (!ch)
 		return;
 
+	circ = &ch->uart_port.state->xmit;
+
 	/* No data to write to the UART */
-	if (ch->ch_w_tail == ch->ch_w_head)
+	if (uart_circ_empty(circ))
 		return;
 
 	/* If port is "stopped", don't send any data to the UART */
@@ -517,11 +520,10 @@
 		if (ch->ch_cached_lsr & UART_LSR_THRE) {
 			ch->ch_cached_lsr &= ~(UART_LSR_THRE);
 
-			writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
+			writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
 			jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
-					"Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
-			ch->ch_w_tail++;
-			ch->ch_w_tail &= WQUEUEMASK;
+					"Tx data: %x\n", circ->buf[circ->head]);
+			circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
 			ch->ch_txcount++;
 		}
 		return;
@@ -536,36 +538,36 @@
 	n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
 
 	/* cache head and tail of queue */
-	head = ch->ch_w_head & WQUEUEMASK;
-	tail = ch->ch_w_tail & WQUEUEMASK;
-	qlen = (head - tail) & WQUEUEMASK;
+	head = circ->head & (UART_XMIT_SIZE - 1);
+	tail = circ->tail & (UART_XMIT_SIZE - 1);
+	qlen = uart_circ_chars_pending(circ);
 
 	/* Find minimum of the FIFO space, versus queue length */
 	n = min(n, qlen);
 
 	while (n > 0) {
 
-		s = ((head >= tail) ? head : WQUEUESIZE) - tail;
+		s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
 		s = min(s, n);
 
 		if (s <= 0)
 			break;
 
-		memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
+		memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s);
 		/* Add and flip queue if needed */
-		tail = (tail + s) & WQUEUEMASK;
+		tail = (tail + s) & (UART_XMIT_SIZE - 1);
 		n -= s;
 		ch->ch_txcount += s;
 		len_written += s;
 	}
 
 	/* Update the final tail */
-	ch->ch_w_tail = tail & WQUEUEMASK;
+	circ->tail = tail & (UART_XMIT_SIZE - 1);
 
 	if (len_written >= ch->ch_t_tlevel)
 		ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
 
-	if (!jsm_tty_write(&ch->uart_port))
+	if (uart_circ_empty(circ))
 		uart_write_wakeup(&ch->uart_port);
 }
 
@@ -946,7 +948,6 @@
 	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
 		ch->ch_r_head = ch->ch_r_tail = 0;
 		ch->ch_e_head = ch->ch_e_tail = 0;
-		ch->ch_w_head = ch->ch_w_tail = 0;
 
 		neo_flush_uart_write(ch);
 		neo_flush_uart_read(ch);
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 7a4a914..434bd88 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -118,6 +118,19 @@
 	udelay(10);
 }
 
+/*
+ * jsm_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static void jsm_tty_write(struct uart_port *port)
+{
+	struct jsm_channel *channel;
+	channel = container_of(port, struct jsm_channel, uart_port);
+	channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
+}
+
 static void jsm_tty_start_tx(struct uart_port *port)
 {
 	struct jsm_channel *channel = (struct jsm_channel *)port;
@@ -216,14 +229,6 @@
 			return -ENOMEM;
 		}
 	}
-	if (!channel->ch_wqueue) {
-		channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
-		if (!channel->ch_wqueue) {
-			jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-				"unable to allocate write queue buf");
-			return -ENOMEM;
-		}
-	}
 
 	channel->ch_flags &= ~(CH_OPENING);
 	/*
@@ -237,7 +242,6 @@
 	 */
 	channel->ch_r_head = channel->ch_r_tail = 0;
 	channel->ch_e_head = channel->ch_e_tail = 0;
-	channel->ch_w_head = channel->ch_w_tail = 0;
 
 	brd->bd_ops->flush_uart_write(channel);
 	brd->bd_ops->flush_uart_read(channel);
@@ -836,75 +840,3 @@
 		}
 	}
 }
-
-/*
- * jsm_tty_write()
- *
- * Take data from the user or kernel and send it out to the FEP.
- * In here exists all the Transparent Print magic as well.
- */
-int jsm_tty_write(struct uart_port *port)
-{
-	int bufcount;
-	int data_count = 0,data_count1 =0;
-	u16 head;
-	u16 tail;
-	u16 tmask;
-	u32 remain;
-	int temp_tail = port->state->xmit.tail;
-	struct jsm_channel *channel = (struct jsm_channel *)port;
-
-	tmask = WQUEUEMASK;
-	head = (channel->ch_w_head) & tmask;
-	tail = (channel->ch_w_tail) & tmask;
-
-	if ((bufcount = tail - head - 1) < 0)
-		bufcount += WQUEUESIZE;
-
-	bufcount = min(bufcount, 56);
-	remain = WQUEUESIZE - head;
-
-	data_count = 0;
-	if (bufcount >= remain) {
-		bufcount -= remain;
-		while ((port->state->xmit.head != temp_tail) &&
-		(data_count < remain)) {
-			channel->ch_wqueue[head++] =
-			port->state->xmit.buf[temp_tail];
-
-			temp_tail++;
-			temp_tail &= (UART_XMIT_SIZE - 1);
-			data_count++;
-		}
-		if (data_count == remain) head = 0;
-	}
-
-	data_count1 = 0;
-	if (bufcount > 0) {
-		remain = bufcount;
-		while ((port->state->xmit.head != temp_tail) &&
-			(data_count1 < remain)) {
-			channel->ch_wqueue[head++] =
-				port->state->xmit.buf[temp_tail];
-
-			temp_tail++;
-			temp_tail &= (UART_XMIT_SIZE - 1);
-			data_count1++;
-
-		}
-	}
-
-	port->state->xmit.tail = temp_tail;
-
-	data_count += data_count1;
-	if (data_count) {
-		head &= tmask;
-		channel->ch_w_head = head;
-	}
-
-	if (data_count) {
-		channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
-	}
-
-	return data_count;
-}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 3aa4553..80f50de 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -161,6 +161,8 @@
 
 	struct msm_hs_wakeup wakeup;
 	struct wake_lock dma_wake_lock;  /* held while any DMA active */
+
+	struct dentry *loopback_dir;
 };
 
 #define MSM_UARTDM_BURST_SIZE 16   /* DM burst size (in bytes) */
@@ -367,13 +369,15 @@
 {
 	char node_name[15];
 	snprintf(node_name, sizeof(node_name), "loopback.%d", id);
-	if (IS_ERR_OR_NULL(debugfs_create_file(node_name,
-					       S_IRUGO | S_IWUSR,
-					       debug_base,
-					       msm_uport,
-					       &loopback_enable_fops))) {
-		debugfs_remove_recursive(debug_base);
-	}
+	msm_uport->loopback_dir = debugfs_create_file(node_name,
+						S_IRUGO | S_IWUSR,
+						debug_base,
+						msm_uport,
+						&loopback_enable_fops);
+
+	if (IS_ERR_OR_NULL(msm_uport->loopback_dir))
+		pr_err("%s(): Cannot create loopback.%d debug entry",
+							__func__, id);
 }
 
 static int __devexit msm_hs_remove(struct platform_device *pdev)
@@ -397,7 +401,7 @@
 			dev_err(dev, "GPIO config error\n");
 
 	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_clock.attr);
-	debugfs_remove_recursive(debug_base);
+	debugfs_remove(msm_uport->loopback_dir);
 
 	dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box),
 			 DMA_TO_DEVICE);
@@ -1796,7 +1800,7 @@
 	return ret;
 }
 
-static int __init msm_hs_probe(struct platform_device *pdev)
+static int __devinit msm_hs_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct uart_port *uport;
@@ -1930,8 +1934,7 @@
 	if (IS_ERR_OR_NULL(debug_base))
 		pr_info("msm_serial_hs: Cannot create debugfs dir\n");
 
-	ret = platform_driver_probe(&msm_serial_hs_platform_driver,
-					msm_hs_probe);
+	ret = platform_driver_register(&msm_serial_hs_platform_driver);
 	if (ret) {
 		printk(KERN_ERR "%s failed to load\n", __FUNCTION__);
 		debugfs_remove_recursive(debug_base);
@@ -2001,6 +2004,7 @@
 static void __exit msm_serial_hs_exit(void)
 {
 	printk(KERN_INFO "msm_serial_hs module removed\n");
+	debugfs_remove_recursive(debug_base);
 	platform_driver_unregister(&msm_serial_hs_platform_driver);
 	uart_unregister_driver(&msm_hs_driver);
 }
@@ -2039,7 +2043,8 @@
 };
 
 static struct platform_driver msm_serial_hs_platform_driver = {
-	.remove = msm_hs_remove,
+	.probe	= msm_hs_probe,
+	.remove = __devexit_p(msm_hs_remove),
 	.driver = {
 		.name = "msm_serial_hs",
 		.pm   = &msm_hs_dev_pm_ops,
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index fa7d518..780a3c2 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -51,7 +51,9 @@
 	UARTDM_NCF_TX,
 	UARTDM_DMEN,
 	UARTDM_BCR,
-	UARTDM_LAST
+	UARTDM_TXFS,
+	UARTDM_RXFS,
+	UARTDM_LAST,
 };
 
 #define UARTDM_MR1_ADDR 0x0
@@ -118,6 +120,7 @@
 #define UARTDM_ISR_ADDR 0x14
 #define UARTDM_RX_TOTAL_SNAP_ADDR 0x38
 
+#define UARTDM_TXFS_ADDR 0x4C
 #define UARTDM_RXFS_ADDR 0x50
 
 /* Register field Mask Mapping */
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index f49769d..285d1de 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -61,6 +61,7 @@
 	int			is_uartdm;
 	unsigned int            old_snap_state;
 	unsigned int		ver_id;
+	int			tx_timeout;
 };
 
 #define UARTDM_VERSION_11_13	0
@@ -89,6 +90,8 @@
 		[UARTDM_DMRX] = UARTDM_DMRX_ADDR,
 		[UARTDM_NCF_TX] = UARTDM_NCF_TX_ADDR,
 		[UARTDM_DMEN] = UARTDM_DMEN_ADDR,
+		[UARTDM_TXFS] = UARTDM_TXFS_ADDR,
+		[UARTDM_RXFS] = UARTDM_RXFS_ADDR,
 	},
 	[UARTDM_VERSION_14] = {
 		[UARTDM_MR1] = 0x0,
@@ -108,6 +111,8 @@
 		[UARTDM_DMRX] = 0x34,
 		[UARTDM_NCF_TX] = 0x40,
 		[UARTDM_DMEN] = 0x3c,
+		[UARTDM_TXFS] = 0x4c,
+		[UARTDM_RXFS] = 0x50,
 	},
 };
 
@@ -119,6 +124,7 @@
 };
 static struct dentry *debug_base;
 static inline void wait_for_xmitr(struct uart_port *port, int bits);
+static int get_console_state(struct uart_port *port);
 static inline void msm_hsl_write(struct uart_port *port,
 				 unsigned int val, unsigned int off)
 {
@@ -135,6 +141,16 @@
 	return UART_TO_MSM(port)->is_uartdm;
 }
 
+static int get_line(struct platform_device *pdev)
+{
+	const struct msm_serial_hslite_platform_data *pdata =
+					pdev->dev.platform_data;
+	if (pdata)
+		return pdata->line;
+
+	return pdev->id;
+}
+
 static int clk_en(struct uart_port *port, int enable)
 {
 	struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
@@ -611,6 +627,9 @@
 		break;
 	}
 
+	/* Set timeout to be ~100x the character transmit time */
+	msm_hsl_port->tx_timeout = 1000000000 / baud;
+
 	vid = msm_hsl_port->ver_id;
 	msm_hsl_write(port, baud_code, regmap[vid][UARTDM_CSR]);
 
@@ -639,7 +658,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;
@@ -1041,12 +1060,51 @@
 	return &msm_hsl_uart_ports[line].uart;
 }
 
+static unsigned int msm_hsl_console_state[8];
+
+static void dump_hsl_regs(struct uart_port *port)
+{
+	struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
+	unsigned int vid = msm_hsl_port->ver_id;
+	unsigned int sr, isr, mr1, mr2, ncf, txfs, rxfs, con_state;
+
+	sr = msm_hsl_read(port, regmap[vid][UARTDM_SR]);
+	isr = msm_hsl_read(port, regmap[vid][UARTDM_ISR]);
+	mr1 = msm_hsl_read(port, regmap[vid][UARTDM_MR1]);
+	mr2 = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
+	ncf = msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
+	txfs = msm_hsl_read(port, regmap[vid][UARTDM_TXFS]);
+	rxfs = msm_hsl_read(port, regmap[vid][UARTDM_RXFS]);
+	con_state = get_console_state(port);
+
+	msm_hsl_console_state[0] = sr;
+	msm_hsl_console_state[1] = isr;
+	msm_hsl_console_state[2] = mr1;
+	msm_hsl_console_state[3] = mr2;
+	msm_hsl_console_state[4] = ncf;
+	msm_hsl_console_state[5] = txfs;
+	msm_hsl_console_state[6] = rxfs;
+	msm_hsl_console_state[7] = con_state;
+
+	pr_info("%s(): Timeout: %d uS\n", __func__, msm_hsl_port->tx_timeout);
+	pr_info("%s(): SR:  %08x\n", __func__, sr);
+	pr_info("%s(): ISR: %08x\n", __func__, isr);
+	pr_info("%s(): MR1: %08x\n", __func__, mr1);
+	pr_info("%s(): MR2: %08x\n", __func__, mr2);
+	pr_info("%s(): NCF: %08x\n", __func__, ncf);
+	pr_info("%s(): TXFS: %08x\n", __func__, txfs);
+	pr_info("%s(): RXFS: %08x\n", __func__, rxfs);
+	pr_info("%s(): Console state: %d\n", __func__, con_state);
+}
+
 /*
  *  Wait for transmitter & holding register to empty
  *  Derived from wait_for_xmitr in 8250 serial driver by Russell King  */
 void wait_for_xmitr(struct uart_port *port, int bits)
 {
-	unsigned int vid = UART_TO_MSM(port)->ver_id;
+	struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
+	unsigned int vid = msm_hsl_port->ver_id;
+	int count = 0;
 
 	if (!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
 			UARTDM_SR_TXEMT_BMSK)) {
@@ -1055,6 +1113,10 @@
 			udelay(1);
 			touch_nmi_watchdog();
 			cpu_relax();
+			if (++count == msm_hsl_port->tx_timeout) {
+				dump_hsl_regs(port);
+				panic("MSM HSL wait_for_xmitr is stuck!");
+			}
 		}
 		msm_hsl_write(port, CLEAR_TX_READY, regmap[vid][UARTDM_CR]);
 	}
@@ -1067,13 +1129,12 @@
 
 	wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK);
 	msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
-
-	while (!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
-				UARTDM_SR_TXRDY_BMSK)) {
-		udelay(1);
-		touch_nmi_watchdog();
-	}
-
+	/*
+	 * Dummy read to add 1 AHB clock delay to fix UART hardware bug.
+	 * Bug: Delay required on TX-transfer-init. after writing to
+	 * NO_CHARS_FOR_TX register.
+	 */
+	msm_hsl_read(port, regmap[vid][UARTDM_SR]);
 	msm_hsl_write(port, ch, regmap[vid][UARTDM_TF]);
 }
 
@@ -1192,7 +1253,7 @@
 	struct uart_port *port;
 
 	struct platform_device *pdev = to_platform_device(dev);
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 
 	enable = get_console_state(port);
 
@@ -1213,7 +1274,7 @@
 	struct uart_port *port;
 
 	struct platform_device *pdev = to_platform_device(dev);
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 
 	cur_state = get_console_state(port);
 	enable = buf[0] - '0';
@@ -1281,12 +1342,12 @@
 	if (pdev->id == -1)
 		pdev->id = atomic_inc_return(&msm_serial_hsl_next_id) - 1;
 
-	if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
+	if (unlikely(get_line(pdev) < 0 || get_line(pdev) >= UART_NR))
 		return -ENXIO;
 
 	printk(KERN_INFO "msm_serial_hsl: detected port #%d\n", pdev->id);
 
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 	port->dev = &pdev->dev;
 	msm_hsl_port = UART_TO_MSM(port);
 
@@ -1344,7 +1405,7 @@
 	if (unlikely(ret))
 		pr_err("%s():Can't create console attribute\n", __func__);
 #endif
-	msm_hsl_debugfs_init(msm_hsl_port, pdev->id);
+	msm_hsl_debugfs_init(msm_hsl_port, get_line(pdev));
 
 	/* Temporarily increase the refcount on the GSBI clock to avoid a race
 	 * condition with the earlyprintk handover mechanism.
@@ -1362,7 +1423,7 @@
 	struct msm_hsl_port *msm_hsl_port = platform_get_drvdata(pdev);
 	struct uart_port *port;
 
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 #ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
 	device_remove_file(&pdev->dev, &dev_attr_console);
 #endif
@@ -1385,7 +1446,7 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct uart_port *port;
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 
 	if (port) {
 
@@ -1404,7 +1465,7 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct uart_port *port;
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 
 	if (port) {
 
@@ -1427,7 +1488,7 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct uart_port *port;
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 
 	dev_dbg(dev, "pm_runtime: suspending\n");
 	msm_hsl_deinit_clock(port);
@@ -1438,7 +1499,7 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct uart_port *port;
-	port = get_port_from_line(pdev->id);
+	port = get_port_from_line(get_line(pdev));
 
 	dev_dbg(dev, "pm_runtime: resuming\n");
 	msm_hsl_init_clock(port);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 4652109..902588b 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -256,6 +256,8 @@
 	pch_ml7213_uart2,
 	pch_ml7223_uart0,
 	pch_ml7223_uart1,
+	pch_ml7831_uart0,
+	pch_ml7831_uart1,
 };
 
 static struct pch_uart_driver_data drv_dat[] = {
@@ -268,6 +270,8 @@
 	[pch_ml7213_uart2] = {PCH_UART_2LINE, 2},
 	[pch_ml7223_uart0] = {PCH_UART_8LINE, 0},
 	[pch_ml7223_uart1] = {PCH_UART_2LINE, 1},
+	[pch_ml7831_uart0] = {PCH_UART_8LINE, 0},
+	[pch_ml7831_uart1] = {PCH_UART_2LINE, 1},
 };
 
 static unsigned int default_baud = 9600;
@@ -625,6 +629,7 @@
 		dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n",
 			__func__);
 		dma_release_channel(priv->chan_tx);
+		priv->chan_tx = NULL;
 		return;
 	}
 
@@ -1212,8 +1217,7 @@
 		dev_err(priv->port.dev,
 			"pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
 
-	if (priv->use_dma_flag)
-		pch_free_dma(port);
+	pch_free_dma(port);
 
 	free_irq(priv->port.irq, priv);
 }
@@ -1277,6 +1281,7 @@
 	if (rtn)
 		goto out;
 
+	pch_uart_set_mctrl(&priv->port, priv->port.mctrl);
 	/* Don't rewrite B0 */
 	if (tty_termios_baud_rate(termios))
 		tty_termios_encode_baud_rate(termios, baud, baud);
@@ -1545,6 +1550,10 @@
 	 .driver_data = pch_ml7223_uart0},
 	{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D),
 	 .driver_data = pch_ml7223_uart1},
+	{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8811),
+	 .driver_data = pch_ml7831_uart0},
+	{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8812),
+	 .driver_data = pch_ml7831_uart1},
 	{0,},
 };
 
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 4302e6e..81243a6 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -100,6 +100,16 @@
 	int max_count = 256;
 
 	do {
+		/* work around Errata #20 according to
+		 * Intel(R) PXA27x Processor Family
+		 * Specification Update (May 2005)
+		 *
+		 * Step 2
+		 * Disable the Reciever Time Out Interrupt via IER[RTOEI]
+		 */
+		up->ier &= ~UART_IER_RTOIE;
+		serial_out(up, UART_IER, up->ier);
+
 		ch = serial_in(up, UART_RX);
 		flag = TTY_NORMAL;
 		up->port.icount.rx++;
@@ -156,6 +166,16 @@
 		*status = serial_in(up, UART_LSR);
 	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
 	tty_flip_buffer_push(tty);
+
+	/* work around Errata #20 according to
+	 * Intel(R) PXA27x Processor Family
+	 * Specification Update (May 2005)
+	 *
+	 * Step 6:
+	 * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
+	 */
+	up->ier |= UART_IER_RTOIE;
+	serial_out(up, UART_IER, up->ier);
 }
 
 static void transmit_chars(struct uart_pxa_port *up)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 7dc8b53..d09ca85 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -193,8 +193,7 @@
 	return ((struct tty_file_private *)file->private_data)->tty;
 }
 
-/* Associate a new file with the tty structure */
-int tty_add_file(struct tty_struct *tty, struct file *file)
+int tty_alloc_file(struct file *file)
 {
 	struct tty_file_private *priv;
 
@@ -202,15 +201,36 @@
 	if (!priv)
 		return -ENOMEM;
 
+	file->private_data = priv;
+
+	return 0;
+}
+
+/* Associate a new file with the tty structure */
+void tty_add_file(struct tty_struct *tty, struct file *file)
+{
+	struct tty_file_private *priv = file->private_data;
+
 	priv->tty = tty;
 	priv->file = file;
-	file->private_data = priv;
 
 	spin_lock(&tty_files_lock);
 	list_add(&priv->list, &tty->tty_files);
 	spin_unlock(&tty_files_lock);
+}
 
-	return 0;
+/**
+ * tty_free_file - free file->private_data
+ *
+ * This shall be used only for fail path handling when tty_add_file was not
+ * called yet.
+ */
+void tty_free_file(struct file *file)
+{
+	struct tty_file_private *priv = file->private_data;
+
+	file->private_data = NULL;
+	kfree(priv);
 }
 
 /* Delete file from its tty */
@@ -221,8 +241,7 @@
 	spin_lock(&tty_files_lock);
 	list_del(&priv->list);
 	spin_unlock(&tty_files_lock);
-	file->private_data = NULL;
-	kfree(priv);
+	tty_free_file(file);
 }
 
 
@@ -1811,6 +1830,10 @@
 	nonseekable_open(inode, filp);
 
 retry_open:
+	retval = tty_alloc_file(filp);
+	if (retval)
+		return -ENOMEM;
+
 	noctty = filp->f_flags & O_NOCTTY;
 	index  = -1;
 	retval = 0;
@@ -1823,6 +1846,7 @@
 		if (!tty) {
 			tty_unlock();
 			mutex_unlock(&tty_mutex);
+			tty_free_file(filp);
 			return -ENXIO;
 		}
 		driver = tty_driver_kref_get(tty->driver);
@@ -1855,6 +1879,7 @@
 		}
 		tty_unlock();
 		mutex_unlock(&tty_mutex);
+		tty_free_file(filp);
 		return -ENODEV;
 	}
 
@@ -1862,6 +1887,7 @@
 	if (!driver) {
 		tty_unlock();
 		mutex_unlock(&tty_mutex);
+		tty_free_file(filp);
 		return -ENODEV;
 	}
 got_driver:
@@ -1872,6 +1898,8 @@
 		if (IS_ERR(tty)) {
 			tty_unlock();
 			mutex_unlock(&tty_mutex);
+			tty_driver_kref_put(driver);
+			tty_free_file(filp);
 			return PTR_ERR(tty);
 		}
 	}
@@ -1887,15 +1915,11 @@
 	tty_driver_kref_put(driver);
 	if (IS_ERR(tty)) {
 		tty_unlock();
+		tty_free_file(filp);
 		return PTR_ERR(tty);
 	}
 
-	retval = tty_add_file(tty, filp);
-	if (retval) {
-		tty_unlock();
-		tty_release(inode, filp);
-		return retval;
-	}
+	tty_add_file(tty, filp);
 
 	check_tty_count(tty, "tty_open");
 	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index ef925d5..a76c808 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -36,6 +36,7 @@
 
 #include <linux/kmod.h>
 #include <linux/nsproxy.h>
+#include <linux/ratelimit.h>
 
 /*
  *	This guards the refcounted line discipline lists. The lock
@@ -548,15 +549,16 @@
 /**
  *	tty_ldisc_wait_idle	-	wait for the ldisc to become idle
  *	@tty: tty to wait for
+ *	@timeout: for how long to wait at most
  *
  *	Wait for the line discipline to become idle. The discipline must
  *	have been halted for this to guarantee it remains idle.
  */
-static int tty_ldisc_wait_idle(struct tty_struct *tty)
+static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
 {
-	int ret;
+	long ret;
 	ret = wait_event_timeout(tty_ldisc_idle,
-			atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
+			atomic_read(&tty->ldisc->users) == 1, timeout);
 	if (ret < 0)
 		return ret;
 	return ret > 0 ? 0 : -EBUSY;
@@ -666,7 +668,7 @@
 
 	tty_ldisc_flush_works(tty);
 
-	retval = tty_ldisc_wait_idle(tty);
+	retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 
 	tty_lock();
 	mutex_lock(&tty->ldisc_mutex);
@@ -763,8 +765,6 @@
 	if (IS_ERR(ld))
 		return -1;
 
-	WARN_ON_ONCE(tty_ldisc_wait_idle(tty));
-
 	tty_ldisc_close(tty, tty->ldisc);
 	tty_ldisc_put(tty->ldisc);
 	tty->ldisc = NULL;
@@ -839,7 +839,7 @@
 	tty_unlock();
 	cancel_work_sync(&tty->buf.work);
 	mutex_unlock(&tty->ldisc_mutex);
-
+retry:
 	tty_lock();
 	mutex_lock(&tty->ldisc_mutex);
 
@@ -848,6 +848,22 @@
 	   it means auditing a lot of other paths so this is
 	   a FIXME */
 	if (tty->ldisc) {	/* Not yet closed */
+		if (atomic_read(&tty->ldisc->users) != 1) {
+			char cur_n[TASK_COMM_LEN], tty_n[64];
+			long timeout = 3 * HZ;
+			tty_unlock();
+
+			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
+				timeout = MAX_SCHEDULE_TIMEOUT;
+				printk_ratelimited(KERN_WARNING
+					"%s: waiting (%s) for %s took too long, but we keep waiting...\n",
+					__func__, get_task_comm(cur_n, current),
+					tty_name(tty, tty_n));
+			}
+			mutex_unlock(&tty->ldisc_mutex);
+			goto retry;
+		}
+
 		if (reset == 0) {
 
 			if (!tty_ldisc_reinit(tty, tty->termios->c_line))
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 33d37d2..a4aaca0 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -227,7 +227,6 @@
 	int do_clocal = 0, retval;
 	unsigned long flags;
 	DEFINE_WAIT(wait);
-	int cd;
 
 	/* block if port is in the process of being closed */
 	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
@@ -284,11 +283,14 @@
 				retval = -ERESTARTSYS;
 			break;
 		}
-		/* Probe the carrier. For devices with no carrier detect this
-		   will always return true */
-		cd = tty_port_carrier_raised(port);
+		/*
+		 * Probe the carrier. For devices with no carrier detect
+		 * tty_port_carrier_raised will always return true.
+		 * Never ask drivers if CLOCAL is set, this causes troubles
+		 * on some hardware.
+		 */
 		if (!(port->flags & ASYNC_CLOSING) &&
-				(do_clocal || cd))
+				(do_clocal || tty_port_carrier_raised(port)))
 			break;
 		if (signal_pending(current)) {
 			retval = -ERESTARTSYS;
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 5e096f4..65447c5 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -1463,7 +1463,6 @@
 	if (!perm && op->op != KD_FONT_OP_GET)
 		return -EPERM;
 	op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
-	op->flags |= KD_FONT_FLAG_OLD;
 	i = con_font_op(vc, op);
 	if (i)
 		return i;
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 48f1781..cdfd09a 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"
@@ -118,8 +120,6 @@
 
 source "drivers/usb/musb/Kconfig"
 
-source "drivers/usb/renesas_usbhs/Kconfig"
-
 source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
diff --git a/drivers/usb/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/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index dac7676..158f631 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -539,7 +539,6 @@
 {
 	int i;
 
-	mutex_lock(&open_mutex);
 	if (acm->dev) {
 		usb_autopm_get_interface(acm->control);
 		acm_set_control(acm, acm->ctrlout = 0);
@@ -551,14 +550,23 @@
 		acm->control->needs_remote_wakeup = 0;
 		usb_autopm_put_interface(acm->control);
 	}
-	mutex_unlock(&open_mutex);
 }
 
 static void acm_tty_hangup(struct tty_struct *tty)
 {
-	struct acm *acm = tty->driver_data;
+	struct acm *acm;
+
+	mutex_lock(&open_mutex);
+	acm = tty->driver_data;
+
+	if (!acm)
+		goto out;
+
 	tty_port_hangup(&acm->port);
 	acm_port_down(acm);
+
+out:
+	mutex_unlock(&open_mutex);
 }
 
 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
@@ -569,8 +577,9 @@
 	   shutdown */
 	if (!acm)
 		return;
+
+	mutex_lock(&open_mutex);
 	if (tty_port_close_start(&acm->port, tty, filp) == 0) {
-		mutex_lock(&open_mutex);
 		if (!acm->dev) {
 			tty_port_tty_set(&acm->port, NULL);
 			acm_tty_unregister(acm);
@@ -582,6 +591,7 @@
 	acm_port_down(acm);
 	tty_port_close_end(&acm->port, tty);
 	tty_port_tty_set(&acm->port, NULL);
+	mutex_unlock(&open_mutex);
 }
 
 static int acm_tty_write(struct tty_struct *tty,
@@ -1181,6 +1191,8 @@
 		i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
 		if (i < 0) {
 			kfree(acm->country_codes);
+			acm->country_codes = NULL;
+			acm->country_code_size = 0;
 			goto skip_countries;
 		}
 
@@ -1189,6 +1201,8 @@
 		if (i < 0) {
 			device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
 			kfree(acm->country_codes);
+			acm->country_codes = NULL;
+			acm->country_code_size = 0;
 			goto skip_countries;
 		}
 	}
@@ -1456,6 +1470,16 @@
 	},
 	{ USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
 	},
+	/* Motorola H24 HSPA module: */
+	{ USB_DEVICE(0x22b8, 0x2d91) }, /* modem                                */
+	{ USB_DEVICE(0x22b8, 0x2d92) }, /* modem           + diagnostics        */
+	{ USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port                      */
+	{ USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics        */
+	{ USB_DEVICE(0x22b8, 0x2d96) }, /* modem                         + NMEA */
+	{ USB_DEVICE(0x22b8, 0x2d97) }, /* modem           + diagnostics + NMEA */
+	{ USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port               + NMEA */
+	{ USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */
+
 	{ USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
 	.driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
 					   data interface instead of
@@ -1534,6 +1558,9 @@
 	{ NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
 	{ SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
 
+	/* Support for Owen devices */
+	{ USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
+
 	/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
 
 	/* Support Lego NXT using pbLua firmware */
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 2b9ff51..90581a8 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -57,6 +57,8 @@
 
 #define WDM_MAX			16
 
+/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
+#define WDM_DEFAULT_BUFSIZE	256
 
 static DEFINE_MUTEX(wdm_mutex);
 
@@ -88,7 +90,8 @@
 	int			count;
 	dma_addr_t		shandle;
 	dma_addr_t		ihandle;
-	struct mutex		lock;
+	struct mutex		wlock;
+	struct mutex		rlock;
 	wait_queue_head_t	wait;
 	struct work_struct	rxwork;
 	int			werr;
@@ -323,7 +326,7 @@
 	}
 
 	/* concurrent writes and disconnect */
-	r = mutex_lock_interruptible(&desc->lock);
+	r = mutex_lock_interruptible(&desc->wlock);
 	rv = -ERESTARTSYS;
 	if (r) {
 		kfree(buf);
@@ -386,7 +389,7 @@
 out:
 	usb_autopm_put_interface(desc->intf);
 outnp:
-	mutex_unlock(&desc->lock);
+	mutex_unlock(&desc->wlock);
 outnl:
 	return rv < 0 ? rv : count;
 }
@@ -399,7 +402,7 @@
 	struct wdm_device *desc = file->private_data;
 
 
-	rv = mutex_lock_interruptible(&desc->lock); /*concurrent reads */
+	rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */
 	if (rv < 0)
 		return -ERESTARTSYS;
 
@@ -467,14 +470,16 @@
 	for (i = 0; i < desc->length - cntr; i++)
 		desc->ubuf[i] = desc->ubuf[i + cntr];
 
+	spin_lock_irq(&desc->iuspin);
 	desc->length -= cntr;
+	spin_unlock_irq(&desc->iuspin);
 	/* in case we had outstanding data */
 	if (!desc->length)
 		clear_bit(WDM_READ, &desc->flags);
 	rv = cntr;
 
 err:
-	mutex_unlock(&desc->lock);
+	mutex_unlock(&desc->rlock);
 	return rv;
 }
 
@@ -540,7 +545,8 @@
 	}
 	intf->needs_remote_wakeup = 1;
 
-	mutex_lock(&desc->lock);
+	/* using write lock to protect desc->count */
+	mutex_lock(&desc->wlock);
 	if (!desc->count++) {
 		desc->werr = 0;
 		desc->rerr = 0;
@@ -553,7 +559,7 @@
 	} else {
 		rv = 0;
 	}
-	mutex_unlock(&desc->lock);
+	mutex_unlock(&desc->wlock);
 	usb_autopm_put_interface(desc->intf);
 out:
 	mutex_unlock(&wdm_mutex);
@@ -565,9 +571,11 @@
 	struct wdm_device *desc = file->private_data;
 
 	mutex_lock(&wdm_mutex);
-	mutex_lock(&desc->lock);
+
+	/* using write lock to protect desc->count */
+	mutex_lock(&desc->wlock);
 	desc->count--;
-	mutex_unlock(&desc->lock);
+	mutex_unlock(&desc->wlock);
 
 	if (!desc->count) {
 		dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
@@ -630,7 +638,7 @@
 	struct usb_cdc_dmm_desc *dmhd;
 	u8 *buffer = intf->altsetting->extra;
 	int buflen = intf->altsetting->extralen;
-	u16 maxcom = 0;
+	u16 maxcom = WDM_DEFAULT_BUFSIZE;
 
 	if (!buffer)
 		goto out;
@@ -665,7 +673,8 @@
 	desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
 	if (!desc)
 		goto out;
-	mutex_init(&desc->lock);
+	mutex_init(&desc->rlock);
+	mutex_init(&desc->wlock);
 	spin_lock_init(&desc->iuspin);
 	init_waitqueue_head(&desc->wait);
 	desc->wMaxCommand = maxcom;
@@ -716,7 +725,7 @@
 		goto err;
 
 	desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
-					 desc->bMaxPacketSize0,
+					 desc->wMaxCommand,
 					 GFP_KERNEL,
 					 &desc->response->transfer_dma);
 	if (!desc->inbuf)
@@ -779,11 +788,13 @@
 	/* to terminate pending flushes */
 	clear_bit(WDM_IN_USE, &desc->flags);
 	spin_unlock_irqrestore(&desc->iuspin, flags);
-	mutex_lock(&desc->lock);
+	wake_up_all(&desc->wait);
+	mutex_lock(&desc->rlock);
+	mutex_lock(&desc->wlock);
 	kill_urbs(desc);
 	cancel_work_sync(&desc->rxwork);
-	mutex_unlock(&desc->lock);
-	wake_up_all(&desc->wait);
+	mutex_unlock(&desc->wlock);
+	mutex_unlock(&desc->rlock);
 	if (!desc->count)
 		cleanup(desc);
 	mutex_unlock(&wdm_mutex);
@@ -798,8 +809,10 @@
 	dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
 
 	/* if this is an autosuspend the caller does the locking */
-	if (!(message.event & PM_EVENT_AUTO))
-		mutex_lock(&desc->lock);
+	if (!(message.event & PM_EVENT_AUTO)) {
+		mutex_lock(&desc->rlock);
+		mutex_lock(&desc->wlock);
+	}
 	spin_lock_irq(&desc->iuspin);
 
 	if ((message.event & PM_EVENT_AUTO) &&
@@ -815,8 +828,10 @@
 		kill_urbs(desc);
 		cancel_work_sync(&desc->rxwork);
 	}
-	if (!(message.event & PM_EVENT_AUTO))
-		mutex_unlock(&desc->lock);
+	if (!(message.event & PM_EVENT_AUTO)) {
+		mutex_unlock(&desc->wlock);
+		mutex_unlock(&desc->rlock);
+	}
 
 	return rv;
 }
@@ -854,7 +869,8 @@
 {
 	struct wdm_device *desc = usb_get_intfdata(intf);
 
-	mutex_lock(&desc->lock);
+	mutex_lock(&desc->rlock);
+	mutex_lock(&desc->wlock);
 	kill_urbs(desc);
 
 	/*
@@ -876,7 +892,8 @@
 	int rv;
 
 	rv = recover_from_urb_loss(desc);
-	mutex_unlock(&desc->lock);
+	mutex_unlock(&desc->wlock);
+	mutex_unlock(&desc->rlock);
 	return 0;
 }
 
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 37518df..0ca54e2 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -407,7 +407,7 @@
 		sinfo.si_errno = as->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
-		pid = as->pid;
+		pid = get_pid(as->pid);
 		uid = as->uid;
 		euid = as->euid;
 		secid = as->secid;
@@ -422,9 +422,11 @@
 		cancel_bulk_urbs(ps, as->bulk_addr);
 	spin_unlock(&ps->lock);
 
-	if (signr)
+	if (signr) {
 		kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid,
 				      euid, secid);
+		put_pid(pid);
+	}
 
 	wake_up(&ps->wait);
 }
@@ -607,9 +609,10 @@
 }
 
 static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
-			   unsigned int index)
+			   unsigned int request, unsigned int index)
 {
 	int ret = 0;
+	struct usb_host_interface *alt_setting;
 
 	if (ps->dev->state != USB_STATE_UNAUTHENTICATED
 	 && ps->dev->state != USB_STATE_ADDRESS
@@ -618,6 +621,19 @@
 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
 		return 0;
 
+	/*
+	 * check for the special corner case 'get_device_id' in the printer
+	 * class specification, where wIndex is (interface << 8 | altsetting)
+	 * instead of just interface
+	 */
+	if (requesttype == 0xa1 && request == 0) {
+		alt_setting = usb_find_alt_setting(ps->dev->actconfig,
+						   index >> 8, index & 0xff);
+		if (alt_setting
+		 && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
+			index >>= 8;
+	}
+
 	index &= 0xff;
 	switch (requesttype & USB_RECIP_MASK) {
 	case USB_RECIP_ENDPOINT:
@@ -770,7 +786,8 @@
 
 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
 		return -EFAULT;
-	ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
+	ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest,
+			      ctrl.wIndex);
 	if (ret)
 		return ret;
 	wLength = ctrl.wLength;		/* To suppress 64k PAGE_SIZE warning */
@@ -1100,7 +1117,7 @@
 			kfree(dr);
 			return -EINVAL;
 		}
-		ret = check_ctrlrecip(ps, dr->bRequestType,
+		ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
 				      le16_to_cpup(&dr->wIndex));
 		if (ret) {
 			kfree(dr);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 97c5690..289f732 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);
 }
@@ -1621,7 +1634,7 @@
 	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
 			__func__, atomic_read(&intf->dev.power.usage_count),
 			status);
-	if (status > 0)
+	if (status > 0 || status == -EINPROGRESS)
 		status = 0;
 	return status;
 }
@@ -1706,6 +1719,11 @@
 		return -EAGAIN;
 
 	status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
+
+	/* Allow a retry if autosuspend failed temporarily */
+	if (status == -EAGAIN || status == -EBUSY)
+		usb_mark_last_busy(udev);
+
 	/* The PM core reacts badly unless the return code is 0,
 	 * -EAGAIN, or -EBUSY, so always return -EBUSY on an error.
 	 */
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 54338fc..1d26d45 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1395,11 +1395,10 @@
 					ret = -EAGAIN;
 				else
 					urb->transfer_flags |= URB_DMA_MAP_SG;
-				if (n != urb->num_sgs) {
-					urb->num_sgs = n;
+				urb->num_mapped_sgs = n;
+				if (n != urb->num_sgs)
 					urb->transfer_flags |=
 							URB_DMA_SG_COMBINED;
-				}
 			} else if (urb->sg) {
 				struct scatterlist *sg = urb->sg;
 				urb->transfer_dma = dma_map_page(
@@ -1772,6 +1771,8 @@
 		struct usb_interface *iface = usb_ifnum_to_if(udev,
 				cur_alt->desc.bInterfaceNumber);
 
+		if (!iface)
+			return -EINVAL;
 		if (iface->resetting_device) {
 			/*
 			 * The USB core just reset the device, so the xHCI host
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5442297..5cf1c3e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -846,6 +846,12 @@
 					USB_PORT_FEAT_C_PORT_LINK_STATE);
 		}
 
+		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
+				hub_is_superspeed(hub->hdev)) {
+			need_debounce_delay = true;
+			clear_port_feature(hub->hdev, port1,
+					USB_PORT_FEAT_C_BH_PORT_RESET);
+		}
 		/* We can forget about a "removed" device when there's a
 		 * physical disconnect or the connect status changes.
 		 */
@@ -1690,7 +1696,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 +1784,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 +1818,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 +1829,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 +1850,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 +1878,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..200dc9b 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -38,6 +38,54 @@
 	/* Creative SB Audigy 2 NX */
 	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Logitech Webcam C200 */
+	{ USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C250 */
+	{ USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C300 */
+	{ USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam B/C500 */
+	{ USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C600 */
+	{ USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam Pro 9000 */
+	{ USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C905 */
+	{ USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C210 */
+	{ USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C260 */
+	{ USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C310 */
+	{ USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C910 */
+	{ USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C160 */
+	{ USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C270 */
+	{ USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Quickcam Pro 9000 */
+	{ USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Quickcam E3500 */
+	{ USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Quickcam Vision Pro */
+	{ USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* Logitech Harmony 700-series */
 	{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
 
@@ -69,6 +117,12 @@
 	{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
 			USB_QUIRK_CONFIG_INTF_STRINGS },
 
+	/* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
+	{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Guillemot Webcam Hercules Dualpix Exchange*/
+	{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -96,6 +150,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..5607ac4
--- /dev/null
+++ b/drivers/usb/dwc3/Makefile
@@ -0,0 +1,33 @@
+ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
+ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC3)			+= dwc3.o
+
+dwc3-y					:= core.o
+dwc3-y					+= gadget.o ep0.o
+
+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_OMAP)	+= 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..9206096
--- /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_DWC3) || defined(CONFIG_USB_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..f8327c8 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -82,7 +82,7 @@
 config USB_GADGET_VBUS_DRAW
 	int "Maximum VBUS Power usage (2-500 mA)"
 	range 2 500
-	default 2
+	default 500
 	help
 	   Some devices need to draw power from USB when they are
 	   configured, perhaps to operate circuitry or to recharge
@@ -96,9 +96,6 @@
 	   This value will be used except for system-specific gadget
 	   drivers that have more specific information.
 
-config	USB_GADGET_SELECTED
-	boolean
-
 #
 # USB Peripheral Controller Support
 #
@@ -122,10 +119,9 @@
 # Integrated controllers
 #
 
-config USB_GADGET_AT91
-	boolean "Atmel AT91 USB Device Port"
+config USB_AT91
+	tristate "Atmel AT91 USB Device Port"
 	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
-	select USB_GADGET_SELECTED
 	help
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
 	   full speed USB Device Port with support for five configurable
@@ -135,27 +131,16 @@
 	   dynamically linked module called "at91_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_AT91
-	tristate
-	depends on USB_GADGET_AT91
-	default USB_GADGET
-
-config USB_GADGET_ATMEL_USBA
-	boolean "Atmel USBA"
+config USB_ATMEL_USBA
+	tristate "Atmel USBA"
 	select USB_GADGET_DUALSPEED
 	depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
 	help
 	  USBA is the integrated high-speed USB Device controller on
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
 
-config USB_ATMEL_USBA
-	tristate
-	depends on USB_GADGET_ATMEL_USBA
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_FSL_USB2
-	boolean "Freescale Highspeed USB DR Peripheral Controller"
+config USB_FSL_USB2
+	tristate "Freescale Highspeed USB DR Peripheral Controller"
 	depends on FSL_SOC || ARCH_MXC
 	select USB_GADGET_DUALSPEED
 	select USB_FSL_MPH_DR_OF if OF
@@ -170,26 +155,14 @@
 	   dynamically linked module called "fsl_usb2_udc" and force
 	   all gadget drivers to also be dynamically linked.
 
-config USB_FSL_USB2
-	tristate
-	depends on USB_GADGET_FSL_USB2
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_FUSB300
-	boolean "Faraday FUSB300 USB Peripheral Controller"
+config USB_FUSB300
+	tristate "Faraday FUSB300 USB Peripheral Controller"
 	select USB_GADGET_DUALSPEED
 	help
 	   Faraday usb device controller FUSB300 driver
 
-config USB_FUSB300
-	tristate
-	depends on USB_GADGET_FUSB300
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_OMAP
-	boolean "OMAP USB Device Controller"
+config USB_OMAP
+	tristate "OMAP USB Device Controller"
 	depends on ARCH_OMAP
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
 	select USB_OTG_UTILS if ARCH_OMAP
@@ -204,14 +177,8 @@
 	   dynamically linked module called "omap_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_OMAP
-	tristate
-	depends on USB_GADGET_OMAP
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_PXA25X
-	boolean "PXA 25x or IXP 4xx"
+config USB_PXA25X
+	tristate "PXA 25x or IXP 4xx"
 	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
 	select USB_OTG_UTILS
 	help
@@ -226,24 +193,18 @@
 	   dynamically linked module called "pxa25x_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_PXA25X
-	tristate
-	depends on USB_GADGET_PXA25X
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 # if there's only one gadget driver, using only two bulk endpoints,
 # don't waste memory for the other endpoints
 config USB_PXA25X_SMALL
-	depends on USB_GADGET_PXA25X
+	depends on USB_PXA25X
 	bool
 	default n if USB_ETH_RNDIS
 	default y if USB_ZERO
 	default y if USB_ETH
 	default y if USB_G_SERIAL
 
-config USB_GADGET_R8A66597
-	boolean "Renesas R8A66597 USB Peripheral Controller"
+config USB_R8A66597
+	tristate "Renesas R8A66597 USB Peripheral Controller"
 	select USB_GADGET_DUALSPEED
 	help
 	   R8A66597 is a discrete USB host and peripheral controller chip that
@@ -254,32 +215,20 @@
 	   dynamically linked module called "r8a66597_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_R8A66597
-	tristate
-	depends on USB_GADGET_R8A66597
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_RENESAS_USBHS
-	boolean "Renesas USBHS"
-	depends on USB_RENESAS_USBHS
-	select USB_GADGET_DUALSPEED
+config USB_RENESAS_USBHS
+	tristate 'Renesas USBHS controller'
+	depends on SUPERH || ARCH_SHMOBILE
 	help
-	   Renesas USBHS is a discrete USB host and peripheral controller
-	   chip that supports both full and high speed USB 2.0 data transfers.
-	   platform is able to configure endpoint (pipe) style
+	   Renesas USBHS is a discrete USB host and peripheral controller chip
+	   that supports both full and high speed USB 2.0 data transfers.
+	   It has nine or more configurable endpoints, and endpoint zero.
 
-	   Say "y" to enable the gadget specific portion of the USBHS driver.
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "renesas_usbhs" and force all
+	   gadget drivers to also be dynamically linked.
 
-
-config USB_RENESAS_USBHS_UDC
-	tristate
-	depends on USB_GADGET_RENESAS_USBHS
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_PXA27X
-	boolean "PXA 27x"
+config USB_PXA27X
+	tristate "PXA 27x"
 	depends on ARCH_PXA && (PXA27x || PXA3xx)
 	select USB_OTG_UTILS
 	help
@@ -293,14 +242,8 @@
 	   dynamically linked module called "pxa27x_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_PXA27X
-	tristate
-	depends on USB_GADGET_PXA27X
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_S3C_HSOTG
-	boolean "S3C HS/OtG USB Device controller"
+config USB_S3C_HSOTG
+	tristate "S3C HS/OtG USB Device controller"
 	depends on S3C_DEV_USB_HSOTG
 	select USB_GADGET_S3C_HSOTG_PIO
 	select USB_GADGET_DUALSPEED
@@ -308,14 +251,8 @@
 	  The Samsung S3C64XX USB2.0 high-speed gadget controller
 	  integrated into the S3C64XX series SoC.
 
-config USB_S3C_HSOTG
-	tristate
-	depends on USB_GADGET_S3C_HSOTG
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_IMX
-	boolean "Freescale IMX USB Peripheral Controller"
+config USB_IMX
+	tristate "Freescale IMX USB Peripheral Controller"
 	depends on ARCH_MX1
 	help
 	   Freescale's IMX series include an integrated full speed
@@ -329,14 +266,8 @@
 	   dynamically linked module called "imx_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_IMX
-	tristate
-	depends on USB_GADGET_IMX
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_S3C2410
-	boolean "S3C2410 USB Device Controller"
+config USB_S3C2410
+	tristate "S3C2410 USB Device Controller"
 	depends on ARCH_S3C2410
 	help
 	  Samsung's S3C2410 is an ARM-4 processor with an integrated
@@ -346,18 +277,12 @@
 	  This driver has been tested on the S3C2410, S3C2412, and
 	  S3C2440 processors.
 
-config USB_S3C2410
-	tristate
-	depends on USB_GADGET_S3C2410
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 config USB_S3C2410_DEBUG
 	boolean "S3C2410 udc debug messages"
-	depends on USB_GADGET_S3C2410
+	depends on USB_S3C2410
 
-config USB_GADGET_S3C_HSUDC
-	boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller"
+config USB_S3C_HSUDC
+	tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
 	depends on ARCH_S3C2410
 	select USB_GADGET_DUALSPEED
 	help
@@ -367,41 +292,29 @@
 
 	  This driver has been tested on S3C2416 and S3C2450 processors.
 
-config USB_S3C_HSUDC
-	tristate
-	depends on USB_GADGET_S3C_HSUDC
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_PXA_U2O
-	boolean "PXA9xx Processor USB2.0 controller"
+config USB_PXA_U2O
+	tristate "PXA9xx Processor USB2.0 controller"
+	depends on ARCH_MMP
 	select USB_GADGET_DUALSPEED
 	help
 	  PXA9xx Processor series include a high speed USB2.0 device
 	  controller, which support high speed and full speed USB peripheral.
 
-config USB_PXA_U2O
-	tristate
-	depends on USB_GADGET_PXA_U2O
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 #
 # Controllers available in both integrated and discrete versions
 #
 
 # musb builds in ../musb along with host support
 config USB_GADGET_MUSB_HDRC
-	boolean "Inventra HDRC USB Peripheral (TI, ADI, ...)"
+	tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
 	depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
 	select USB_GADGET_DUALSPEED
-	select USB_GADGET_SELECTED
 	help
 	  This OTG-capable silicon IP is used in dual designs including
 	  the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
 
-config USB_GADGET_M66592
-	boolean "Renesas M66592 USB Peripheral Controller"
+config USB_M66592
+	tristate "Renesas M66592 USB Peripheral Controller"
 	select USB_GADGET_DUALSPEED
 	help
 	   M66592 is a discrete USB peripheral controller chip that
@@ -412,18 +325,12 @@
 	   dynamically linked module called "m66592_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_M66592
-	tristate
-	depends on USB_GADGET_M66592
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 #
 # Controllers available only in discrete form (and all PCI controllers)
 #
 
-config USB_GADGET_AMD5536UDC
-	boolean "AMD5536 UDC"
+config USB_AMD5536UDC
+	tristate "AMD5536 UDC"
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	help
@@ -437,14 +344,8 @@
 	   dynamically linked module called "amd5536udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_AMD5536UDC
-	tristate
-	depends on USB_GADGET_AMD5536UDC
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_FSL_QE
-	boolean "Freescale QE/CPM USB Device Controller"
+config USB_FSL_QE
+	tristate "Freescale QE/CPM USB Device Controller"
 	depends on FSL_SOC && (QUICC_ENGINE || CPM)
 	help
 	   Some of Freescale PowerPC processors have a Full Speed
@@ -456,14 +357,8 @@
 	   Set CONFIG_USB_GADGET to "m" to build this driver as a
 	   dynamically linked module called "fsl_qe_udc".
 
-config USB_FSL_QE
-	tristate
-	depends on USB_GADGET_FSL_QE
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_CI13XXX_PCI
-	boolean "MIPS USB CI13xxx PCI UDC"
+config USB_CI13XXX_PCI
+	tristate "MIPS USB CI13xxx PCI UDC"
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	help
@@ -474,14 +369,8 @@
 	  dynamically linked module called "ci13xxx_udc" and force all
 	  gadget drivers to also be dynamically linked.
 
-config USB_CI13XXX_PCI
-	tristate
-	depends on USB_GADGET_CI13XXX_PCI
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_NET2280
-	boolean "NetChip 228x"
+config USB_NET2280
+	tristate "NetChip 228x"
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	help
@@ -496,14 +385,8 @@
 	   dynamically linked module called "net2280" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_NET2280
-	tristate
-	depends on USB_GADGET_NET2280
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_GOKU
-	boolean "Toshiba TC86C001 'Goku-S'"
+config USB_GOKU
+	tristate "Toshiba TC86C001 'Goku-S'"
 	depends on PCI
 	help
 	   The Toshiba TC86C001 is a PCI device which includes controllers
@@ -516,14 +399,8 @@
 	   dynamically linked module called "goku_udc" and to force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_GOKU
-	tristate
-	depends on USB_GADGET_GOKU
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_LANGWELL
-	boolean "Intel Langwell USB Device Controller"
+config USB_LANGWELL
+	tristate "Intel Langwell USB Device Controller"
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	help
@@ -537,14 +414,8 @@
 	   dynamically linked module called "langwell_udc" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_LANGWELL
-	tristate
-	depends on USB_GADGET_LANGWELL
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_EG20T
-	boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
+config USB_EG20T
+	tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	help
@@ -565,14 +436,8 @@
 	  ML7213 is companion chip for Intel Atom E6xx series.
 	  ML7213 is completely compatible for Intel EG20T PCH.
 
-config USB_EG20T
-	tristate
-	depends on USB_GADGET_EG20T
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_CI13XXX_MSM
-	boolean "MIPS USB CI13xxx for MSM"
+config USB_CI13XXX_MSM
+	tristate "MIPS USB CI13xxx for MSM"
 	depends on ARCH_MSM
 	select USB_GADGET_DUALSPEED
 	select USB_MSM_OTG
@@ -588,14 +453,8 @@
 	  dynamically linked module called "ci13xxx_msm" and force all
 	  gadget drivers to also be dynamically linked.
 
-config USB_CI13XXX_MSM
-	tristate
-	depends on USB_GADGET_CI13XXX_MSM
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_CI13XXX_MSM_HSIC
-	boolean "MIPS HSIC CI13xxx for MSM"
+config USB_CI13XXX_MSM_HSIC
+	tristate "MIPS HSIC CI13xxx for MSM"
 	depends on ARCH_MSM
 	select USB_GADGET_DUALSPEED
 	help
@@ -606,20 +465,39 @@
 	  dynamically linked module called "ci13xxx_msm_hsic" and force all
 	  gadget drivers to also be dynamically linked.
 
-config USB_CI13XXX_MSM_HSIC
-	tristate
-	depends on USB_GADGET_CI13XXX_MSM_HSIC
-	default USB_GADGET
+config USB_DWC3_MSM
+	tristate "DesignWare USB3.0 (DRD) Controller for MSM"
+	depends on ARCH_MSM
+	select USB_DWC3
+	select USB_GADGET_DUALSPEED
 	select USB_GADGET_SELECTED
+	help
+	  The DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+	  integrated into the Qualcomm MSM chipset series, supporting host,
+	  device and otg modes of operation. For more information please
+	  refer to http://www.qualcomm.com/chipsets.
+
+config USB_DWC3_OMAP
+	tristate "DesignWare USB3.0 (DRD) Controller for OMAP"
+	depends on ARCH_OMAP
+	select USB_DWC3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
+	select USB_GADGET_SELECTED
+	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.
 
 #
 # LAST -- dummy/emulated controller
 #
 
-config USB_GADGET_MSM_72K
-	boolean "MSM 72K Device Controller"
+config USB_MSM_72K
+	tristate "MSM 72K Device Controller"
 	depends on ARCH_MSM
-	select USB_GADGET_SELECTED
 	select USB_GADGET_DUALSPEED
 	help
 	   USB gadget driver for Qualcomm MSM 72K architecture.
@@ -628,27 +506,22 @@
 	   dynamically linked module called "msm72k" and force all
 	   gadget drivers to also be dynamically linked.
 
-config USB_MSM_72K
-	tristate
-	depends on USB_GADGET_MSM_72K
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_DUMMY_HCD
-	boolean "Dummy HCD (DEVELOPMENT)"
+config USB_DUMMY_HCD
+	tristate "Dummy HCD (DEVELOPMENT)"
 	depends on USB=y || (USB=m && USB_GADGET=m)
 	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
 	help
 	  This host controller driver emulates USB, looping all data transfer
 	  requests back to a USB "gadget driver" in the same host.  The host
 	  side is the master; the gadget side is the slave.  Gadget drivers
 	  can be high, full, or low speed; and they have access to endpoints
 	  like those from NET2280, PXA2xx, or SA1100 hardware.
-	  
+
 	  This may help in some stages of creating a driver to embed in a
 	  Linux device, since it lets you debug several parts of the gadget
 	  driver without its hardware or drivers being involved.
-	  
+
 	  Since such a gadget side driver needs to interoperate with a host
 	  side Linux-USB device driver, this may help to debug both sides
 	  of a USB protocol stack.
@@ -657,12 +530,6 @@
 	  dynamically linked module called "dummy_hcd" and force all
 	  gadget drivers to also be dynamically linked.
 
-config USB_DUMMY_HCD
-	tristate
-	depends on USB_GADGET_DUMMY_HCD
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # first and will be selected by default.
 
@@ -673,12 +540,24 @@
 	bool
 	depends on USB_GADGET
 
+# Selected by UDC drivers that support super-speed opperation
+config USB_GADGET_SUPERSPEED
+	bool "Operate as superspeed"
+	depends on USB_GADGET
+	depends on USB_GADGET_DUALSPEED
+	default n
+	help
+	 When a superspeed peripheral controller is selected
+	 (for example DesignWare USB3.0 controller), use this flag to
+	 indicate if the device should operate in superspeed(=y)
+	 or not.
+
 #
 # USB Gadget Drivers
 #
 choice
 	tristate "USB Gadget Drivers"
-	depends on USB_GADGET && USB_GADGET_SELECTED
+	depends on USB_GADGET
 	default USB_ETH
 	help
 	  A Linux "Gadget Driver" talks to the USB Peripheral Controller
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..3fb9c83 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -70,6 +70,8 @@
 #include "f_rndis.c"
 #include "rndis.c"
 #include "u_ether.c"
+#include "u_bam_data.c"
+#include "f_mbim.c"
 
 MODULE_AUTHOR("Mike Lockwood");
 MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -116,6 +118,7 @@
 	struct android_usb_platform_data *pdata;
 
 	bool enabled;
+	struct mutex mutex;
 	bool connected;
 	bool sw_connected;
 	struct work_struct work;
@@ -164,12 +167,28 @@
 	.bNumConfigurations   = 1,
 };
 
+static struct usb_otg_descriptor otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
+	.bDescriptorType =	USB_DT_OTG,
+	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
+	.bcdOTG               = __constant_cpu_to_le16(0x0200),
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+	NULL,
+};
+
 static struct usb_configuration android_config_driver = {
 	.label		= "android",
 	.unbind		= android_unbind_config,
 	.bConfigurationValue = 1,
-	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower	= 0xFA, /* 500ma */
+};
+
+enum android_device_state {
+	USB_DISCONNECTED,
+	USB_CONNECTED,
+	USB_CONFIGURED,
 };
 
 static void android_work(struct work_struct *data)
@@ -180,18 +199,45 @@
 	char *connected[2]    = { "USB_STATE=CONNECTED", NULL };
 	char *configured[2]   = { "USB_STATE=CONFIGURED", NULL };
 	char **uevent_envp = NULL;
+	static enum android_device_state last_uevent, next_state;
 	unsigned long flags;
 
 	spin_lock_irqsave(&cdev->lock, flags);
-        if (cdev->config)
+	if (cdev->config) {
 		uevent_envp = configured;
-	else if (dev->connected != dev->sw_connected)
+		next_state = USB_CONFIGURED;
+	} else if (dev->connected != dev->sw_connected) {
 		uevent_envp = dev->connected ? connected : disconnected;
+		next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
+	}
 	dev->sw_connected = dev->connected;
 	spin_unlock_irqrestore(&cdev->lock, flags);
 
 	if (uevent_envp) {
+		/*
+		 * Some userspace modules, e.g. MTP, work correctly only if
+		 * CONFIGURED uevent is preceded by DISCONNECT uevent.
+		 * Check if we missed sending out a DISCONNECT uevent. This can
+		 * happen if host PC resets and configures device really quick.
+		 */
+		if (((uevent_envp == connected) &&
+		      (last_uevent != USB_DISCONNECTED)) ||
+		    ((uevent_envp == configured) &&
+		      (last_uevent == USB_CONFIGURED))) {
+			pr_info("%s: sent missed DISCONNECT event\n", __func__);
+			kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE,
+								disconnected);
+			msleep(20);
+		}
+		/*
+		 * Before sending out CONFIGURED uevent give function drivers
+		 * a chance to wakeup userspace threads and notify disconnect
+		 */
+		if (uevent_envp == configured)
+			msleep(50);
+
 		kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
+		last_uevent = next_state;
 		pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
 	} else {
 		pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
@@ -342,6 +388,35 @@
 	.attributes	= rmnet_function_attributes,
 };
 
+
+/* MBIM - used with BAM */
+#define MAX_MBIM_INSTANCES 1
+
+static int mbim_function_init(struct android_usb_function *f,
+					 struct usb_composite_dev *cdev)
+{
+	return mbim_init(MAX_MBIM_INSTANCES);
+}
+
+static void mbim_function_cleanup(struct android_usb_function *f)
+{
+	fmbim_cleanup();
+}
+
+static int mbim_function_bind_config(struct android_usb_function *f,
+					  struct usb_configuration *c)
+{
+	return mbim_bind_config(c, 0);
+}
+
+static struct android_usb_function mbim_function = {
+	.name		= "usb_mbim",
+	.cleanup	= mbim_function_cleanup,
+	.bind_config	= mbim_function_bind_config,
+	.init		= mbim_function_init,
+};
+
+
 /* DIAG */
 static char diag_clients[32];	    /*enabled DIAG clients- "diag[,diag_mdm]" */
 static ssize_t clients_store(
@@ -458,7 +533,7 @@
 	}
 
 bind_config:
-	for (i = 0; i < ports; i++) { 
+	for (i = 0; i < ports; i++) {
 		err = gser_bind_config(c, i);
 		if (err) {
 			pr_err("serial: bind_config failed for port %d", i);
@@ -960,6 +1035,7 @@
 
 
 static struct android_usb_function *supported_functions[] = {
+	&mbim_function,
 	&rmnet_smd_function,
 	&rmnet_sdio_function,
 	&rmnet_smd_sdio_function,
@@ -977,6 +1053,31 @@
 	NULL
 };
 
+static void android_cleanup_functions(struct android_usb_function **functions)
+{
+	struct android_usb_function *f;
+	struct device_attribute **attrs;
+	struct device_attribute *attr;
+
+	while (*functions) {
+		f = *functions++;
+
+		if (f->dev) {
+			device_destroy(android_class, f->dev->devt);
+			kfree(f->dev_name);
+		} else
+			continue;
+
+		if (f->cleanup)
+			f->cleanup(f);
+
+		attrs = f->attributes;
+		if (attrs) {
+			while ((attr = *attrs++))
+				device_remove_file(f->dev, attr);
+		}
+	}
+}
 
 static int android_init_functions(struct android_usb_function **functions,
 				  struct usb_composite_dev *cdev)
@@ -986,16 +1087,21 @@
 	struct device_attribute **attrs;
 	struct device_attribute *attr;
 	int err = 0;
-	int index = 0;
+	int index = 1; /* index 0 is for android0 device */
 
 	for (; (f = *functions++); index++) {
 		f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name);
+		if (!f->dev_name) {
+			err = -ENOMEM;
+			goto err_out;
+		}
 		f->dev = device_create(android_class, dev->dev,
 				MKDEV(0, index), f, f->dev_name);
 		if (IS_ERR(f->dev)) {
 			pr_err("%s: Failed to create dev %s", __func__,
 							f->dev_name);
 			err = PTR_ERR(f->dev);
+			f->dev = NULL;
 			goto err_create;
 		}
 
@@ -1004,7 +1110,7 @@
 			if (err) {
 				pr_err("%s: Failed to init %s", __func__,
 								f->name);
-				goto err_out;
+				goto err_init;
 			}
 		}
 
@@ -1016,35 +1122,26 @@
 		if (err) {
 			pr_err("%s: Failed to create function %s attributes",
 					__func__, f->name);
-			goto err_out;
+			goto err_attrs;
 		}
 	}
 	return 0;
 
-err_out:
+err_attrs:
+	for (attr = *(attrs -= 2); attrs != f->attributes; attr = *(attrs--))
+		device_remove_file(f->dev, attr);
+	if (f->cleanup)
+		f->cleanup(f);
+err_init:
 	device_destroy(android_class, f->dev->devt);
 err_create:
+	f->dev = NULL;
 	kfree(f->dev_name);
+err_out:
+	android_cleanup_functions(dev->functions);
 	return err;
 }
 
-static void android_cleanup_functions(struct android_usb_function **functions)
-{
-	struct android_usb_function *f;
-
-	while (*functions) {
-		f = *functions++;
-
-		if (f->dev) {
-			device_destroy(android_class, f->dev->devt);
-			kfree(f->dev_name);
-		}
-
-		if (f->cleanup)
-			f->cleanup(f);
-	}
-}
-
 static int
 android_bind_enabled_functions(struct android_dev *dev,
 			       struct usb_configuration *c)
@@ -1123,8 +1220,13 @@
 	struct android_usb_function *f;
 	char *buff = buf;
 
+	mutex_lock(&dev->mutex);
+
 	list_for_each_entry(f, &dev->enabled_functions, enabled_list)
 		buff += snprintf(buff, PAGE_SIZE, "%s,", f->name);
+
+	mutex_unlock(&dev->mutex);
+
 	if (buff != buf)
 		*(buff-1) = '\n';
 	return buff - buf;
@@ -1139,6 +1241,13 @@
 	char buf[256], *b;
 	int err;
 
+	mutex_lock(&dev->mutex);
+
+	if (dev->enabled) {
+		mutex_unlock(&dev->mutex);
+		return -EBUSY;
+	}
+
 	INIT_LIST_HEAD(&dev->enabled_functions);
 
 	strlcpy(buf, buff, sizeof(buf));
@@ -1153,6 +1262,8 @@
 		}
 	}
 
+	mutex_unlock(&dev->mutex);
+
 	return size;
 }
 
@@ -1170,6 +1281,8 @@
 	struct usb_composite_dev *cdev = dev->cdev;
 	int enabled = 0;
 
+	mutex_lock(&dev->mutex);
+
 	sscanf(buff, "%d", &enabled);
 	if (enabled && !dev->enabled) {
 		/* update values in composite driver's copy of device descriptor */
@@ -1187,12 +1300,16 @@
 		dev->enabled = true;
 	} else if (!enabled && dev->enabled) {
 		usb_gadget_disconnect(cdev->gadget);
+		/* Cancel pending control requests */
+		usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
 		usb_remove_config(cdev, &android_config_driver);
 		dev->enabled = false;
 	} else {
 		pr_err("android_usb: already %s\n",
 				dev->enabled ? "enabled" : "disabled");
 	}
+
+	mutex_unlock(&dev->mutex);
 	return size;
 }
 
@@ -1227,9 +1344,9 @@
 }									\
 static ssize_t								\
 field ## _store(struct device *dev, struct device_attribute *attr,	\
-		const char *buf, size_t size)		       		\
+		const char *buf, size_t size)				\
 {									\
-	int value;					       		\
+	int value;							\
 	if (sscanf(buf, format_string, &value) == 1) {			\
 		device_desc.field = value;				\
 		return size;						\
@@ -1247,7 +1364,7 @@
 }									\
 static ssize_t								\
 field ## _store(struct device *dev, struct device_attribute *attr,	\
-		const char *buf, size_t size)		       		\
+		const char *buf, size_t size)				\
 {									\
 	if (size >= sizeof(buffer)) return -EINVAL;			\
 	if (sscanf(buf, "%255s", buffer) == 1) {			\
@@ -1352,6 +1469,9 @@
 	strings_dev[STRING_SERIAL_IDX].id = id;
 	device_desc.iSerialNumber = id;
 
+	if (gadget_is_otg(cdev->gadget))
+		android_config_driver.descriptors = otg_desc;
+
 	gcnum = usb_gadget_controller_number(gadget);
 	if (gcnum >= 0)
 		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
@@ -1368,7 +1488,6 @@
 		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
 	}
 
-	usb_gadget_set_selfpowered(gadget);
 	dev->cdev = cdev;
 
 	return 0;
@@ -1378,6 +1497,9 @@
 {
 	struct android_dev *dev = _android_dev;
 
+	manufacturer_string[0] = '\0';
+	product_string[0] = '\0';
+	serial_string[0] = '0';
 	cancel_work_sync(&dev->work);
 	android_cleanup_functions(dev->functions);
 	return 0;
@@ -1388,6 +1510,7 @@
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.unbind		= android_usb_unbind,
+	.max_speed	= USB_SPEED_SUPER
 };
 
 static int
@@ -1486,15 +1609,29 @@
 {
 	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
 	struct android_dev *dev = _android_dev;
+	int ret = 0;
 
 	dev->pdata = pdata;
 
+	ret = usb_composite_probe(&android_usb_driver, android_bind);
+	if (ret) {
+		pr_err("%s(): Failed to register android "
+				 "composite driver\n", __func__);
+	}
+
+	return ret;
+}
+
+static int android_remove(struct platform_device *pdev)
+{
+	usb_composite_unregister(&android_usb_driver);
 	return 0;
 }
 
 static struct platform_driver android_platform_driver = {
-	.probe = android_probe,
 	.driver = { .name = "android_usb"},
+	.probe = android_probe,
+	.remove = android_remove,
 };
 
 static int __init init(void)
@@ -1516,6 +1653,7 @@
 	dev->functions = supported_functions;
 	INIT_LIST_HEAD(&dev->enabled_functions);
 	INIT_WORK(&dev->work, android_work);
+	mutex_init(&dev->mutex);
 
 	ret = android_create_device(dev);
 	if (ret) {
@@ -1534,13 +1672,7 @@
 				 "platform driver\n", __func__);
 		goto err_probe;
 	}
-	ret = usb_composite_probe(&android_usb_driver, android_bind);
-	if (ret) {
-		pr_err("%s(): Failed to register android"
-				 "composite driver\n", __func__);
-		platform_driver_unregister(&android_platform_driver);
-		goto err_probe;
-	}
+
 	return ret;
 
 err_probe:
@@ -1554,9 +1686,10 @@
 
 static void __exit cleanup(void)
 {
-	usb_composite_unregister(&android_usb_driver);
-	class_destroy(android_class);
+	platform_driver_unregister(&android_platform_driver);
+	android_destroy_device(_android_dev);
 	kfree(_android_dev);
+	class_destroy(android_class);
 	_android_dev = NULL;
 }
 module_exit(cleanup);
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index f4690ff..98cbc06 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_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index c893889..863143b 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.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
@@ -21,6 +21,12 @@
 
 #define MSM_USB_BASE	(udc->regs)
 
+struct ci13xxx_udc_context {
+	int irq;
+	void __iomem *regs;
+};
+static struct ci13xxx_udc_context _udc_ctxt;
+
 static irqreturn_t msm_udc_irq(int irq, void *data)
 {
 	return udc_irq();
@@ -34,7 +40,7 @@
 	case CI13XXX_CONTROLLER_RESET_EVENT:
 		dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
 		writel(0, USB_AHBBURST);
-		writel(0, USB_AHBMODE);
+		writel_relaxed(0x08, USB_AHBMODE);
 		break;
 	default:
 		dev_dbg(dev, "unknown ci13xxx_udc event\n");
@@ -47,8 +53,9 @@
 	.flags			= CI13XXX_REGS_SHARED |
 				  CI13XXX_REQUIRE_TRANSCEIVER |
 				  CI13XXX_PULLUP_ON_VBUS |
+				  CI13XXX_ZERO_ITC |
 				  CI13XXX_DISABLE_STREAMING |
-				  CI13XXX_ZERO_ITC,
+				  CI13XXX_IS_OTG,
 
 	.notify_event		= ci13xxx_msm_notify_event,
 };
@@ -56,8 +63,6 @@
 static int ci13xxx_msm_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	void __iomem *regs;
-	int irq;
 	int ret;
 
 	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
@@ -68,26 +73,27 @@
 		return -ENXIO;
 	}
 
-	regs = ioremap(res->start, resource_size(res));
-	if (!regs) {
+	_udc_ctxt.regs = ioremap(res->start, resource_size(res));
+	if (!_udc_ctxt.regs) {
 		dev_err(&pdev->dev, "ioremap failed\n");
 		return -ENOMEM;
 	}
 
-	ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs);
+	ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, _udc_ctxt.regs);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "udc_probe failed\n");
 		goto iounmap;
 	}
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
+	_udc_ctxt.irq = platform_get_irq(pdev, 0);
+	if (_udc_ctxt.irq < 0) {
 		dev_err(&pdev->dev, "IRQ not found\n");
 		ret = -ENXIO;
 		goto udc_remove;
 	}
 
-	ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
+	ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name,
+					  pdev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "request_irq failed\n");
 		goto udc_remove;
@@ -101,14 +107,24 @@
 udc_remove:
 	udc_remove();
 iounmap:
-	iounmap(regs);
+	iounmap(_udc_ctxt.regs);
 
 	return ret;
 }
 
+int ci13xxx_msm_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+	free_irq(_udc_ctxt.irq, pdev);
+	udc_remove();
+	iounmap(_udc_ctxt.regs);
+	return 0;
+}
+
 static struct platform_driver ci13xxx_msm_driver = {
 	.probe = ci13xxx_msm_probe,
 	.driver = { .name = "msm_hsusb", },
+	.remove = ci13xxx_msm_remove,
 };
 
 static int __init ci13xxx_msm_init(void)
@@ -116,3 +132,11 @@
 	return platform_driver_register(&ci13xxx_msm_driver);
 }
 module_init(ci13xxx_msm_init);
+
+static void __exit ci13xxx_msm_exit(void)
+{
+	platform_driver_unregister(&ci13xxx_msm_driver);
+}
+module_exit(ci13xxx_msm_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 135c84d..c74b69a 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -35,14 +35,17 @@
 
 #define MSM_USB_BASE	(mhsic->regs)
 
-#define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
-#define USB_PHY_VDD_DIG_VOL_MIN		1045000 /* uV */
-#define USB_PHY_VDD_DIG_VOL_MAX		1320000 /* uV */
-#define USB_PHY_VDD_DIG_LOAD		49360	/* uA */
-#define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
-#define HSIC_CFG_REG 0x30
-#define HSIC_IO_CAL_PER_REG 0x33
-#define HSIC_DBG1_REG 0x38
+#define ULPI_IO_TIMEOUT_USEC			(10 * 1000)
+#define USB_PHY_VDD_DIG_VOL_SUSP_MIN	500000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MIN			1045000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MAX			1320000 /* uV */
+#define USB_PHY_VDD_DIG_LOAD			49360	/* uA */
+#define LINK_RESET_TIMEOUT_USEC			(250 * 1000)
+#define PHY_SUSPEND_TIMEOUT_USEC		(500 * 1000)
+#define PHY_RESUME_TIMEOUT_USEC			(100 * 1000)
+#define HSIC_CFG_REG					0x30
+#define HSIC_IO_CAL_PER_REG				0x33
+#define HSIC_DBG1_REG					0x38
 
 struct msm_hsic_per *the_mhsic;
 
@@ -57,6 +60,11 @@
 	bool				async_int;
 	void __iomem		*regs;
 	int					irq;
+	atomic_t			in_lpm;
+	struct wake_lock	wlock;
+	struct msm_xo_voter	*xo_handle;
+	struct workqueue_struct *wq;
+	struct work_struct	suspend_w;
 };
 
 static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
@@ -302,6 +310,227 @@
 	}
 }
 
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_hsic_suspend(struct msm_hsic_per *mhsic)
+{
+	int cnt = 0, ret;
+	u32 val;
+
+	if (atomic_read(&mhsic->in_lpm)) {
+		dev_dbg(mhsic->dev, "%s called while in lpm\n", __func__);
+		return 0;
+	}
+	disable_irq(mhsic->irq);
+
+	/*
+	 * PHY may take some time or even fail to enter into low power
+	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
+	 * in failure case.
+	 */
+	val = readl_relaxed(USB_PORTSC) | PORTSC_PHCD;
+	writel_relaxed(val, USB_PORTSC);
+
+	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+		if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
+		dev_err(mhsic->dev, "Unable to suspend PHY\n");
+		msm_hsic_reset(mhsic);
+	}
+
+	/*
+	 * PHY has capability to generate interrupt asynchronously in low
+	 * power mode (LPM). This interrupt is level triggered. So USB IRQ
+	 * line must be disabled till async interrupt enable bit is cleared
+	 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+	 * block data communication from PHY.
+	 */
+	writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
+				ULPI_STP_CTRL, USB_USBCMD);
+
+	/*
+	 * Ensure that hardware is put in low power mode before
+	 * clocks are turned OFF and VDD is allowed to minimize.
+	 */
+	mb();
+
+	clk_disable(mhsic->iface_clk);
+	clk_disable(mhsic->core_clk);
+	clk_disable(mhsic->phy_clk);
+	clk_disable(mhsic->cal_clk);
+
+	ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_OFF);
+	if (ret)
+		dev_err(mhsic->dev, "%s failed to devote for TCXO %d\n"
+				, __func__, ret);
+
+	ret = regulator_set_voltage(mhsic->hsic_vddcx,
+				USB_PHY_VDD_DIG_VOL_SUSP_MIN,
+				USB_PHY_VDD_DIG_VOL_MAX);
+	if (ret < 0)
+		dev_err(mhsic->dev, "unable to set vddcx voltage: min:0.5v max:1.32v\n");
+
+	if (device_may_wakeup(mhsic->dev))
+		enable_irq_wake(mhsic->irq);
+
+	atomic_set(&mhsic->in_lpm, 1);
+	enable_irq(mhsic->irq);
+	wake_unlock(&mhsic->wlock);
+
+	dev_info(mhsic->dev, "HSIC-USB in low power mode\n");
+
+	return 0;
+}
+
+static int msm_hsic_resume(struct msm_hsic_per *mhsic)
+{
+	int cnt = 0, ret;
+	unsigned temp;
+
+	if (!atomic_read(&mhsic->in_lpm)) {
+		dev_dbg(mhsic->dev, "%s called while not in lpm\n", __func__);
+		return 0;
+	}
+
+	wake_lock(&mhsic->wlock);
+	ret = regulator_set_voltage(mhsic->hsic_vddcx,
+				USB_PHY_VDD_DIG_VOL_MIN,
+				USB_PHY_VDD_DIG_VOL_MAX);
+	if (ret < 0)
+		dev_err(mhsic->dev,
+				"unable to set vddcx voltage: min:1.045v max:1.32v\n");
+
+	ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
+	if (ret)
+		dev_err(mhsic->dev, "%s failed to vote for TCXO %d\n",
+				__func__, ret);
+
+	clk_enable(mhsic->iface_clk);
+	clk_enable(mhsic->core_clk);
+	clk_enable(mhsic->phy_clk);
+	clk_enable(mhsic->cal_clk);
+
+	temp = readl_relaxed(USB_USBCMD);
+	temp &= ~ASYNC_INTR_CTRL;
+	temp &= ~ULPI_STP_CTRL;
+	writel_relaxed(temp, USB_USBCMD);
+
+	if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+		goto skip_phy_resume;
+
+	temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
+	writel_relaxed(temp, USB_PORTSC);
+	while (cnt < PHY_RESUME_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
+			(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
+		/*
+		 * This is a fatal error. Reset the link and
+		 * PHY to make hsic working.
+		 */
+		dev_err(mhsic->dev, "Unable to resume USB. Reset the hsic\n");
+		msm_hsic_reset(mhsic);
+	}
+skip_phy_resume:
+	if (device_may_wakeup(mhsic->dev))
+		disable_irq_wake(mhsic->irq);
+
+	atomic_set(&mhsic->in_lpm, 0);
+
+	if (mhsic->async_int) {
+		mhsic->async_int = false;
+		enable_irq(mhsic->irq);
+	}
+
+	dev_info(mhsic->dev, "HSIC-USB exited from low power mode\n");
+
+	return 0;
+}
+
+static int msm_hsic_pm_suspend(struct device *dev)
+{
+	struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "MSM HSIC Peripheral PM suspend\n");
+
+	return msm_hsic_suspend(mhsic);
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int msm_hsic_pm_resume(struct device *dev)
+{
+	dev_dbg(dev, "MSM HSIC Peripheral PM resume\n");
+
+	/*
+	 * Do not resume hardware as part of system resume,
+	 * rather, wait for the ASYNC INT from the h/w
+	 */
+	return 0;
+}
+#else
+static int msm_hsic_pm_resume(struct device *dev)
+{
+	struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "MSM HSIC Peripheral PM resume\n");
+
+	return msm_hsic_resume(mhsic);
+}
+#endif
+
+static void msm_hsic_pm_suspend_work(struct work_struct *w)
+{
+	pm_runtime_put_noidle(the_mhsic->dev);
+	pm_runtime_suspend(the_mhsic->dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+static int msm_hsic_runtime_idle(struct device *dev)
+{
+	dev_dbg(dev, "MSM HSIC Peripheral runtime idle\n");
+
+	return 0;
+}
+
+static int msm_hsic_runtime_suspend(struct device *dev)
+{
+	struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "MSM HSIC Peripheral runtime suspend\n");
+
+	return msm_hsic_suspend(mhsic);
+}
+
+static int msm_hsic_runtime_resume(struct device *dev)
+{
+	struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "MSM HSIC Peripheral runtime resume\n");
+	pm_runtime_get_noresume(mhsic->dev);
+
+	return msm_hsic_resume(mhsic);
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
+	SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
+				msm_hsic_runtime_idle)
+};
+#endif
+
 /**
  * Dummy match function - will be called only for HSIC msm
  * device (msm_device_gadget_hsic_peripheral).
@@ -320,6 +549,15 @@
 
 static irqreturn_t msm_udc_hsic_irq(int irq, void *data)
 {
+	struct msm_hsic_per *mhsic = data;
+
+	if (atomic_read(&mhsic->in_lpm)) {
+		disable_irq_nosync(mhsic->irq);
+		mhsic->async_int = true;
+		pm_request_resume(mhsic->dev);
+		return IRQ_HANDLED;
+	}
+
 	return udc_irq();
 }
 
@@ -332,12 +570,16 @@
 	case CI13XXX_CONTROLLER_RESET_EVENT:
 		dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
 		writel_relaxed(0, USB_AHBBURST);
-		writel_relaxed(0, USB_AHBMODE);
+		writel_relaxed(0x08, USB_AHBMODE);
 		break;
 	case CI13XXX_CONTROLLER_CONNECT_EVENT:
 		dev_dbg(dev, "CI13XXX_CONTROLLER_CONNECT_EVENT received\n");
 		msm_hsic_start();
 		break;
+	case CI13XXX_CONTROLLER_SUSPEND_EVENT:
+		dev_dbg(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
+		queue_work(mhsic->wq, &mhsic->suspend_w);
+		break;
 	default:
 		dev_dbg(dev, "unknown ci13xxx_udc event\n");
 		break;
@@ -378,6 +620,15 @@
 		goto error;
 	}
 
+	mhsic->wq = alloc_workqueue("mhsic_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!mhsic->wq) {
+		pr_err("%s: Unable to create workqueue mhsic wq\n",
+				__func__);
+		ret = -ENOMEM;
+		goto error;
+	}
+	INIT_WORK(&mhsic->suspend_w, msm_hsic_pm_suspend_work);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "Unable to get memory resource\n");
@@ -392,6 +643,21 @@
 	}
 	dev_info(&pdev->dev, "HSIC Peripheral regs = %p\n", mhsic->regs);
 
+	mhsic->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "hsic_peripheral");
+	if (IS_ERR(mhsic->xo_handle)) {
+		dev_err(&pdev->dev, "%s not able to get the handle "
+			"to vote for TCXO\n", __func__);
+		ret = PTR_ERR(mhsic->xo_handle);
+		goto unmap;
+	}
+
+	ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
+	if (ret) {
+		dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
+				__func__, ret);
+		goto free_xo_handle;
+	}
+
 	ret = msm_hsic_enable_clocks(pdev, mhsic, true);
 
 	if (ret) {
@@ -422,16 +688,21 @@
 
 	msm_hsic_connect_peripheral(&pdev->dev);
 
+	device_init_wakeup(&pdev->dev, 1);
+	wake_lock_init(&mhsic->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
+	wake_lock(&mhsic->wlock);
+
 	ret = request_irq(mhsic->irq, msm_udc_hsic_irq,
-					  IRQF_SHARED, pdev->name, pdev);
+					  IRQF_SHARED, pdev->name, mhsic);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "request_irq failed\n");
 		ret = -ENODEV;
 		goto udc_remove;
 	}
 
-	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
 
 	return 0;
 udc_remove:
@@ -440,9 +711,13 @@
 	msm_hsic_init_vddcx(mhsic, 0);
 deinit_clocks:
 	msm_hsic_enable_clocks(pdev, mhsic, 0);
+	msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_OFF);
+free_xo_handle:
+	msm_xo_put(mhsic->xo_handle);
 unmap:
 	iounmap(mhsic->regs);
 error:
+	destroy_workqueue(mhsic->wq);
 	kfree(mhsic);
 	return ret;
 }
@@ -452,19 +727,29 @@
 	struct msm_hsic_per *mhsic = platform_get_drvdata(pdev);
 
 	device_init_wakeup(&pdev->dev, 0);
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+
 	msm_hsic_init_vddcx(mhsic, 0);
 	msm_hsic_enable_clocks(pdev, mhsic, 0);
+	msm_xo_put(mhsic->xo_handle);
+	wake_lock_destroy(&mhsic->wlock);
+	destroy_workqueue(mhsic->wq);
 	udc_remove();
 	iounmap(mhsic->regs);
 	kfree(mhsic);
 
 	return 0;
 }
+
 static struct platform_driver msm_hsic_peripheral_driver = {
 	.probe	= msm_hsic_probe,
 	.remove	= __devexit_p(hsic_msm_remove),
 	.driver = {
 		.name = "msm_hsic_peripheral",
+#ifdef CONFIG_PM
+		.pm = &msm_hsic_dev_pm_ops,
+#endif
 	},
 };
 
@@ -482,3 +767,4 @@
 module_init(msm_hsic_peripheral_init);
 module_exit(msm_hsic_peripheral_exit);
 
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index ff4bbad..9cbfad8 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1918,6 +1918,11 @@
 	udc->configured = 0;
 	spin_unlock_irqrestore(udc->lock, flags);
 
+	gadget->b_hnp_enable = 0;
+	gadget->a_hnp_support = 0;
+	gadget->host_request = 0;
+	gadget->otg_srp_reqd = 0;
+
 	/* flush all endpoints */
 	gadget_for_each_ep(ep, gadget) {
 		usb_ep_fifo_flush(ep);
@@ -2046,8 +2051,15 @@
 	}
 
 	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
-		/* Assume that device is bus powered for now. */
-		*((u16 *)req->buf) = _udc->remote_wakeup << 1;
+		if (setup->wIndex == OTG_STATUS_SELECTOR) {
+			*((u8 *)req->buf) = _udc->gadget.host_request <<
+						HOST_REQUEST_FLAG;
+			req->length = 1;
+		} else {
+			/* Assume that device is bus powered for now. */
+			*((u16 *)req->buf) = _udc->remote_wakeup << 1;
+		}
+		/* TODO: D1 - Remote Wakeup; D0 - Self Powered */
 		retval = 0;
 	} else if ((setup->bRequestType & USB_RECIP_MASK) \
 		   == USB_RECIP_ENDPOINT) {
@@ -2297,8 +2309,7 @@
 			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
 			    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
 				goto delegate;
-			if (le16_to_cpu(req.wLength) != 2 ||
-			    le16_to_cpu(req.wValue)  != 0)
+			if (le16_to_cpu(req.wValue)  != 0)
 				break;
 			err = isr_get_status_response(udc, &req);
 			break;
@@ -2342,6 +2353,16 @@
 					udc->remote_wakeup = 1;
 					err = isr_setup_status_phase(udc);
 					break;
+				case USB_DEVICE_B_HNP_ENABLE:
+					udc->gadget.b_hnp_enable = 1;
+					err = isr_setup_status_phase(udc);
+					break;
+				case USB_DEVICE_A_HNP_SUPPORT:
+					udc->gadget.a_hnp_support = 1;
+					err = isr_setup_status_phase(udc);
+					break;
+				case USB_DEVICE_A_ALT_HNP_SUPPORT:
+					break;
 				case USB_DEVICE_TEST_MODE:
 					tmode = le16_to_cpu(req.wIndex) >> 8;
 					switch (tmode) {
@@ -2354,11 +2375,21 @@
 						err = isr_setup_status_phase(
 								udc);
 						break;
+					case TEST_OTG_SRP_REQD:
+						udc->gadget.otg_srp_reqd = 1;
+						err = isr_setup_status_phase(
+								udc);
+						break;
+					case TEST_OTG_HNP_REQD:
+						udc->gadget.host_request = 1;
+						err = isr_setup_status_phase(
+								udc);
+						break;
 					default:
 						break;
 					}
 				default:
-					goto delegate;
+					break;
 				}
 			} else {
 				goto delegate;
@@ -2485,6 +2516,7 @@
 	} while (mEp->dir != direction);
 
 	mEp->desc = NULL;
+	mEp->ep.desc = NULL;
 
 	spin_unlock_irqrestore(mEp->lock, flags);
 	return retval;
@@ -2857,7 +2889,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 +2902,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 +2996,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 +3046,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 +3111,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /******************************************************************************
  * BUS block
@@ -3140,6 +3176,9 @@
 				udc->suspended = 1;
 				spin_unlock(udc->lock);
 				udc->driver->suspend(&udc->gadget);
+				if (udc->udc_driver->notify_event)
+					udc->udc_driver->notify_event(udc,
+					  CI13XXX_CONTROLLER_SUSPEND_EVENT);
 				spin_lock(udc->lock);
 			}
 			isr_statistics.sli++;
@@ -3182,7 +3221,7 @@
 		void __iomem *regs)
 {
 	struct ci13xxx *udc;
-	int retval = 0;
+	int retval = 0, i;
 
 	trace("%p, %p, %p", dev, regs, name);
 
@@ -3201,7 +3240,10 @@
 	udc->gadget.ops          = &usb_gadget_ops;
 	udc->gadget.speed        = USB_SPEED_UNKNOWN;
 	udc->gadget.is_dualspeed = 1;
-	udc->gadget.is_otg       = 0;
+	if (udc->udc_driver->flags & CI13XXX_IS_OTG)
+		udc->gadget.is_otg       = 1;
+	else
+		udc->gadget.is_otg       = 0;
 	udc->gadget.name         = driver->name;
 
 	INIT_LIST_HEAD(&udc->gadget.ep_list);
@@ -3217,6 +3259,11 @@
 	if (retval < 0)
 		goto free_udc;
 
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+		INIT_LIST_HEAD(&mEp->ep.ep_list);
+	}
+
 	udc->transceiver = otg_get_transceiver();
 
 	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
@@ -3249,12 +3296,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 +3342,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/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index fce611a..684517b 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -125,9 +125,11 @@
 #define CI13XXX_PULLUP_ON_VBUS		BIT(2)
 #define CI13XXX_DISABLE_STREAMING	BIT(3)
 #define CI13XXX_ZERO_ITC		BIT(4)
+#define CI13XXX_IS_OTG			BIT(5)
 
 #define CI13XXX_CONTROLLER_RESET_EVENT		0
 #define CI13XXX_CONTROLLER_CONNECT_EVENT	1
+#define CI13XXX_CONTROLLER_SUSPEND_EVENT	2
 	void	(*notify_event) (struct ci13xxx *udc, unsigned event);
 };
 
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4c33695..4f2946c 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,
 
@@ -1310,6 +1634,8 @@
 int usb_composite_probe(struct usb_composite_driver *driver,
 			       int (*bind)(struct usb_composite_dev *cdev))
 {
+	int retval;
+
 	if (!driver || !driver->dev || !bind || composite)
 		return -EINVAL;
 
@@ -1319,10 +1645,15 @@
 		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;
 
-	return usb_gadget_probe_driver(&composite_driver, composite_bind);
+	retval = usb_gadget_probe_driver(&composite_driver, composite_bind);
+	if (retval)
+		composite = NULL;
+	return retval;
 }
 
 /**
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..72bff49 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;
@@ -665,21 +664,20 @@
 	struct usb_diag_ch *ch;
 
 	list_for_each_entry(ch, &usb_diag_ch_list, list) {
-		struct diag_context *ctxt;
+		struct diag_context *ctxt = ch->priv_usb;
 
-		ctxt = ch->priv_usb;
-
-		temp += scnprintf(buf + temp, PAGE_SIZE - temp,
-				"---Name: %s---\n"
-				"endpoints: %s, %s\n"
-				"dpkts_tolaptop: %lu\n"
-				"dpkts_tomodem:  %lu\n"
-				"pkts_tolaptop_pending: %u\n",
-				ch->name,
-				ctxt->in->name, ctxt->out->name,
-				ctxt->dpkts_tolaptop,
-				ctxt->dpkts_tomodem,
-				ctxt->dpkts_tolaptop_pending);
+		if (ctxt)
+			temp += scnprintf(buf + temp, PAGE_SIZE - temp,
+					"---Name: %s---\n"
+					"endpoints: %s, %s\n"
+					"dpkts_tolaptop: %lu\n"
+					"dpkts_tomodem:  %lu\n"
+					"pkts_tolaptop_pending: %u\n",
+					ch->name,
+					ctxt->in->name, ctxt->out->name,
+					ctxt->dpkts_tolaptop,
+					ctxt->dpkts_tomodem,
+					ctxt->dpkts_tolaptop_pending);
 	}
 
 	return simple_read_from_buffer(ubuf, count, ppos, buf, temp);
@@ -691,13 +689,13 @@
 	struct usb_diag_ch *ch;
 
 	list_for_each_entry(ch, &usb_diag_ch_list, list) {
-		struct diag_context *ctxt;
+		struct diag_context *ctxt = ch->priv_usb;
 
-		ctxt = ch->priv_usb;
-
-		ctxt->dpkts_tolaptop = 0;
-		ctxt->dpkts_tomodem = 0;
-		ctxt->dpkts_tolaptop_pending = 0;
+		if (ctxt) {
+			ctxt->dpkts_tolaptop = 0;
+			ctxt->dpkts_tomodem = 0;
+			ctxt->dpkts_tolaptop_pending = 0;
+		}
 	}
 
 	return count;
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 544257a..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..03e5968 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;
@@ -373,7 +374,7 @@
 
 	/* support autoresume for remote wakeup testing */
 	if (autoresume)
-		sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 
 	/* support OTG systems */
 	if (gadget_is_otg(cdev->gadget)) {
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_mbim.c b/drivers/usb/gadget/f_mbim.c
new file mode 100644
index 0000000..8288496
--- /dev/null
+++ b/drivers/usb/gadget/f_mbim.c
@@ -0,0 +1,1772 @@
+/* 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/kernel.h>
+#include <linux/device.h>
+
+#include <linux/usb/cdc.h>
+
+#include <linux/usb/composite.h>
+#include <linux/usb/android_composite.h>
+#include <linux/platform_device.h>
+
+#include <linux/spinlock.h>
+
+/*
+ * This function is a "Mobile Broadband Interface Model" (MBIM) link.
+ * MBIM is intended to be used with high-speed network attachments.
+ *
+ * Note that MBIM requires the use of "alternate settings" for its data
+ * interface.  This means that the set_alt() method has real work to do,
+ * and also means that a get_alt() method is required.
+ */
+
+#define MBIM_BULK_BUFFER_SIZE		4096
+
+#define MBIM_IOCTL_MAGIC		'o'
+#define MBIM_GET_NTB_SIZE		_IOR(MBIM_IOCTL_MAGIC, 2, u32)
+#define MBIM_GET_DATAGRAM_COUNT		_IOR(MBIM_IOCTL_MAGIC, 3, u16)
+
+#define NR_MBIM_PORTS			1
+
+struct ctrl_pkt {
+	void			*buf;
+	int			len;
+	struct list_head	list;
+};
+
+struct mbim_ep_descs {
+	struct usb_endpoint_descriptor	*in;
+	struct usb_endpoint_descriptor	*out;
+	struct usb_endpoint_descriptor	*notify;
+};
+
+struct mbim_notify_port {
+	struct usb_ep			*notify;
+	struct usb_request		*notify_req;
+	u8				notify_state;
+	atomic_t			notify_count;
+};
+
+enum mbim_notify_state {
+	NCM_NOTIFY_NONE,
+	NCM_NOTIFY_CONNECT,
+	NCM_NOTIFY_SPEED,
+};
+
+struct f_mbim {
+	struct usb_function function;
+	struct usb_composite_dev *cdev;
+
+	atomic_t	online;
+	bool		is_open;
+
+	atomic_t	open_excl;
+	atomic_t	ioctl_excl;
+	atomic_t	read_excl;
+	atomic_t	write_excl;
+
+	wait_queue_head_t read_wq;
+	wait_queue_head_t write_wq;
+
+	u8				port_num;
+	struct data_port		bam_port;
+	struct mbim_notify_port		not_port;
+
+	struct mbim_ep_descs		fs;
+	struct mbim_ep_descs		hs;
+
+	u8				ctrl_id, data_id;
+
+	struct ndp_parser_opts		*parser_opts;
+
+	spinlock_t			lock;
+
+	struct list_head	cpkt_req_q;
+	struct list_head	cpkt_resp_q;
+
+	u32			ntb_input_size;
+	u16			ntb_max_datagrams;
+
+	pid_t			user_pid;
+
+	atomic_t		error;
+};
+
+struct mbim_ntb_input_size {
+	u32	ntb_input_size;
+	u16	ntb_max_datagrams;
+	u16	reserved;
+};
+
+/* temporary variable used between mbim_open() and mbim_gadget_bind() */
+static struct f_mbim *_mbim_dev;
+
+static unsigned int nr_mbim_ports;
+
+static struct mbim_ports {
+	struct f_mbim	*port;
+	unsigned	port_num;
+} mbim_ports[NR_MBIM_PORTS];
+
+static inline struct f_mbim *func_to_mbim(struct usb_function *f)
+{
+	return container_of(f, struct f_mbim, function);
+}
+
+/* peak (theoretical) bulk transfer rate in bits-per-second */
+static inline unsigned mbim_bitrate(struct usb_gadget *g)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return 13 * 512 * 8 * 1000 * 8;
+	else
+		return 19 *  64 * 1 * 1000 * 8;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define NTB_DEFAULT_IN_SIZE	(0x4000)
+#define NTB_OUT_SIZE		(0x1000)
+#define NDP_IN_DIVISOR		(0x4)
+
+#define FORMATS_SUPPORTED	USB_CDC_NCM_NTB16_SUPPORTED
+
+static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
+	.wLength = sizeof ntb_parameters,
+	.bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
+	.dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
+	.wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
+	.wNdpInPayloadRemainder = cpu_to_le16(0),
+	.wNdpInAlignment = cpu_to_le16(4),
+
+	.dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
+	.wNdpOutDivisor = cpu_to_le16(4),
+	.wNdpOutPayloadRemainder = cpu_to_le16(0),
+	.wNdpOutAlignment = cpu_to_le16(4),
+	.wNtbOutMaxDatagrams = cpu_to_le16(4),
+};
+
+/*
+ * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
+ * packet, to simplify cancellation; and a big transfer interval, to
+ * waste less bandwidth.
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC	5	/* 1 << 5 == 32 msec */
+#define NCM_STATUS_BYTECOUNT		16	/* 8 byte header + data */
+
+static struct usb_interface_assoc_descriptor mbim_iad_desc = {
+	.bLength =		sizeof mbim_iad_desc,
+	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
+
+	/* .bFirstInterface =	DYNAMIC, */
+	.bInterfaceCount =	2,	/* control + data */
+	.bFunctionClass =	2,
+	.bFunctionSubClass =	0x0e,
+	.bFunctionProtocol =	0,
+	/* .iFunction =		DYNAMIC */
+};
+
+/* interface descriptor: */
+static struct usb_interface_descriptor mbim_control_intf = {
+	.bLength =		sizeof mbim_control_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber = DYNAMIC */
+	.bNumEndpoints =	1,
+	.bInterfaceClass =	0x02,
+	.bInterfaceSubClass =	0x0e,
+	.bInterfaceProtocol =	0,
+	/* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc mbim_header_desc = {
+	.bLength =		sizeof mbim_header_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+
+	.bcdCDC =		cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_union_desc mbim_union_desc = {
+	.bLength =		sizeof(mbim_union_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+	/* .bMasterInterface0 =	DYNAMIC */
+	/* .bSlaveInterface0 =	DYNAMIC */
+};
+
+static struct usb_cdc_mbb_desc mbb_desc = {
+	.bLength =		sizeof mbb_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_MBB_TYPE,
+
+	.bcdMbbVersion =	cpu_to_le16(0x0100),
+
+	.wMaxControlMessage =	cpu_to_le16(0x1000),
+	.bNumberFilters =	0x10,
+	.bMaxFilterSize =	0x80,
+	.wMaxSegmentSize =	cpu_to_le16(0x1000),
+	.bmNetworkCapabilities = 0x20,
+};
+
+/* the default data interface has no endpoints ... */
+static struct usb_interface_descriptor mbim_data_nop_intf = {
+	.bLength =		sizeof mbim_data_nop_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber = DYNAMIC */
+	.bAlternateSetting =	0,
+	.bNumEndpoints =	0,
+	.bInterfaceClass =	0x0a,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0x02,
+	/* .iInterface = DYNAMIC */
+};
+
+/* ... but the "real" data interface has two bulk endpoints */
+static struct usb_interface_descriptor mbim_data_intf = {
+	.bLength =		sizeof mbim_data_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber = DYNAMIC */
+	.bAlternateSetting =	1,
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	0x0a,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0x02,
+	/* .iInterface = DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor fs_mbim_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
+	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+
+static struct usb_endpoint_descriptor fs_mbim_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor fs_mbim_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *mbim_fs_function[] = {
+	(struct usb_descriptor_header *) &mbim_iad_desc,
+	/* MBIM control descriptors */
+	(struct usb_descriptor_header *) &mbim_control_intf,
+	(struct usb_descriptor_header *) &mbim_header_desc,
+	(struct usb_descriptor_header *) &mbb_desc,
+	(struct usb_descriptor_header *) &fs_mbim_notify_desc,
+	/* data interface, altsettings 0 and 1 */
+	(struct usb_descriptor_header *) &mbim_data_nop_intf,
+	(struct usb_descriptor_header *) &mbim_data_intf,
+	(struct usb_descriptor_header *) &fs_mbim_in_desc,
+	(struct usb_descriptor_header *) &fs_mbim_out_desc,
+	NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor hs_mbim_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+static struct usb_endpoint_descriptor hs_mbim_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_mbim_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *mbim_hs_function[] = {
+	(struct usb_descriptor_header *) &mbim_iad_desc,
+	/* MBIM control descriptors */
+	(struct usb_descriptor_header *) &mbim_control_intf,
+	(struct usb_descriptor_header *) &mbim_header_desc,
+	(struct usb_descriptor_header *) &mbb_desc,
+	(struct usb_descriptor_header *) &hs_mbim_notify_desc,
+	/* data interface, altsettings 0 and 1 */
+	(struct usb_descriptor_header *) &mbim_data_nop_intf,
+	(struct usb_descriptor_header *) &mbim_data_intf,
+	(struct usb_descriptor_header *) &hs_mbim_in_desc,
+	(struct usb_descriptor_header *) &hs_mbim_out_desc,
+	NULL,
+};
+
+/* string descriptors: */
+
+#define STRING_CTRL_IDX	0
+#define STRING_DATA_IDX	1
+
+static struct usb_string mbim_string_defs[] = {
+	[STRING_CTRL_IDX].s = "MBIM Control",
+	[STRING_DATA_IDX].s = "MBIM Data",
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings mbim_string_table = {
+	.language =		0x0409,	/* en-us */
+	.strings =		mbim_string_defs,
+};
+
+static struct usb_gadget_strings *mbim_strings[] = {
+	&mbim_string_table,
+	NULL,
+};
+
+/*
+ * Here are options for the Datagram Pointer table (NDP) parser.
+ * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
+ * in NDP16 offsets and sizes fields are 1 16bit word wide,
+ * in NDP32 -- 2 16bit words wide. Also signatures are different.
+ * To make the parser code the same, put the differences in the structure,
+ * and switch pointers to the structures when the format is changed.
+ */
+
+struct ndp_parser_opts {
+	u32		nth_sign;
+	u32		ndp_sign;
+	unsigned	nth_size;
+	unsigned	ndp_size;
+	unsigned	ndplen_align;
+	/* sizes in u16 units */
+	unsigned	dgram_item_len; /* index or length */
+	unsigned	block_length;
+	unsigned	fp_index;
+	unsigned	reserved1;
+	unsigned	reserved2;
+	unsigned	next_fp_index;
+};
+
+#define INIT_NDP16_OPTS {				\
+	.nth_sign = USB_CDC_NCM_NTH16_SIGN,		\
+	.ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN,	\
+	.nth_size = sizeof(struct usb_cdc_ncm_nth16),	\
+	.ndp_size = sizeof(struct usb_cdc_ncm_ndp16),	\
+	.ndplen_align = 4,				\
+	.dgram_item_len = 1,				\
+	.block_length = 1,				\
+	.fp_index = 1,					\
+	.reserved1 = 0,					\
+	.reserved2 = 0,					\
+	.next_fp_index = 1,				\
+}
+
+#define INIT_NDP32_OPTS {				\
+	.nth_sign = USB_CDC_NCM_NTH32_SIGN,		\
+	.ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN,	\
+	.nth_size = sizeof(struct usb_cdc_ncm_nth32),	\
+	.ndp_size = sizeof(struct usb_cdc_ncm_ndp32),	\
+	.ndplen_align = 8,				\
+	.dgram_item_len = 2,				\
+	.block_length = 2,				\
+	.fp_index = 2,					\
+	.reserved1 = 1,					\
+	.reserved2 = 2,					\
+	.next_fp_index = 2,				\
+}
+
+static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
+static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+
+static inline int mbim_lock(atomic_t *excl)
+{
+	if (atomic_inc_return(excl) == 1) {
+		return 0;
+	} else {
+		atomic_dec(excl);
+		return -EBUSY;
+	}
+}
+
+static inline void mbim_unlock(atomic_t *excl)
+{
+	atomic_dec(excl);
+}
+
+static struct ctrl_pkt *mbim_alloc_ctrl_pkt(unsigned len, gfp_t flags)
+{
+	struct ctrl_pkt *pkt;
+
+	pkt = kzalloc(sizeof(struct ctrl_pkt), flags);
+	if (!pkt)
+		return ERR_PTR(-ENOMEM);
+
+	pkt->buf = kmalloc(len, flags);
+	if (!pkt->buf) {
+		kfree(pkt);
+		return ERR_PTR(-ENOMEM);
+	}
+	pkt->len = len;
+
+	return pkt;
+}
+
+static void mbim_free_ctrl_pkt(struct ctrl_pkt *pkt)
+{
+	if (pkt) {
+		kfree(pkt->buf);
+		kfree(pkt);
+	}
+}
+
+static struct usb_request *mbim_alloc_req(struct usb_ep *ep, int buffer_size)
+{
+	struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
+	if (!req)
+		return NULL;
+
+	req->buf = kmalloc(buffer_size, GFP_KERNEL);
+	if (!req->buf) {
+		usb_ep_free_request(ep, req);
+		return NULL;
+	}
+	req->length = buffer_size;
+	return req;
+}
+
+void fmbim_free_req(struct usb_ep *ep, struct usb_request *req)
+{
+	if (req) {
+		kfree(req->buf);
+		usb_ep_free_request(ep, req);
+	}
+}
+
+static void fmbim_ctrl_response_available(struct f_mbim *dev)
+{
+	struct usb_request		*req = dev->not_port.notify_req;
+	struct usb_cdc_notification	*event = NULL;
+	unsigned long			flags;
+	int				ret;
+
+	int notif_c = 0;
+
+	pr_info("dev:%p portno#%d\n", dev, dev->port_num);
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (!atomic_read(&dev->online)) {
+		pr_info("dev:%p is not online\n", dev);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return;
+	}
+
+	if (!req) {
+		pr_info("dev:%p req is NULL\n", dev);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return;
+	}
+
+	if (!req->buf) {
+		pr_info("dev:%p req->buf is NULL\n", dev);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return;
+	}
+
+	notif_c = atomic_inc_return(&dev->not_port.notify_count);
+	pr_info("atomic_inc_return[notif_c] = %d", notif_c);
+
+	event = req->buf;
+	event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
+			| USB_RECIP_INTERFACE;
+	event->bNotificationType = USB_CDC_NOTIFY_RESPONSE_AVAILABLE;
+	event->wValue = cpu_to_le16(0);
+	event->wIndex = cpu_to_le16(dev->ctrl_id);
+	event->wLength = cpu_to_le16(0);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	pr_info("Call usb_ep_queue");
+
+	ret = usb_ep_queue(dev->not_port.notify,
+			   dev->not_port.notify_req, GFP_ATOMIC);
+	if (ret) {
+		atomic_dec(&dev->not_port.notify_count);
+		pr_err("ep enqueue error %d\n", ret);
+	}
+
+	pr_info("Succcessfull Exit");
+}
+
+static int
+fmbim_send_cpkt_response(struct f_mbim *gr, struct ctrl_pkt *cpkt)
+{
+	struct f_mbim	*dev = gr;
+	unsigned long	flags;
+
+	if (!gr || !cpkt) {
+		pr_err("Invalid cpkt, dev:%p cpkt:%p\n",
+				gr, cpkt);
+		return -ENODEV;
+	}
+
+	pr_info("dev:%p port_num#%d\n", dev, dev->port_num);
+
+	if (!atomic_read(&dev->online)) {
+		pr_info("dev:%p is not connected\n", dev);
+		mbim_free_ctrl_pkt(cpkt);
+		return 0;
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+	list_add(&cpkt->list, &dev->cpkt_resp_q);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	fmbim_ctrl_response_available(dev);
+
+	return 0;
+}
+
+/* ---------------------------- BAM INTERFACE ----------------------------- */
+
+static int mbim_bam_setup(int no_ports)
+{
+	int ret;
+
+	pr_info("no_ports:%d\n", no_ports);
+
+	ret = bam_data_setup(no_ports);
+	if (ret) {
+		pr_err("bam_data_setup failed err: %d\n", ret);
+		return ret;
+	}
+
+	pr_info("Initialized %d ports\n", no_ports);
+	return 0;
+}
+
+static int mbim_bam_connect(struct f_mbim *dev)
+{
+	int ret;
+
+	pr_info("dev:%p portno:%d\n", dev, dev->port_num);
+
+	ret = bam_data_connect(&dev->bam_port, dev->port_num, dev->port_num);
+	if (ret) {
+		pr_err("bam_data_setup failed: err:%d\n",
+				ret);
+		return ret;
+	} else {
+		pr_info("mbim bam connected\n");
+	}
+
+	return 0;
+}
+
+static int mbim_bam_disconnect(struct f_mbim *dev)
+{
+	pr_info("dev:%p port:%d. Do nothing.\n",
+			dev, dev->port_num);
+
+	/* bam_data_disconnect(&dev->bam_port, dev->port_num); */
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------*/
+
+static inline void mbim_reset_values(struct f_mbim *mbim)
+{
+	mbim->parser_opts = &ndp16_opts;
+
+	mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
+
+	atomic_set(&mbim->not_port.notify_count, 0);
+	atomic_set(&mbim->online, 0);
+}
+
+/*
+ * Context: mbim->lock held
+ */
+static void mbim_do_notify(struct f_mbim *mbim)
+{
+	struct usb_request		*req = mbim->not_port.notify_req;
+	struct usb_cdc_notification	*event;
+	struct usb_composite_dev	*cdev = mbim->cdev;
+	__le32				*data;
+	int				status;
+
+	pr_info("notify_state: %d", mbim->not_port.notify_state);
+
+	if (!req)
+		return;
+
+	event = req->buf;
+
+	switch (mbim->not_port.notify_state) {
+
+	case NCM_NOTIFY_NONE:
+		return;
+
+	case NCM_NOTIFY_CONNECT:
+		event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
+		if (mbim->is_open)
+			event->wValue = cpu_to_le16(1);
+		else
+			event->wValue = cpu_to_le16(0);
+		event->wLength = 0;
+		req->length = sizeof *event;
+
+		pr_info("notify connect %s\n",
+			mbim->is_open ? "true" : "false");
+		mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+		break;
+
+	case NCM_NOTIFY_SPEED:
+		event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
+		event->wValue = cpu_to_le16(0);
+		event->wLength = cpu_to_le16(8);
+		req->length = NCM_STATUS_BYTECOUNT;
+
+		/* SPEED_CHANGE data is up/down speeds in bits/sec */
+		data = req->buf + sizeof *event;
+		data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
+		data[1] = data[0];
+
+		pr_info("notify speed %d\n",
+			mbim_bitrate(cdev->gadget));
+		mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
+		break;
+	}
+	event->bmRequestType = 0xA1;
+	event->wIndex = cpu_to_le16(mbim->ctrl_id);
+
+	mbim->not_port.notify_req = NULL;
+	/*
+	 * In double buffering if there is a space in FIFO,
+	 * completion callback can be called right after the call,
+	 * so unlocking
+	 */
+	spin_unlock(&mbim->lock);
+	status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
+	spin_lock(&mbim->lock);
+	if (status < 0) {
+		mbim->not_port.notify_req = req;
+		atomic_dec(&mbim->not_port.notify_count);
+		pr_err("usb_ep_queue failed, err: %d", status);
+	}
+}
+
+/*
+ * Context: mbim->lock held
+ */
+static void mbim_notify(struct f_mbim *mbim)
+{
+	/*
+	 * If mbim_notify() is called before the second (CONNECT)
+	 * notification is sent, then it will reset to send the SPEED
+	 * notificaion again (and again, and again), but it's not a problem
+	 */
+	pr_info("dev:%p\n", mbim);
+
+	mbim->not_port.notify_state = NCM_NOTIFY_SPEED;
+	mbim_do_notify(mbim);
+}
+
+static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_mbim			*mbim = req->context;
+	struct usb_cdc_notification	*event = req->buf;
+
+	int notif_c = 0;
+
+	pr_info("dev:%p\n", mbim);
+
+	spin_lock(&mbim->lock);
+	switch (req->status) {
+	case 0:
+		pr_info("Notification %02x sent\n",
+			event->bNotificationType);
+
+		notif_c = atomic_dec_return(&mbim->not_port.notify_count);
+
+		if (notif_c != 0) {
+			pr_info("Continue to mbim_do_notify()");
+			break;
+		} else {
+			pr_info("notify_count decreased to 0. Do not notify");
+			spin_unlock(&mbim->lock);
+			return;
+		}
+
+		break;
+
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* connection gone */
+		mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+		atomic_set(&mbim->not_port.notify_count, 0);
+		pr_info("ESHUTDOWN/ECONNRESET, connection gone");
+		break;
+	default:
+		pr_err("Unknown event %02x --> %d\n",
+			event->bNotificationType, req->status);
+		break;
+	}
+
+	mbim->not_port.notify_req = req;
+	mbim_do_notify(mbim);
+
+	spin_unlock(&mbim->lock);
+
+	pr_info("dev:%p Exit\n", mbim);
+}
+
+static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	/* now for SET_NTB_INPUT_SIZE only */
+	unsigned		in_size = 0;
+	struct usb_function	*f = req->context;
+	struct f_mbim		*mbim = func_to_mbim(f);
+	struct mbim_ntb_input_size *ntb = NULL;
+
+	pr_info("dev:%p\n", mbim);
+
+	req->context = NULL;
+	if (req->status || req->actual != req->length) {
+		pr_err("Bad control-OUT transfer\n");
+		goto invalid;
+	}
+
+	if (req->length == 4) {
+		in_size = get_unaligned_le32(req->buf);
+		if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
+		    in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+			pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
+			goto invalid;
+		}
+	} else if (req->length == 8) {
+		ntb = (struct mbim_ntb_input_size *)req->buf;
+		in_size = get_unaligned_le32(&(ntb->ntb_input_size));
+		if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
+		    in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+			pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
+			goto invalid;
+		}
+		mbim->ntb_max_datagrams =
+			get_unaligned_le16(&(ntb->ntb_max_datagrams));
+	} else {
+		pr_err("Illegal NTB length %d\n", in_size);
+		goto invalid;
+	}
+
+	pr_info("Set NTB INPUT SIZE %d\n", in_size);
+
+	mbim->ntb_input_size = in_size;
+	return;
+
+invalid:
+	usb_ep_set_halt(ep);
+
+	pr_err("dev:%p Failed\n", mbim);
+
+	return;
+}
+
+static void
+fmbim_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_mbim		*dev = req->context;
+	struct ctrl_pkt		*cpkt = NULL;
+	int			len = req->actual;
+
+	if (!dev) {
+		pr_err("mbim dev is null\n");
+		return;
+	}
+
+	if (req->status < 0) {
+		pr_err("mbim command error %d\n", req->status);
+		return;
+	}
+
+	pr_info("dev:%p port#%d\n", dev, dev->port_num);
+
+	spin_lock(&dev->lock);
+	if (!dev->is_open) {
+		pr_err("mbim file handler %p is not open", dev);
+		spin_unlock(&dev->lock);
+		return;
+	}
+
+	cpkt = mbim_alloc_ctrl_pkt(len, GFP_ATOMIC);
+	if (!cpkt) {
+		pr_err("Unable to allocate ctrl pkt\n");
+		spin_unlock(&dev->lock);
+		return;
+	}
+
+	pr_info("Add to cpkt_req_q packet with len = %d\n", len);
+	memcpy(cpkt->buf, req->buf, len);
+	list_add_tail(&cpkt->list, &dev->cpkt_req_q);
+	spin_unlock(&dev->lock);
+
+	/* wakeup read thread */
+	pr_info("Wake up read queue");
+	wake_up(&dev->read_wq);
+
+	return;
+}
+
+static int
+mbim_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct f_mbim			*mbim = func_to_mbim(f);
+	struct usb_composite_dev	*cdev = mbim->cdev;
+	struct usb_request		*req = cdev->req;
+	struct ctrl_pkt		*cpkt = NULL;
+	int	value = -EOPNOTSUPP;
+	u16	w_index = le16_to_cpu(ctrl->wIndex);
+	u16	w_value = le16_to_cpu(ctrl->wValue);
+	u16	w_length = le16_to_cpu(ctrl->wLength);
+
+	/*
+	 * composite driver infrastructure handles everything except
+	 * CDC class messages; interface activation uses set_alt().
+	 */
+
+	if (!atomic_read(&mbim->online)) {
+		pr_info("usb cable is not connected\n");
+		return -ENOTCONN;
+	}
+
+	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_RESET_FUNCTION:
+
+		pr_info("USB_CDC_RESET_FUNCTION");
+		value = 0;
+		if (!_mbim_dev->user_pid) {
+			pr_err("QBI pid is not set");
+			break;
+		}
+
+		if (!_mbim_dev->is_open) {
+			pr_err("QBI is not up yet");
+			break;
+		}
+
+		send_sig_info(SIGUSR1, SEND_SIG_NOINFO,
+			find_task_by_vpid(_mbim_dev->user_pid));
+
+		pr_info("Sent signal to QBI pid %d",
+			_mbim_dev->user_pid);
+		break;
+
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_SEND_ENCAPSULATED_COMMAND:
+
+		pr_info("USB_CDC_SEND_ENCAPSULATED_COMMAND");
+
+		if (w_length > req->length) {
+			pr_err("w_length > req->length: %d > %d",
+			w_length, req->length);
+		}
+		value = w_length;
+		req->complete = fmbim_cmd_complete;
+		req->context = mbim;
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_GET_ENCAPSULATED_RESPONSE:
+
+		pr_info("USB_CDC_GET_ENCAPSULATED_RESPONSE");
+
+		if (w_value) {
+			pr_err("w_length > 0: %d", w_length);
+			break;
+		}
+
+		pr_info("req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+
+		spin_lock(&mbim->lock);
+		if (list_empty(&mbim->cpkt_resp_q)) {
+			pr_err("ctrl resp queue empty\n");
+			spin_unlock(&mbim->lock);
+			break;
+		}
+
+		cpkt = list_first_entry(&mbim->cpkt_resp_q,
+					struct ctrl_pkt, list);
+		list_del(&cpkt->list);
+		spin_unlock(&mbim->lock);
+
+		value = min_t(unsigned, w_length, cpkt->len);
+		memcpy(req->buf, cpkt->buf, value);
+		mbim_free_ctrl_pkt(cpkt);
+
+		pr_info("copied encapsulated_response %d bytes",
+			value);
+
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_GET_NTB_PARAMETERS:
+
+		pr_info("USB_CDC_GET_NTB_PARAMETERS");
+
+		if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
+			break;
+
+		value = w_length > sizeof ntb_parameters ?
+			sizeof ntb_parameters : w_length;
+		memcpy(req->buf, &ntb_parameters, value);
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_GET_NTB_INPUT_SIZE:
+
+		pr_info("USB_CDC_GET_NTB_INPUT_SIZE");
+
+		if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
+			break;
+
+		put_unaligned_le32(mbim->ntb_input_size, req->buf);
+		value = 4;
+		pr_info("Reply to host INPUT SIZE %d\n",
+		     mbim->ntb_input_size);
+		break;
+
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_SET_NTB_INPUT_SIZE:
+
+		pr_info("USB_CDC_SET_NTB_INPUT_SIZE");
+
+		if (w_length != 4 && w_length != 8) {
+			pr_err("wrong NTB length %d", w_length);
+			break;
+		}
+
+		if (w_value != 0 || w_index != mbim->ctrl_id)
+			break;
+
+		req->complete = mbim_ep0out_complete;
+		req->length = w_length;
+		req->context = f;
+
+		value = req->length;
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_GET_NTB_FORMAT:
+	{
+		uint16_t format;
+
+		pr_info("USB_CDC_GET_NTB_FORMAT");
+
+		if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
+			break;
+
+		format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
+		put_unaligned_le16(format, req->buf);
+		value = 2;
+		pr_info("NTB FORMAT: sending %d\n", format);
+		break;
+	}
+
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+		| USB_CDC_SET_NTB_FORMAT:
+	{
+		pr_info("USB_CDC_SET_NTB_FORMAT");
+
+		if (w_length != 0 || w_index != mbim->ctrl_id)
+			break;
+		switch (w_value) {
+		case 0x0000:
+			mbim->parser_opts = &ndp16_opts;
+			pr_info("NCM16 selected\n");
+			break;
+		case 0x0001:
+			mbim->parser_opts = &ndp32_opts;
+			pr_info("NCM32 selected\n");
+			break;
+		default:
+			break;
+		}
+		value = 0;
+		break;
+	}
+
+	/* optional in mbim descriptor: */
+	/* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
+	/* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
+
+	default:
+	pr_err("invalid control req: %02x.%02x v%04x i%04x l%d\n",
+		ctrl->bRequestType, ctrl->bRequest,
+		w_value, w_index, w_length);
+	}
+
+	 /* respond with data transfer or status phase? */
+	if (value >= 0) {
+		pr_info("control request: %02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+		req->zero = 0;
+		req->length = value;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0) {
+			pr_err("queueing req failed: %02x.%02x, err %d\n",
+				ctrl->bRequestType,
+			       ctrl->bRequest, value);
+		}
+	} else {
+		pr_err("ctrl req err %d: %02x.%02x v%04x i%04x l%d\n",
+			value, ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+	}
+
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
+
+static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_mbim		*mbim = func_to_mbim(f);
+	struct usb_composite_dev *cdev = mbim->cdev;
+	int ret = 0;
+
+	/* Control interface has only altsetting 0 */
+	if (intf == mbim->ctrl_id) {
+
+		pr_info("CONTROL_INTERFACE");
+
+		if (alt != 0)
+			goto fail;
+
+		if (mbim->not_port.notify->driver_data) {
+			pr_info("reset mbim control %d\n", intf);
+			usb_ep_disable(mbim->not_port.notify);
+		}
+
+		ret = config_ep_by_speed(cdev->gadget, f,
+					mbim->not_port.notify);
+		if (ret) {
+			mbim->not_port.notify->desc = NULL;
+			pr_err("Failed configuring notify ep %s: err %d\n",
+				mbim->not_port.notify->name, ret);
+			return ret;
+		}
+
+		ret = usb_ep_enable(mbim->not_port.notify);
+		if (ret) {
+			pr_err("usb ep#%s enable failed, err#%d\n",
+				mbim->not_port.notify->name, ret);
+			return ret;
+		}
+		mbim->not_port.notify->driver_data = mbim;
+
+	/* Data interface has two altsettings, 0 and 1 */
+	} else if (intf == mbim->data_id) {
+
+		pr_info("DATA_INTERFACE");
+
+		if (alt > 1)
+			goto fail;
+
+		if (mbim->bam_port.in->driver_data) {
+			pr_info("reset mbim\n");
+			mbim_reset_values(mbim);
+			mbim_bam_disconnect(mbim);
+		}
+
+		/*
+		 * CDC Network only sends data in non-default altsettings.
+		 * Changing altsettings resets filters, statistics, etc.
+		 */
+		if (alt == 1) {
+			pr_info("Alt set 1, initialize ports");
+
+			if (!mbim->bam_port.in->desc) {
+
+				pr_info("Choose endpoints");
+
+				ret = config_ep_by_speed(cdev->gadget, f,
+							mbim->bam_port.in);
+				if (ret) {
+					mbim->bam_port.in->desc = NULL;
+					pr_err("IN ep %s failed: %d\n",
+					mbim->bam_port.in->name, ret);
+					return ret;
+				}
+
+				pr_info("Set mbim port in_desc = 0x%p",
+					mbim->bam_port.in->desc);
+
+				ret = config_ep_by_speed(cdev->gadget, f,
+							mbim->bam_port.out);
+				if (ret) {
+					mbim->bam_port.out->desc = NULL;
+					pr_err("OUT ep %s failed: %d\n",
+					mbim->bam_port.out->name, ret);
+					return ret;
+				}
+
+				pr_info("Set mbim port out_desc = 0x%p",
+					mbim->bam_port.out->desc);
+			} else {
+				pr_info("PORTS already SET");
+			}
+
+			pr_info("Activate mbim\n");
+			mbim_bam_connect(mbim);
+		}
+
+		spin_lock(&mbim->lock);
+		mbim_notify(mbim);
+		spin_unlock(&mbim->lock);
+	} else {
+		goto fail;
+	}
+
+	atomic_set(&mbim->online, 1);
+
+	pr_info("SET DEVICE ONLINE");
+
+	/* wakeup file threads */
+	wake_up(&mbim->read_wq);
+	wake_up(&mbim->write_wq);
+
+	return 0;
+
+fail:
+	pr_err("ERROR: Illegal Interface");
+	return -EINVAL;
+}
+
+/*
+ * Because the data interface supports multiple altsettings,
+ * this MBIM function *MUST* implement a get_alt() method.
+ */
+static int mbim_get_alt(struct usb_function *f, unsigned intf)
+{
+	struct f_mbim	*mbim = func_to_mbim(f);
+
+	if (intf == mbim->ctrl_id)
+		return 0;
+	return mbim->bam_port.in->driver_data ? 1 : 0;
+}
+
+static void mbim_disable(struct usb_function *f)
+{
+	struct f_mbim	*mbim = func_to_mbim(f);
+
+	pr_info("SET DEVICE OFFLINE");
+	atomic_set(&mbim->online, 0);
+
+	if (_mbim_dev && _mbim_dev->user_pid && _mbim_dev->is_open) {
+		send_sig_info(SIGUSR1, SEND_SIG_NOINFO,
+			find_task_by_vpid(_mbim_dev->user_pid));
+		pr_info("Sending reset signal to QBI pid %d",
+			_mbim_dev->user_pid);
+	}
+
+	mbim_bam_disconnect(mbim);
+
+	if (mbim->not_port.notify->driver_data) {
+		usb_ep_disable(mbim->not_port.notify);
+		mbim->not_port.notify->driver_data = NULL;
+	}
+
+	pr_info("mbim deactivated\n");
+}
+
+/*---------------------- function driver setup/binding ---------------------*/
+
+static int
+mbim_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct f_mbim		*mbim = func_to_mbim(f);
+	int			status;
+	struct usb_ep		*ep;
+
+	pr_info("Enter");
+
+	mbim->cdev = cdev;
+
+	/* allocate instance-specific interface IDs */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	mbim->ctrl_id = status;
+	mbim_iad_desc.bFirstInterface = status;
+
+	mbim_control_intf.bInterfaceNumber = status;
+	mbim_union_desc.bMasterInterface0 = status;
+
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	mbim->data_id = status;
+
+	mbim_data_nop_intf.bInterfaceNumber = status;
+	mbim_data_intf.bInterfaceNumber = status;
+	mbim_union_desc.bSlaveInterface0 = status;
+
+	status = -ENODEV;
+
+	/* allocate instance-specific endpoints */
+	ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_in_desc);
+	if (!ep) {
+		pr_err("usb epin autoconfig failed\n");
+		goto fail;
+	}
+	pr_info("usb epin autoconfig succeeded\n");
+	ep->driver_data = cdev;	/* claim */
+	mbim->bam_port.in = ep;
+
+	ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_out_desc);
+	if (!ep) {
+		pr_err("usb epout autoconfig failed\n");
+		goto fail;
+	}
+	pr_info("usb epout autoconfig succeeded\n");
+	ep->driver_data = cdev;	/* claim */
+	mbim->bam_port.out = ep;
+
+	ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_notify_desc);
+	if (!ep) {
+		pr_err("usb notify ep autoconfig failed\n");
+		goto fail;
+	}
+	pr_info("usb notify ep autoconfig succeeded\n");
+	mbim->not_port.notify = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	status = -ENOMEM;
+
+	/* allocate notification request and buffer */
+	mbim->not_port.notify_req = mbim_alloc_req(ep, NCM_STATUS_BYTECOUNT);
+	if (!mbim->not_port.notify_req) {
+		pr_info("failed to allocate notify request\n");
+		goto fail;
+	}
+	pr_info("allocated notify ep request & request buffer\n");
+
+	mbim->not_port.notify_req->context = mbim;
+	mbim->not_port.notify_req->complete = mbim_notify_complete;
+
+	/* copy descriptors, and track endpoint copies */
+	f->descriptors = usb_copy_descriptors(mbim_fs_function);
+	if (!f->descriptors)
+		goto fail;
+
+	/*
+	 * support all relevant hardware speeds... we expect that when
+	 * hardware is dual speed, all bulk-capable endpoints work at
+	 * both speeds
+	 */
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		hs_mbim_in_desc.bEndpointAddress =
+				fs_mbim_in_desc.bEndpointAddress;
+		hs_mbim_out_desc.bEndpointAddress =
+				fs_mbim_out_desc.bEndpointAddress;
+		hs_mbim_notify_desc.bEndpointAddress =
+				fs_mbim_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->hs_descriptors = usb_copy_descriptors(mbim_hs_function);
+		if (!f->hs_descriptors)
+			goto fail;
+	}
+
+	pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
+			mbim->port_num,
+			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+			mbim->bam_port.in->name, mbim->bam_port.out->name,
+			mbim->not_port.notify->name);
+
+	return 0;
+
+fail:
+	pr_err("%s failed to bind, err %d\n", f->name, status);
+
+	if (f->descriptors)
+		usb_free_descriptors(f->descriptors);
+
+	if (mbim->not_port.notify_req) {
+		kfree(mbim->not_port.notify_req->buf);
+		usb_ep_free_request(mbim->not_port.notify,
+				    mbim->not_port.notify_req);
+	}
+
+	/* we might as well release our claims on endpoints */
+	if (mbim->not_port.notify)
+		mbim->not_port.notify->driver_data = NULL;
+	if (mbim->bam_port.out)
+		mbim->bam_port.out->driver_data = NULL;
+	if (mbim->bam_port.in)
+		mbim->bam_port.in->driver_data = NULL;
+
+	return status;
+}
+
+static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_mbim	*mbim = func_to_mbim(f);
+
+	if (gadget_is_dualspeed(c->cdev->gadget))
+		usb_free_descriptors(f->hs_descriptors);
+	usb_free_descriptors(f->descriptors);
+
+	kfree(mbim->not_port.notify_req->buf);
+	usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
+}
+
+/**
+ * mbim_bind_config - add MBIM link to a configuration
+ * @c: the configuration to support the network link
+ * Context: single threaded during gadget setup
+ * Returns zero on success, else negative errno.
+ */
+int mbim_bind_config(struct usb_configuration *c, unsigned portno)
+{
+	struct f_mbim	*mbim = NULL;
+	int status = 0;
+
+	pr_info("port number %u", portno);
+
+	if (portno >= nr_mbim_ports) {
+		pr_err("Can not add port %u. Max ports = %d",
+		       portno, nr_mbim_ports);
+		return -ENODEV;
+	}
+
+	status = mbim_bam_setup(nr_mbim_ports);
+	if (status) {
+		pr_err("bam setup failed");
+		return status;
+	}
+
+	/* maybe allocate device-global string IDs */
+	if (mbim_string_defs[0].id == 0) {
+
+		/* control interface label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		mbim_string_defs[STRING_CTRL_IDX].id = status;
+		mbim_control_intf.iInterface = status;
+
+		/* data interface label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		mbim_string_defs[STRING_DATA_IDX].id = status;
+		mbim_data_nop_intf.iInterface = status;
+		mbim_data_intf.iInterface = status;
+	}
+
+	/* allocate and initialize one new instance */
+	mbim = mbim_ports[0].port;
+	if (!mbim) {
+		pr_info("mbim struct not allocated");
+		return -ENOMEM;
+	}
+
+	mbim->cdev = c->cdev;
+
+	spin_lock_init(&mbim->lock);
+
+	mbim_reset_values(mbim);
+
+	mbim->function.name = "usb_mbim";
+	mbim->function.strings = mbim_strings;
+	mbim->function.bind = mbim_bind;
+	mbim->function.unbind = mbim_unbind;
+	mbim->function.set_alt = mbim_set_alt;
+	mbim->function.get_alt = mbim_get_alt;
+	mbim->function.setup = mbim_setup;
+	mbim->function.disable = mbim_disable;
+
+	INIT_LIST_HEAD(&mbim->cpkt_req_q);
+	INIT_LIST_HEAD(&mbim->cpkt_resp_q);
+
+	status = usb_add_function(c, &mbim->function);
+
+	pr_info("Exit status %d", status);
+
+	return status;
+}
+
+/* ------------ MBIM DRIVER File Operations API for USER SPACE ------------ */
+
+static ssize_t
+mbim_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
+{
+	struct f_mbim *dev = fp->private_data;
+	struct ctrl_pkt *cpkt = NULL;
+	int ret = 0;
+
+	pr_debug("Enter(%d)\n", count);
+
+	if (!dev) {
+		pr_err("Received NULL mbim pointer\n");
+		return -ENODEV;
+	}
+
+	if (count > MBIM_BULK_BUFFER_SIZE) {
+		pr_err("Buffer size is too big %d, should be at most %d\n",
+			count, MBIM_BULK_BUFFER_SIZE);
+		return -EINVAL;
+	}
+
+	if (mbim_lock(&dev->read_excl)) {
+		pr_err("Previous reading is not finished yet\n");
+		return -EBUSY;
+	}
+
+	/* block until mbim online */
+	while (!(atomic_read(&dev->online) || atomic_read(&dev->error))) {
+		pr_err("USB cable not connected. Wait.\n");
+		ret = wait_event_interruptible(dev->read_wq,
+			(atomic_read(&dev->online) ||
+			atomic_read(&dev->error)));
+		if (ret < 0) {
+			mbim_unlock(&dev->read_excl);
+			return 0;
+		}
+	}
+
+	if (atomic_read(&dev->error)) {
+		mbim_unlock(&dev->read_excl);
+		return -EIO;
+	}
+
+	while (list_empty(&dev->cpkt_req_q)) {
+		pr_err("Requests list is empty. Wait.\n");
+		ret = wait_event_interruptible(dev->read_wq,
+			!list_empty(&dev->cpkt_req_q));
+		if (ret < 0) {
+			pr_err("Waiting failed\n");
+			mbim_unlock(&dev->read_excl);
+			return 0;
+		}
+		pr_debug("Received request packet\n");
+	}
+
+	cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
+							list);
+	if (cpkt->len > count) {
+		mbim_unlock(&dev->read_excl);
+		pr_err("cpkt size too big:%d > buf size:%d\n",
+				cpkt->len, count);
+		return -ENOMEM;
+	}
+
+	pr_debug("cpkt size:%d\n", cpkt->len);
+
+	list_del(&cpkt->list);
+	mbim_unlock(&dev->read_excl);
+
+	ret = copy_to_user(buf, cpkt->buf, cpkt->len);
+	if (ret) {
+		pr_err("copy_to_user failed: err %d\n", ret);
+		ret = 0;
+	} else {
+		pr_debug("copied %d bytes to user\n", cpkt->len);
+		ret = cpkt->len;
+	}
+
+	mbim_free_ctrl_pkt(cpkt);
+
+	return ret;
+}
+
+static ssize_t
+mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
+{
+	struct f_mbim *dev = fp->private_data;
+	struct ctrl_pkt *cpkt = NULL;
+	int ret = 0;
+
+	pr_debug("Enter(%d)", count);
+
+	if (!dev) {
+		pr_err("Received NULL mbim pointer\n");
+		return -ENODEV;
+	}
+
+	if (!count) {
+		pr_err("zero length ctrl pkt\n");
+		return -ENODEV;
+	}
+
+	if (count > MAX_CTRL_PKT_SIZE) {
+		pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
+				count, MAX_CTRL_PKT_SIZE);
+		return -ENOMEM;
+	}
+
+	if (mbim_lock(&dev->write_excl)) {
+		pr_err("Previous writing not finished yet\n");
+		return -EBUSY;
+	}
+
+	if (!atomic_read(&dev->online)) {
+		pr_err("USB cable not connected\n");
+		mbim_unlock(&dev->write_excl);
+		return -EPIPE;
+	}
+
+	cpkt = mbim_alloc_ctrl_pkt(count, GFP_KERNEL);
+	if (!cpkt) {
+		pr_err("failed to allocate ctrl pkt\n");
+		mbim_unlock(&dev->write_excl);
+		return -ENOMEM;
+	}
+
+	ret = copy_from_user(cpkt->buf, buf, count);
+	if (ret) {
+		pr_err("copy_from_user failed err:%d\n", ret);
+		mbim_free_ctrl_pkt(cpkt);
+		mbim_unlock(&dev->write_excl);
+		return 0;
+	}
+
+	fmbim_send_cpkt_response(dev, cpkt);
+
+	mbim_unlock(&dev->write_excl);
+
+	pr_debug("Exit(%d)", count);
+
+	return count;
+}
+
+static int mbim_open(struct inode *ip, struct file *fp)
+{
+	pr_info("Open mbim driver\n");
+
+	while (!_mbim_dev) {
+		pr_err("mbim_dev not created yet\n");
+		return -ENODEV;
+	}
+
+	if (mbim_lock(&_mbim_dev->open_excl)) {
+		pr_err("Already opened\n");
+		return -EBUSY;
+	}
+
+	pr_info("Lock mbim_dev->open_excl for open\n");
+
+	if (!atomic_read(&_mbim_dev->online))
+		pr_err("USB cable not connected\n");
+
+	pr_info("Set QBI pid %d\n", pid_nr(task_pid(current)));
+	_mbim_dev->user_pid = pid_nr(task_pid(current));
+
+	fp->private_data = _mbim_dev;
+
+	atomic_set(&_mbim_dev->error, 0);
+
+	spin_lock(&_mbim_dev->lock);
+	_mbim_dev->is_open = true;
+	mbim_notify(_mbim_dev);
+	spin_unlock(&_mbim_dev->lock);
+
+	pr_info("Exit, mbim file opened\n");
+
+	return 0;
+}
+
+static int mbim_release(struct inode *ip, struct file *fp)
+{
+	struct f_mbim *mbim = fp->private_data;
+
+	pr_info("Close mbim file");
+
+	spin_lock(&mbim->lock);
+	mbim->is_open = false;
+	mbim_notify(mbim);
+	spin_unlock(&mbim->lock);
+
+	mbim->user_pid = 0;
+
+	mbim_unlock(&_mbim_dev->open_excl);
+
+	return 0;
+}
+
+static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
+{
+	struct f_mbim *mbim = fp->private_data;
+	int ret = 0;
+
+	pr_info("Received command %d", cmd);
+
+	if (mbim_lock(&mbim->ioctl_excl))
+		return -EBUSY;
+
+	switch (cmd) {
+	case MBIM_GET_NTB_SIZE:
+		ret = copy_to_user((void __user *)arg,
+			&mbim->ntb_input_size, sizeof(mbim->ntb_input_size));
+		if (ret) {
+			pr_err("copying to user space failed");
+			ret = -EFAULT;
+		}
+		pr_info("Sent NTB size %d", mbim->ntb_input_size);
+		break;
+	case MBIM_GET_DATAGRAM_COUNT:
+		ret = copy_to_user((void __user *)arg,
+			&mbim->ntb_max_datagrams,
+			sizeof(mbim->ntb_max_datagrams));
+		if (ret) {
+			pr_err("copying to user space failed");
+			ret = -EFAULT;
+		}
+		pr_info("Sent NTB datagrams count %d",
+			mbim->ntb_max_datagrams);
+		break;
+	default:
+		pr_err("wrong parameter");
+		ret = -EINVAL;
+	}
+
+	mbim_unlock(&mbim->ioctl_excl);
+
+	return ret;
+}
+
+/* file operations for MBIM device /dev/android_mbim */
+static const struct file_operations mbim_fops = {
+	.owner = THIS_MODULE,
+	.open = mbim_open,
+	.release = mbim_release,
+	.read = mbim_read,
+	.write = mbim_write,
+	.unlocked_ioctl	= mbim_ioctl,
+};
+
+static struct miscdevice mbim_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "android_mbim",
+	.fops = &mbim_fops,
+};
+
+static int mbim_init(int instances)
+{
+	int i;
+	struct f_mbim *dev = NULL;
+	int ret;
+
+	pr_info("initialize %d instances\n", instances);
+
+	if (instances > NR_MBIM_PORTS) {
+		pr_err("Max-%d instances supported\n", NR_MBIM_PORTS);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < instances; i++) {
+		dev = kzalloc(sizeof(struct f_mbim), GFP_KERNEL);
+		if (!dev) {
+			pr_err("Failed to allocate mbim dev\n");
+			ret = -ENOMEM;
+			goto fail_probe;
+		}
+
+		dev->port_num = i;
+		spin_lock_init(&dev->lock);
+		INIT_LIST_HEAD(&dev->cpkt_req_q);
+		INIT_LIST_HEAD(&dev->cpkt_resp_q);
+
+		mbim_ports[i].port = dev;
+		mbim_ports[i].port_num = i;
+
+		init_waitqueue_head(&dev->read_wq);
+		init_waitqueue_head(&dev->write_wq);
+
+		atomic_set(&dev->open_excl, 0);
+		atomic_set(&dev->ioctl_excl, 0);
+		atomic_set(&dev->read_excl, 0);
+		atomic_set(&dev->write_excl, 0);
+
+		nr_mbim_ports++;
+
+	}
+
+	_mbim_dev = dev;
+	ret = misc_register(&mbim_device);
+	if (ret) {
+		pr_err("mbim driver failed to register");
+		goto fail_probe;
+	}
+
+	pr_info("Initialized %d ports\n", nr_mbim_ports);
+
+	return ret;
+
+fail_probe:
+	pr_err("Failed");
+	for (i = 0; i < nr_mbim_ports; i++) {
+		kfree(mbim_ports[i].port);
+		mbim_ports[i].port = NULL;
+	}
+
+	return ret;
+}
+
+static void fmbim_cleanup(void)
+{
+	int i = 0;
+
+	pr_info("Enter");
+
+	for (i = 0; i < nr_mbim_ports; i++) {
+		kfree(mbim_ports[i].port);
+		mbim_ports[i].port = NULL;
+	}
+	nr_mbim_ports = 0;
+
+	misc_deregister(&mbim_device);
+
+	_mbim_dev = NULL;
+}
+
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 2829231..0e619e6 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");
@@ -504,7 +495,17 @@
 	}
 
 	/* wait for a request to complete */
-	ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
+	ret = wait_event_interruptible(dev->read_wq,
+				dev->rx_done || dev->state != STATE_BUSY);
+	if (dev->state == STATE_CANCELED) {
+		r = -ECANCELED;
+		if (!dev->rx_done)
+			usb_ep_dequeue(dev->ep_out, req);
+		spin_lock_irq(&dev->lock);
+		dev->state = STATE_CANCELED;
+		spin_unlock_irq(&dev->lock);
+		goto done;
+	}
 	if (ret < 0) {
 		r = ret;
 		usb_ep_dequeue(dev->ep_out, req);
@@ -1132,21 +1133,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..c7a20aa 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);
@@ -755,8 +734,6 @@
 	rndis_deregister(rndis->config);
 	rndis_exit();
 
-	rndis_string_defs[0].id = 0;
-
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
@@ -796,14 +773,14 @@
 	if (!can_support_rndis(c) || !ethaddr)
 		return -EINVAL;
 
+	/* setup RNDIS itself */
+	status = rndis_init();
+	if (status < 0)
+		return status;
+
 	/* maybe allocate device-global string IDs */
 	if (rndis_string_defs[0].id == 0) {
 
-		/* ... and setup RNDIS itself */
-		status = rndis_init();
-		if (status < 0)
-			return status;
-
 		/* control interface label */
 		status = usb_string_id(c->cdev);
 		if (status < 0)
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..8a97a6e 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -15,163 +15,43 @@
 #ifndef __GADGET_CHIPS_H
 #define __GADGET_CHIPS_H
 
-#ifdef CONFIG_USB_GADGET_NET2280
-#define	gadget_is_net2280(g)	!strcmp("net2280", (g)->name)
-#else
-#define	gadget_is_net2280(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_AMD5536UDC
-#define	gadget_is_amd5536udc(g)	!strcmp("amd5536udc", (g)->name)
-#else
-#define	gadget_is_amd5536udc(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_DUMMY_HCD
-#define	gadget_is_dummy(g)	!strcmp("dummy_udc", (g)->name)
-#else
-#define	gadget_is_dummy(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_PXA25X
-#define	gadget_is_pxa(g)	!strcmp("pxa25x_udc", (g)->name)
-#else
-#define	gadget_is_pxa(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_GOKU
-#define	gadget_is_goku(g)	!strcmp("goku_udc", (g)->name)
-#else
-#define	gadget_is_goku(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_OMAP
-#define	gadget_is_omap(g)	!strcmp("omap_udc", (g)->name)
-#else
-#define	gadget_is_omap(g)	0
-#endif
-
-/* various unstable versions available */
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name)
-#else
-#define	gadget_is_pxa27x(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_ATMEL_USBA
-#define gadget_is_atmel_usba(g)	!strcmp("atmel_usba_udc", (g)->name)
-#else
-#define gadget_is_atmel_usba(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
-#else
-#define gadget_is_s3c2410(g)    0
-#endif
-
-#ifdef CONFIG_USB_GADGET_AT91
-#define gadget_is_at91(g)	!strcmp("at91_udc", (g)->name)
-#else
-#define gadget_is_at91(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_IMX
-#define gadget_is_imx(g)	!strcmp("imx_udc", (g)->name)
-#else
-#define gadget_is_imx(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_FSL_USB2
-#define gadget_is_fsl_usb2(g)	!strcmp("fsl-usb2-udc", (g)->name)
-#else
-#define gadget_is_fsl_usb2(g)	0
-#endif
-
-/* Mentor high speed "dual role" controller, in peripheral role */
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-#define gadget_is_musbhdrc(g)	!strcmp("musb-hdrc", (g)->name)
-#else
-#define gadget_is_musbhdrc(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_LANGWELL
-#define gadget_is_langwell(g)	(!strcmp("langwell_udc", (g)->name))
-#else
-#define gadget_is_langwell(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_M66592
-#define	gadget_is_m66592(g)	!strcmp("m66592_udc", (g)->name)
-#else
-#define	gadget_is_m66592(g)	0
-#endif
-
-/* Freescale CPM/QE UDC SUPPORT */
-#ifdef CONFIG_USB_GADGET_FSL_QE
-#define gadget_is_fsl_qe(g)	!strcmp("fsl_qe_udc", (g)->name)
-#else
-#define gadget_is_fsl_qe(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_CI13XXX_PCI
-#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name))
-#else
-#define gadget_is_ci13xxx_pci(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_MSM_72K
-#define	gadget_is_msm72k(g)	!strcmp("msm72k_udc", (g)->name)
-#else
-#define	gadget_is_msm72k(g)	0
-#endif
-
-// CONFIG_USB_GADGET_SX2
-// CONFIG_USB_GADGET_AU1X00
-// ...
-
-#ifdef CONFIG_USB_GADGET_R8A66597
-#define	gadget_is_r8a66597(g)	!strcmp("r8a66597_udc", (g)->name)
-#else
-#define	gadget_is_r8a66597(g)	0
-#endif
-
-#ifdef CONFIG_USB_S3C_HSOTG
-#define gadget_is_s3c_hsotg(g)    (!strcmp("s3c-hsotg", (g)->name))
-#else
-#define gadget_is_s3c_hsotg(g)    0
-#endif
-
-#ifdef CONFIG_USB_S3C_HSUDC
-#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
-#else
-#define gadget_is_s3c_hsudc(g) 0
-#endif
-
-#ifdef CONFIG_USB_GADGET_EG20T
-#define	gadget_is_pch(g)	(!strcmp("pch_udc", (g)->name))
-#else
-#define	gadget_is_pch(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_CI13XXX_MSM
+/*
+ * NOTICE: the entries below are alphabetical and should be kept
+ * that way.
+ *
+ * Always be sure to add new entries to the correct position or
+ * accept the bashing later.
+ *
+ * If you have forgotten the alphabetical order let VIM/EMACS
+ * do that for you.
+ */
+#define gadget_is_amd5536udc(g)	(!strcmp("amd5536udc", (g)->name))
+#define gadget_is_at91(g)		(!strcmp("at91_udc", (g)->name))
+#define gadget_is_atmel_usba(g)	(!strcmp("atmel_usba_udc", (g)->name))
 #define gadget_is_ci13xxx_msm(g)	(!strcmp("ci13xxx_msm", (g)->name))
-#else
-#define gadget_is_ci13xxx_msm(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_CI13XXX_MSM_HSIC
-#define gadget_is_ci13xxx_msm_hsic(g)	\
-		(!strncmp("ci13xxx_msm_hsic", (g)->name, 16))
-#else
-#define gadget_is_ci13xxx_msm_hsic(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_RENESAS_USBHS
-#define	gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
-#else
-#define	gadget_is_renesas_usbhs(g) 0
-#endif
+#define gadget_is_ci13xxx_msm_hsic(g)	(!strcmp("ci13xxx_msm_hsic", (g)->name))
+#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name))
+#define gadget_is_dummy(g)		(!strcmp("dummy_udc", (g)->name))
+#define gadget_is_dwc3(g)		(!strcmp("dwc3-gadget", (g)->name))
+#define gadget_is_fsl_qe(g)		(!strcmp("fsl_qe_udc", (g)->name))
+#define gadget_is_fsl_usb2(g)		(!strcmp("fsl-usb2-udc", (g)->name))
+#define gadget_is_goku(g)		(!strcmp("goku_udc", (g)->name))
+#define gadget_is_imx(g)		(!strcmp("imx_udc", (g)->name))
+#define gadget_is_langwell(g)		(!strcmp("langwell_udc", (g)->name))
+#define gadget_is_m66592(g)		(!strcmp("m66592_udc", (g)->name))
+#define gadget_is_msm72k(g)		(!strcmp("msm72k_udc", (g)->name))
+#define gadget_is_musbhdrc(g)		(!strcmp("musb-hdrc", (g)->name))
+#define gadget_is_net2272(g)		(!strcmp("net2272", (g)->name))
+#define gadget_is_net2280(g)		(!strcmp("net2280", (g)->name))
+#define gadget_is_omap(g)		(!strcmp("omap_udc", (g)->name))
+#define gadget_is_pch(g)		(!strcmp("pch_udc", (g)->name))
+#define gadget_is_pxa(g)		(!strcmp("pxa25x_udc", (g)->name))
+#define gadget_is_pxa27x(g)		(!strcmp("pxa27x_udc", (g)->name))
+#define gadget_is_r8a66597(g)		(!strcmp("r8a66597_udc", (g)->name))
+#define gadget_is_renesas_usbhs(g)	(!strcmp("renesas_usbhs_udc", (g)->name))
+#define gadget_is_s3c2410(g)		(!strcmp("s3c2410_udc", (g)->name))
+#define gadget_is_s3c_hsotg(g)		(!strcmp("s3c-hsotg", (g)->name))
+#define gadget_is_s3c_hsudc(g)		(!strcmp("s3c-hsudc", (g)->name))
 
 /**
  * usb_gadget_controller_number - support bcdDevice id convention
@@ -240,6 +120,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..e0fc12c 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -2,7 +2,7 @@
  * Driver for HighSpeed USB Client Controller in MSM7K
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  * Author: Mike Lockwood <lockwood@android.com>
  *         Brian Swetland <swetland@google.com>
  *
@@ -1109,7 +1109,6 @@
 	struct msm_endpoint *ept = ui->ept + bit;
 	struct msm_request *req;
 	unsigned long flags;
-	int req_dequeue = 1;
 	unsigned info;
 
 	/*
@@ -1129,23 +1128,12 @@
 			break;
 		}
 
-dequeue:
 		/* clean speculative fetches on req->item->info */
 		dma_coherent_post_ops();
 		info = req->item->info;
 		/* if the transaction is still in-flight, stop here */
-		if (info & INFO_ACTIVE) {
-			if (req_dequeue) {
-				req_dequeue = 0;
-				ui->dTD_update_fail_count++;
-				ept->dTD_update_fail_count++;
-				udelay(10);
-				goto dequeue;
-			} else {
-				break;
-			}
-		}
-		req_dequeue = 0;
+		if (info & INFO_ACTIVE)
+			break;
 
 		del_timer(&ept->prime_timer);
 		/* advance ept queue to the next request */
@@ -1453,7 +1441,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 +2376,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 +2388,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 +2583,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 +2631,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 +2717,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 +2755,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 +2781,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 55ca63a..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..6f2c79d4 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) {
@@ -1602,7 +1608,7 @@
 	if (status)
 		ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
 
-	unregister_chrdev_region(g_printer_devno, 2);
+	unregister_chrdev_region(g_printer_devno, 1);
 	class_destroy(usb_gadget_class);
 	mutex_unlock(&usb_printer_gadget.lock_printer_io);
 }
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/rndis.c b/drivers/usb/gadget/rndis.c
index 6cea2e1..bbfbde7 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -159,25 +159,6 @@
 #endif	/* RNDIS_PM */
 };
 
-/* HACK: copied from net/core/dev.c to replace dev_get_stats since
- * dev_get_stats cannot be called from atomic context */
-static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
-				    const struct net_device_stats *netdev_stats)
-{
-#if BITS_PER_LONG == 64
-	BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats));
-	memcpy(stats64, netdev_stats, sizeof(*stats64));
-#else
-	size_t i, n = sizeof(*stats64) / sizeof(u64);
-	const unsigned long *src = (const unsigned long *)netdev_stats;
-	u64 *dst = (u64 *)stats64;
-
-	BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) !=
-		     sizeof(*stats64) / sizeof(u64));
-	for (i = 0; i < n; i++)
-		dst[i] = src[i];
-#endif
-}
 
 /* NDIS Functions */
 static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
@@ -190,7 +171,7 @@
 	rndis_query_cmplt_type *resp;
 	struct net_device *net;
 	struct rtnl_link_stats64 temp;
-	struct rtnl_link_stats64 *stats = &temp;
+	const struct rtnl_link_stats64 *stats;
 
 	if (!r) return -ENOMEM;
 	resp = (rndis_query_cmplt_type *)r->buf;
@@ -213,7 +194,7 @@
 	resp->InformationBufferOffset = cpu_to_le32(16);
 
 	net = rndis_per_dev_params[configNr].dev;
-	netdev_stats_to_stats64(stats, &net->stats);
+	stats = dev_get_stats(net, &temp);
 
 	switch (OID) {
 
@@ -1166,11 +1147,15 @@
 
 #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
+static bool rndis_initialized;
 
 int rndis_init(void)
 {
 	u8 i;
 
+	if (rndis_initialized)
+		return 0;
+
 	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
 #ifdef	CONFIG_USB_GADGET_DEBUG_FILES
 		char name [20];
@@ -1197,6 +1182,7 @@
 		INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
 	}
 
+	rndis_initialized = true;
 	return 0;
 }
 
@@ -1205,7 +1191,13 @@
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 	u8 i;
 	char name[20];
+#endif
 
+	if (!rndis_initialized)
+		return;
+	rndis_initialized = false;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
 	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
 		sprintf(name, NAME_TEMPLATE, i);
 		remove_proc_entry(name, NULL);
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 0dfee28..8bdee67 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_bam_data.c b/drivers/usb/gadget/u_bam_data.c
new file mode 100644
index 0000000..73b4e75
--- /dev/null
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -0,0 +1,328 @@
+/* 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.
+ */
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/usb/gadget.h>
+
+#include <mach/bam_dmux.h>
+#include <mach/usb_gadget_xport.h>
+#include <mach/usb_bam.h>
+
+#define BAM2BAM_DATA_N_PORTS	1
+
+static struct workqueue_struct *bam_data_wq;
+static int n_bam2bam_data_ports;
+
+#define SPS_PARAMS_SPS_MODE		BIT(5)
+#define SPS_PARAMS_TBE		        BIT(6)
+#define MSM_VENDOR_ID			BIT(16)
+
+struct data_port {
+	struct usb_function		func;
+	struct usb_ep			*in;
+	struct usb_ep			*out;
+};
+
+struct bam_data_ch_info {
+	unsigned long		flags;
+	unsigned		id;
+
+	struct bam_data_port	*port;
+	struct work_struct	write_tobam_w;
+
+	struct usb_request	*rx_req;
+	struct usb_request	*tx_req;
+
+	u8			src_pipe_idx;
+	u8			dst_pipe_idx;
+	u8			connection_idx;
+};
+
+struct bam_data_port {
+	unsigned			port_num;
+	struct data_port		*port_usb;
+	struct bam_data_ch_info		data_ch;
+
+	struct work_struct		connect_w;
+	struct work_struct		disconnect_w;
+};
+
+struct bam_data_port *bam2bam_data_ports[BAM2BAM_DATA_N_PORTS];
+
+/*------------data_path----------------------------*/
+
+static void bam_data_endless_rx_complete(struct usb_ep *ep,
+					 struct usb_request *req)
+{
+	int status = req->status;
+
+	pr_info("status: %d\n", status);
+}
+
+static void bam_data_endless_tx_complete(struct usb_ep *ep,
+					 struct usb_request *req)
+{
+	int status = req->status;
+
+	pr_info("status: %d\n", status);
+}
+
+static void bam_data_start_endless_rx(struct bam_data_port *port)
+{
+	struct bam_data_ch_info *d = &port->data_ch;
+	int status;
+
+	status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
+	if (status)
+		pr_err("error enqueuing transfer, %d\n", status);
+}
+
+static void bam_data_start_endless_tx(struct bam_data_port *port)
+{
+	struct bam_data_ch_info *d = &port->data_ch;
+	int status;
+
+	status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
+	if (status)
+		pr_err("error enqueuing transfer, %d\n", status);
+}
+
+static void bam2bam_data_disconnect_work(struct work_struct *w)
+{
+	struct bam_data_port *port =
+			container_of(w, struct bam_data_port, disconnect_w);
+
+	pr_info("Enter");
+
+	/* disable endpoints */
+	if (!port->port_usb || !port->port_usb->out || !port->port_usb->in) {
+		pr_err("port_usb->out/in == NULL. Exit");
+		return;
+	}
+	usb_ep_disable(port->port_usb->out);
+	usb_ep_disable(port->port_usb->in);
+
+	port->port_usb->in->driver_data = NULL;
+	port->port_usb->out->driver_data = NULL;
+
+	port->port_usb = 0;
+
+	pr_info("Exit");
+}
+
+static void bam2bam_data_connect_work(struct work_struct *w)
+{
+	struct bam_data_port *port = container_of(w, struct bam_data_port,
+						  connect_w);
+	struct bam_data_ch_info *d = &port->data_ch;
+	u32 sps_params;
+	int ret;
+
+	pr_info("Enter");
+
+	ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
+						  &d->dst_pipe_idx);
+	d->src_pipe_idx = 11;
+	d->dst_pipe_idx = 10;
+
+	if (ret) {
+		pr_err("usb_bam_connect failed: err:%d\n", ret);
+		return;
+	}
+
+	if (!port->port_usb) {
+		pr_err("port_usb is NULL");
+		return;
+	}
+
+	if (!port->port_usb->out) {
+		pr_err("port_usb->out (bulk out ep) is NULL");
+		return;
+	}
+
+	d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
+	if (!d->rx_req)
+		return;
+
+	d->rx_req->context = port;
+	d->rx_req->complete = bam_data_endless_rx_complete;
+	d->rx_req->length = 0;
+	sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx |
+				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
+	d->rx_req->udc_priv = sps_params;
+	d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_KERNEL);
+	if (!d->tx_req)
+		return;
+
+	d->tx_req->context = port;
+	d->tx_req->complete = bam_data_endless_tx_complete;
+	d->tx_req->length = 0;
+	sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx |
+				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
+	d->tx_req->udc_priv = sps_params;
+
+	/* queue in & out requests */
+	bam_data_start_endless_rx(port);
+	bam_data_start_endless_tx(port);
+
+	pr_info("Done\n");
+}
+
+static void bam2bam_data_port_free(int portno)
+{
+	kfree(bam2bam_data_ports[portno]);
+	bam2bam_data_ports[portno] = NULL;
+}
+
+static int bam2bam_data_port_alloc(int portno)
+{
+	struct bam_data_port	*port = NULL;
+	struct bam_data_ch_info	*d = NULL;
+
+	port = kzalloc(sizeof(struct bam_data_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->port_num = portno;
+
+	INIT_WORK(&port->connect_w, bam2bam_data_connect_work);
+	INIT_WORK(&port->disconnect_w, bam2bam_data_disconnect_work);
+
+	/* data ch */
+	d = &port->data_ch;
+	d->port = port;
+	bam2bam_data_ports[portno] = port;
+
+	pr_info("port:%p portno:%d\n", port, portno);
+
+	return 0;
+}
+
+void bam_data_disconnect(struct data_port *gr, u8 port_num)
+{
+	struct bam_data_port	*port;
+	struct bam_data_ch_info	*d;
+
+	pr_info("dev:%p port#%d\n", gr, port_num);
+
+	if (port_num >= n_bam2bam_data_ports) {
+		pr_err("invalid bam2bam portno#%d\n", port_num);
+		return;
+	}
+
+	if (!gr) {
+		pr_err("mbim data port is null\n");
+		return;
+	}
+
+	port = bam2bam_data_ports[port_num];
+
+	d = &port->data_ch;
+	port->port_usb = gr;
+
+	queue_work(bam_data_wq, &port->disconnect_w);
+}
+
+int bam_data_connect(struct data_port *gr, u8 port_num,
+				 u8 connection_idx)
+{
+	struct bam_data_port	*port;
+	struct bam_data_ch_info	*d;
+	int			ret;
+
+	pr_info("dev:%p port#%d\n", gr, port_num);
+
+	if (port_num >= n_bam2bam_data_ports) {
+		pr_err("invalid portno#%d\n", port_num);
+		return -ENODEV;
+	}
+
+	if (!gr) {
+		pr_err("mbim data port is null\n");
+		return -ENODEV;
+	}
+
+	port = bam2bam_data_ports[port_num];
+
+	d = &port->data_ch;
+
+	ret = usb_ep_enable(gr->in);
+	if (ret) {
+		pr_err("usb_ep_enable failed eptype:IN ep:%p", gr->in);
+		return ret;
+	}
+	gr->in->driver_data = port;
+
+	ret = usb_ep_enable(gr->out);
+	if (ret) {
+		pr_err("usb_ep_enable failed eptype:OUT ep:%p", gr->out);
+		gr->in->driver_data = 0;
+		return ret;
+	}
+	gr->out->driver_data = port;
+
+	port->port_usb = gr;
+
+	d->connection_idx = connection_idx;
+
+	queue_work(bam_data_wq, &port->connect_w);
+
+	return 0;
+}
+
+int bam_data_setup(unsigned int no_bam2bam_port)
+{
+	int	i;
+	int	ret;
+
+	pr_info("requested %d BAM2BAM ports", no_bam2bam_port);
+
+	if (!no_bam2bam_port || no_bam2bam_port > BAM2BAM_DATA_N_PORTS) {
+		pr_err("Invalid num of ports count:%d\n", no_bam2bam_port);
+		return -EINVAL;
+	}
+
+	bam_data_wq = alloc_workqueue("k_bam_data",
+				      WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!bam_data_wq) {
+		pr_err("Failed to create workqueue\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < no_bam2bam_port; i++) {
+		n_bam2bam_data_ports++;
+		ret = bam2bam_data_port_alloc(i);
+		if (ret) {
+			n_bam2bam_data_ports--;
+			pr_err("Failed to alloc port:%d\n", i);
+			goto free_bam_ports;
+		}
+	}
+
+	return 0;
+
+free_bam_ports:
+	for (i = 0; i < n_bam2bam_data_ports; i++)
+		bam2bam_data_port_free(i);
+	destroy_workqueue(bam_data_wq);
+
+	return ret;
+}
+
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 818e2a6..89d2887 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -34,8 +34,8 @@
 
 #define GHSIC_DATA_RMNET_RX_Q_SIZE		50
 #define GHSIC_DATA_RMNET_TX_Q_SIZE		300
-#define GHSIC_DATA_SERIAL_RX_Q_SIZE		2
-#define GHSIC_DATA_SERIAL_TX_Q_SIZE		2
+#define GHSIC_DATA_SERIAL_RX_Q_SIZE		10
+#define GHSIC_DATA_SERIAL_TX_Q_SIZE		20
 #define GHSIC_DATA_RX_REQ_SIZE			2048
 #define GHSIC_DATA_TX_INTR_THRESHOLD		20
 
@@ -666,6 +666,7 @@
 	if (!port->wq) {
 		pr_err("%s: Unable to create workqueue:%s\n",
 			__func__, data_bridge_names[port_num]);
+		kfree(port);
 		return -ENOMEM;
 	}
 	port->port_num = port_num;
@@ -754,8 +755,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 +787,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 +802,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..19ad77f 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -67,7 +67,7 @@
 
 	spinlock_t		req_lock;	/* guard {rx,tx}_reqs */
 	struct list_head	tx_reqs, rx_reqs;
-	atomic_t		tx_qlen;
+	unsigned		tx_qlen;
 
 	struct sk_buff_head	rx_frames;
 
@@ -484,7 +484,6 @@
 	spin_unlock(&dev->req_lock);
 	dev_kfree_skb_any(skb);
 
-	atomic_dec(&dev->tx_qlen);
 	if (netif_carrier_ok(dev->net))
 		netif_wake_queue(dev->net);
 }
@@ -599,10 +598,18 @@
 	req->length = length;
 
 	/* throttle highspeed IRQ rate back slightly */
-	if (gadget_is_dualspeed(dev->gadget))
-		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
-			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
-			: 0;
+	if (gadget_is_dualspeed(dev->gadget) &&
+			 (dev->gadget->speed == USB_SPEED_HIGH)) {
+		dev->tx_qlen++;
+		if (dev->tx_qlen == qmult) {
+			req->no_interrupt = 0;
+			dev->tx_qlen = 0;
+		} else {
+			req->no_interrupt = 1;
+		}
+	} else {
+		req->no_interrupt = 0;
+	}
 
 	retval = usb_ep_queue(in, req, GFP_ATOMIC);
 	switch (retval) {
@@ -611,7 +618,6 @@
 		break;
 	case 0:
 		net->trans_start = jiffies;
-		atomic_inc(&dev->tx_qlen);
 	}
 
 	if (retval) {
@@ -637,7 +643,7 @@
 	rx_fill(dev, gfp_flags);
 
 	/* and open the tx floodgates */
-	atomic_set(&dev->tx_qlen, 0);
+	dev->tx_qlen = 0;
 	netif_wake_queue(dev->net);
 }
 
@@ -693,8 +699,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 +897,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 +905,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 +994,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 +1009,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 fd1e124..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_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index 8671669..0256a75 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -108,14 +108,17 @@
 	void *buf;
 	unsigned long flags;
 
-	while (1) {
+	spin_lock_irqsave(&port->port_lock, flags);
+	while (c->ch) {
 		sz = smd_cur_packet_size(c->ch);
-		if (sz == 0)
+		if (sz <= 0)
 			break;
 
 		if (smd_read_avail(c->ch) < sz)
 			break;
 
+		spin_unlock_irqrestore(&port->port_lock, flags);
+
 		buf = kmalloc(sz, GFP_KERNEL);
 		if (!buf)
 			return;
@@ -130,8 +133,8 @@
 			c->to_host++;
 		}
 		kfree(buf);
-		spin_unlock_irqrestore(&port->port_lock, flags);
 	}
+	spin_unlock_irqrestore(&port->port_lock, flags);
 }
 
 static void grmnet_ctrl_smd_write_w(struct work_struct *w)
@@ -143,7 +146,7 @@
 	int ret;
 
 	spin_lock_irqsave(&port->port_lock, flags);
-	while (1) {
+	while (c->ch) {
 		if (list_empty(&c->tx_q))
 			break;
 
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index 9bd4370..8c4b4c7 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -231,7 +231,7 @@
 int gsdio_write(struct gsdio_port *port, struct usb_request *req)
 {
 	unsigned	avail;
-	char		*packet = req->buf;
+	char		*packet;
 	unsigned	size = req->actual;
 	unsigned	n;
 	int		ret = 0;
@@ -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..a5ceaff 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -209,6 +209,7 @@
 static void gsmd_rx_push(struct work_struct *w)
 {
 	struct gsmd_port *port = container_of(w, struct gsmd_port, push);
+	struct smd_port_info *pi = port->pi;
 	struct list_head *q;
 
 	pr_debug("%s: port:%p port#%d", __func__, port, port->port_num);
@@ -216,10 +217,9 @@
 	spin_lock_irq(&port->port_lock);
 
 	q = &port->read_queue;
-	while (!list_empty(q)) {
+	while (pi->ch && !list_empty(q)) {
 		struct usb_request *req;
 		int avail;
-		struct smd_port_info *pi = port->pi;
 
 		req = list_first_entry(q, struct usb_request, list);
 
@@ -245,7 +245,7 @@
 			char		*packet = req->buf;
 			unsigned	size = req->actual;
 			unsigned	n;
-			unsigned	count;
+			int		count;
 
 			n = port->n_read;
 			if (n) {
@@ -296,21 +296,24 @@
 {
 	struct gsmd_port *port = container_of(w, struct gsmd_port, pull);
 	struct list_head *pool = &port->write_pool;
+	struct smd_port_info *pi = port->pi;
+	struct usb_ep *in;
 
 	pr_debug("%s: port:%p port#%d pool:%p\n", __func__,
 			port, port->port_num, pool);
 
+	spin_lock_irq(&port->port_lock);
+
 	if (!port->port_usb) {
 		pr_debug("%s: usb is disconnected\n", __func__);
+		spin_unlock_irq(&port->port_lock);
 		gsmd_read_pending(port);
 		return;
 	}
 
-	spin_lock_irq(&port->port_lock);
-	while (!list_empty(pool)) {
+	in = port->port_usb->in;
+	while (pi->ch && !list_empty(pool)) {
 		struct usb_request *req;
-		struct usb_ep *in = port->port_usb->in;
-		struct smd_port_info *pi = port->pi;
 		int avail;
 		int ret;
 
@@ -660,7 +663,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 +672,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..2f77e46
--- /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-dbg.c b/drivers/usb/host/ehci-dbg.c
index dd67cad..029fbc8 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -808,7 +808,7 @@
 	next += temp;
 
 	temp = scnprintf (next, size, "uframe %04x\n",
-			ehci_readl(ehci, &ehci->regs->frame_index));
+			ehci_read_frame_index(ehci));
 	size -= temp;
 	next += temp;
 
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index f380bf9..bc7f166 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -125,7 +125,7 @@
 	 */
 	if (pdata->init && pdata->init(pdev)) {
 		retval = -ENODEV;
-		goto err3;
+		goto err4;
 	}
 
 	/* Enable USB controller, 83xx or 8536 */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index dc11eaf..0c71c8b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -774,6 +774,35 @@
 	return 0;
 }
 
+static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int retval;
+
+	ehci->regs = (void __iomem *)ehci->caps +
+	    HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+	ehci->sbrn = HCD_USB2;
+
+	retval = ehci_halt(ehci);
+	if (retval)
+		return retval;
+
+	/* data structure init */
+	retval = ehci_init(hcd);
+	if (retval)
+		return retval;
+
+	ehci_reset(ehci);
+
+	return 0;
+}
+
 /*-------------------------------------------------------------------------*/
 
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
@@ -1172,8 +1201,7 @@
 static int ehci_get_frame (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
-		ehci->periodic_size;
+	return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1274,6 +1302,7 @@
 
 #ifdef CONFIG_USB_EHCI_MSM
 #include "ehci-msm.c"
+#include "ehci-msm2.c"
 #define PLATFORM_DRIVER_PRESENT
 #endif
 
@@ -1391,7 +1420,11 @@
 #endif
 
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
-	&ehci_msm_hsic_driver
+	&ehci_msm_hsic_driver,
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM
+	&ehci_msm2_driver,
 #endif
 
 };
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index d438555..af638f4 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1203,10 +1203,9 @@
 			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
 #ifdef	CONFIG_USB_OTG
 			if (hcd->self.otg_port == (wIndex + 1) &&
-					hcd->self.b_hnp_enable &&
-					ehci->start_hnp) {
+					hcd->self.b_hnp_enable) {
 				set_bit(wIndex, &ehci->suspended_ports);
-				ehci->start_hnp(ehci);
+				otg_start_hnp(ehci->transceiver);
 				break;
 			}
 #endif
@@ -1274,7 +1273,21 @@
 		case USB_PORT_FEAT_TEST:
 			if (selector && selector <= 5) {
 				ehci_quiesce(ehci);
+
+			/* Put all enabled ports into suspend */
+				while (ports--) {
+					u32 __iomem *sreg =
+						&ehci->regs->port_status[ports];
+
+					temp = ehci_readl(ehci, sreg)
+					       	& ~PORT_RWC_BITS;
+					if (temp & PORT_PE)
+						ehci_writel(ehci,
+							temp | PORT_SUSPEND,
+							sreg);
+				}
 				ehci_halt(ehci);
+				temp = ehci_readl(ehci, status_reg);
 				temp |= selector << 16;
 				ehci_writel(ehci, temp, status_reg);
 			}
@@ -1289,8 +1302,6 @@
 #endif
 			else
 				goto error;
-			break;
-
 		default:
 			goto error;
 		}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d64f223..347711b 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -53,6 +53,8 @@
 	struct msm_xo_voter	*xo_handle;
 	struct wake_lock	wlock;
 	int			peripheral_status_irq;
+	int			wakeup_irq;
+	bool			wakeup_irq_enabled;
 };
 
 static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
@@ -81,7 +83,7 @@
 	if (!init)
 		goto disable_reg;
 
-	mehci->hsic_vddcx = regulator_get(mehci->dev, "HSIC_VDDCX");
+	mehci->hsic_vddcx = devm_regulator_get(mehci->dev, "HSIC_VDDCX");
 	if (IS_ERR(mehci->hsic_vddcx)) {
 		dev_err(mehci->dev, "unable to get hsic vddcx\n");
 		return PTR_ERR(mehci->hsic_vddcx);
@@ -93,7 +95,7 @@
 	if (ret) {
 		dev_err(mehci->dev, "unable to set the voltage"
 				"for hsic vddcx\n");
-		goto reg_set_voltage_err;
+		return ret;
 	}
 
 	ret = regulator_set_optimum_mode(mehci->hsic_vddcx,
@@ -119,9 +121,6 @@
 reg_optimum_mode_err:
 	regulator_set_voltage(mehci->hsic_vddcx, 0,
 				USB_PHY_VDD_DIG_VOL_MIN);
-reg_set_voltage_err:
-	regulator_put(mehci->hsic_vddcx);
-
 	return ret;
 
 }
@@ -168,7 +167,7 @@
 	if (!init)
 		goto disable_reg;
 
-	hsic_hub_reg = regulator_get(mehci->dev, "EXT_HUB_VDDIO");
+	hsic_hub_reg = devm_regulator_get(mehci->dev, "EXT_HUB_VDDIO");
 	if (IS_ERR(hsic_hub_reg)) {
 		dev_err(mehci->dev, "unable to get ext hub vddcx\n");
 		return PTR_ERR(hsic_hub_reg);
@@ -178,7 +177,7 @@
 	if (ret < 0) {
 		dev_err(mehci->dev, "gpio request failed for GPIO%d\n",
 							pdata->hub_reset);
-		goto gpio_req_fail;
+		return ret;
 	}
 
 	ret = regulator_set_voltage(hsic_hub_reg,
@@ -220,8 +219,6 @@
 				HSIC_HUB_VDD_VOL_MIN);
 reg_set_voltage_fail:
 	gpio_free(pdata->hub_reset);
-gpio_req_fail:
-	regulator_put(hsic_hub_reg);
 
 	return ret;
 
@@ -599,7 +596,7 @@
 	/* bursts of unspecified length. */
 	writel_relaxed(0, USB_AHBBURST);
 	/* Use the AHB transactor */
-	writel_relaxed(0, USB_AHBMODE);
+	writel_relaxed(0x08, USB_AHBMODE);
 	/* Disable streaming mode and select host mode */
 	writel_relaxed(0x13, USB_USBMODE);
 
@@ -712,10 +709,12 @@
 	return 0;
 
 put_clocks:
-	clk_disable_unprepare(mehci->core_clk);
-	clk_disable_unprepare(mehci->phy_clk);
-	clk_disable_unprepare(mehci->cal_clk);
-	clk_disable_unprepare(mehci->ahb_clk);
+	if (!atomic_read(&mehci->in_lpm)) {
+		clk_disable_unprepare(mehci->core_clk);
+		clk_disable_unprepare(mehci->phy_clk);
+		clk_disable_unprepare(mehci->cal_clk);
+		clk_disable_unprepare(mehci->ahb_clk);
+	}
 	clk_put(mehci->ahb_clk);
 put_cal_clk:
 	clk_put(mehci->cal_clk);
@@ -732,7 +731,7 @@
 {
 	struct msm_hsic_hcd *mehci = dev_id;
 
-	pr_debug("%s: mechi:%p dev_id:%p\n", __func__, mehci, dev_id);
+	pr_debug("%s: mehci:%p dev_id:%p\n", __func__, mehci, dev_id);
 
 	if (mehci)
 		msm_hsic_config_gpios(mehci, 0);
@@ -740,6 +739,22 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
+{
+	struct msm_hsic_hcd *mehci = data;
+
+	dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt\n", __func__);
+
+	if (mehci->wakeup_irq_enabled) {
+		mehci->wakeup_irq_enabled = 0;
+		disable_irq_wake(irq);
+		disable_irq_nosync(irq);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
 static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -854,6 +869,23 @@
 				__func__, mehci->peripheral_status_irq, ret);
 	}
 
+	/* configure wakeup irq */
+	ret = platform_get_irq(pdev, 2);
+	if (ret > 0) {
+		mehci->wakeup_irq = ret;
+		dev_dbg(&pdev->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
+		ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
+				IRQF_TRIGGER_LOW,
+				"msm_hsic_wakeup", mehci);
+		if (!ret) {
+			disable_irq_nosync(mehci->wakeup_irq);
+		} else {
+			dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
+					mehci->wakeup_irq, ret);
+			mehci->wakeup_irq = 0;
+		}
+	}
+
 	/*
 	 * This pdev->dev is assigned parent of root-hub by USB core,
 	 * hence, runtime framework automatically calls this driver's
@@ -892,8 +924,13 @@
 	if (mehci->peripheral_status_irq)
 		free_irq(mehci->peripheral_status_irq, mehci);
 
+	if (mehci->wakeup_irq) {
+		if (mehci->wakeup_irq_enabled)
+			disable_irq_wake(mehci->wakeup_irq);
+		free_irq(mehci->wakeup_irq, mehci);
+	}
+
 	device_init_wakeup(&pdev->dev, 0);
-	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
 	usb_remove_hcd(hcd);
@@ -924,7 +961,22 @@
 		enable_irq_wake(hcd->irq);
 
 	return msm_hsic_suspend(mehci);
+}
 
+static int msm_hsic_pm_suspend_noirq(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+	dev_dbg(dev, "ehci-msm-hsic PM suspend_noirq\n");
+
+	if (device_may_wakeup(dev) && !mehci->wakeup_irq_enabled) {
+		enable_irq(mehci->wakeup_irq);
+		enable_irq_wake(mehci->wakeup_irq);
+		mehci->wakeup_irq_enabled = 1;
+	}
+
+	return 0;
 }
 
 static int msm_hsic_pm_resume(struct device *dev)
@@ -938,6 +990,12 @@
 	if (device_may_wakeup(dev))
 		disable_irq_wake(hcd->irq);
 
+	if (mehci->wakeup_irq_enabled) {
+		mehci->wakeup_irq_enabled = 0;
+		disable_irq_wake(mehci->wakeup_irq);
+		disable_irq_nosync(mehci->wakeup_irq);
+	}
+
 	ret = msm_hsic_resume(mehci);
 	if (ret)
 		return ret;
@@ -981,6 +1039,7 @@
 #ifdef CONFIG_PM
 static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
+	.suspend_noirq = msm_hsic_pm_suspend_noirq,
 	SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
 				msm_hsic_runtime_idle)
 };
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index f45f257..6a86632 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -1,6 +1,6 @@
 /* ehci-msm.c - HSUSB Host Controller Driver Implementation
  *
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * Partly derived from ehci-fsl.c and ehci-hcd.c
  * Copyright (c) 2000-2004 by David Brownell
@@ -67,7 +67,7 @@
 	/* bursts of unspecified length. */
 	writel(0, USB_AHBBURST);
 	/* Use the AHB transactor */
-	writel(0, USB_AHBMODE);
+	writel_relaxed(0x08, USB_AHBMODE);
 	/* Disable streaming mode and select host mode */
 	writel(0x13, USB_USBMODE);
 
@@ -176,6 +176,7 @@
 		goto put_transceiver;
 	}
 
+	hcd_to_ehci(hcd)->transceiver = otg;
 	device_init_wakeup(&pdev->dev, 1);
 	pm_runtime_enable(&pdev->dev);
 
@@ -199,6 +200,7 @@
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
+	hcd_to_ehci(hcd)->transceiver = NULL;
 	otg_set_host(otg, NULL);
 	otg_put_transceiver(otg);
 
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
new file mode 100644
index 0000000..17fa7b1
--- /dev/null
+++ b/drivers/usb/host/ehci-msm2.c
@@ -0,0 +1,1050 @@
+/* ehci-msm2.c - HSUSB Host Controller Driver Implementation
+ *
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Partly derived from ehci-fsl.c and ehci-hcd.c
+ * Copyright (c) 2000-2004 by David Brownell
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/usb/ulpi.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/msm_hsusb.h>
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+
+#define MSM_USB_BASE (hcd->regs)
+
+struct msm_hcd {
+	struct ehci_hcd				ehci;
+	struct device				*dev;
+	struct clk				*iface_clk;
+	struct clk				*core_clk;
+	struct clk				*alt_core_clk;
+	struct regulator			*hsusb_vddcx;
+	struct regulator			*hsusb_3p3;
+	struct regulator			*hsusb_1p8;
+	struct regulator			*vbus;
+	bool					async_int;
+	bool					vbus_on;
+	atomic_t				in_lpm;
+	struct wake_lock			wlock;
+};
+
+static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
+{
+	return (struct msm_hcd *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *mhcd_to_hcd(struct msm_hcd *mhcd)
+{
+	return container_of((void *) mhcd, struct usb_hcd, hcd_priv);
+}
+
+#define HSUSB_PHY_3P3_VOL_MIN		3050000 /* uV */
+#define HSUSB_PHY_3P3_VOL_MAX		3300000 /* uV */
+#define HSUSB_PHY_3P3_HPM_LOAD		50000	/* uA */
+
+#define HSUSB_PHY_1P8_VOL_MIN		1800000 /* uV */
+#define HSUSB_PHY_1P8_VOL_MAX		1800000 /* uV */
+#define HSUSB_PHY_1P8_HPM_LOAD		50000	/* uA */
+
+#define HSUSB_PHY_VDD_DIG_VOL_MIN	1045000	/* uV */
+#define HSUSB_PHY_VDD_DIG_VOL_MAX	1320000	/* uV */
+#define HSUSB_PHY_VDD_DIG_LOAD		49360	/* uA */
+
+static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
+{
+	int ret = 0;
+
+	if (!init)
+		goto disable_reg;
+
+	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "HSUSB_VDDCX");
+	if (IS_ERR(mhcd->hsusb_vddcx)) {
+		dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+		return PTR_ERR(mhcd->hsusb_vddcx);
+	}
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx,
+			HSUSB_PHY_VDD_DIG_VOL_MIN,
+			HSUSB_PHY_VDD_DIG_VOL_MAX);
+	if (ret) {
+		dev_err(mhcd->dev, "unable to set the voltage"
+				"for ehci vddcx\n");
+		return ret;
+	}
+
+	ret = regulator_set_optimum_mode(mhcd->hsusb_vddcx,
+				HSUSB_PHY_VDD_DIG_LOAD);
+	if (ret < 0) {
+		dev_err(mhcd->dev, "%s: Unable to set optimum mode of the"
+				" regulator: VDDCX\n", __func__);
+		goto reg_optimum_mode_err;
+	}
+
+	ret = regulator_enable(mhcd->hsusb_vddcx);
+	if (ret) {
+		dev_err(mhcd->dev, "unable to enable ehci vddcx\n");
+		goto reg_enable_err;
+	}
+
+	return 0;
+
+disable_reg:
+	regulator_disable(mhcd->hsusb_vddcx);
+reg_enable_err:
+	regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
+reg_optimum_mode_err:
+	regulator_set_voltage(mhcd->hsusb_vddcx, 0,
+				HSUSB_PHY_VDD_DIG_VOL_MIN);
+	return ret;
+
+}
+
+static int msm_ehci_ldo_init(struct msm_hcd *mhcd, int init)
+{
+	int rc = 0;
+
+	if (!init)
+		goto put_1p8;
+
+	mhcd->hsusb_3p3 = devm_regulator_get(mhcd->dev, "HSUSB_3p3");
+	if (IS_ERR(mhcd->hsusb_3p3)) {
+		dev_err(mhcd->dev, "unable to get hsusb 3p3\n");
+		return PTR_ERR(mhcd->hsusb_3p3);
+	}
+
+	rc = regulator_set_voltage(mhcd->hsusb_3p3,
+			HSUSB_PHY_3P3_VOL_MIN, HSUSB_PHY_3P3_VOL_MAX);
+	if (rc) {
+		dev_err(mhcd->dev, "unable to set voltage level for"
+				"hsusb 3p3\n");
+		return rc;
+	}
+	mhcd->hsusb_1p8 = devm_regulator_get(mhcd->dev, "HSUSB_1p8");
+	if (IS_ERR(mhcd->hsusb_1p8)) {
+		dev_err(mhcd->dev, "unable to get hsusb 1p8\n");
+		rc = PTR_ERR(mhcd->hsusb_1p8);
+		goto put_3p3_lpm;
+	}
+	rc = regulator_set_voltage(mhcd->hsusb_1p8,
+			HSUSB_PHY_1P8_VOL_MIN, HSUSB_PHY_1P8_VOL_MAX);
+	if (rc) {
+		dev_err(mhcd->dev, "unable to set voltage level for"
+				"hsusb 1p8\n");
+		goto put_1p8;
+	}
+
+	return 0;
+
+put_1p8:
+	regulator_set_voltage(mhcd->hsusb_1p8, 0, HSUSB_PHY_1P8_VOL_MAX);
+put_3p3_lpm:
+	regulator_set_voltage(mhcd->hsusb_3p3, 0, HSUSB_PHY_3P3_VOL_MAX);
+
+	return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+#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_P50;
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
+	if (ret) {
+		dev_err(mhcd->dev, "%s: unable to set the voltage of regulator"
+			" HSUSB_VDDCX\n", __func__);
+		return ret;
+	}
+
+	dev_dbg(mhcd->dev, "%s: min_vol:%d max_vol:%d\n", __func__, min_vol,
+								max_vol);
+
+	return ret;
+}
+#else
+static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
+{
+	return 0;
+}
+#endif
+
+static void msm_ehci_vbus_power(struct msm_hcd *mhcd, bool on)
+{
+	int ret;
+
+	if (!mhcd->vbus) {
+		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) {
+		if (pdata && pdata->dock_connect_irq)
+			free_irq(pdata->dock_connect_irq, mhcd);
+		return rc;
+	}
+
+	mhcd->vbus = devm_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;
+
+	if (IS_ERR(mhcd->hsusb_1p8)) {
+		dev_err(mhcd->dev, "%s: HSUSB_1p8 is not initialized\n",
+								__func__);
+		return -ENODEV;
+	}
+
+	if (IS_ERR(mhcd->hsusb_3p3)) {
+		dev_err(mhcd->dev, "%s: HSUSB_3p3 is not initialized\n",
+								__func__);
+		return -ENODEV;
+	}
+
+	if (on) {
+		ret = regulator_set_optimum_mode(mhcd->hsusb_1p8,
+						HSUSB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			dev_err(mhcd->dev, "%s: Unable to set HPM of the"
+				" regulator: HSUSB_1p8\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_enable(mhcd->hsusb_1p8);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to enable the hsusb"
+						" 1p8\n", __func__);
+			regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(mhcd->hsusb_3p3,
+						HSUSB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			dev_err(mhcd->dev, "%s: Unable to set HPM of the "
+				"regulator: HSUSB_3p3\n", __func__);
+			regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+			regulator_disable(mhcd->hsusb_1p8);
+			return ret;
+		}
+
+		ret = regulator_enable(mhcd->hsusb_3p3);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to enable the "
+					"hsusb 3p3\n", __func__);
+			regulator_set_optimum_mode(mhcd->hsusb_3p3, 0);
+			regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+			regulator_disable(mhcd->hsusb_1p8);
+			return ret;
+		}
+
+	} else {
+		ret = regulator_disable(mhcd->hsusb_1p8);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to disable the "
+					"hsusb 1p8\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+		if (ret < 0)
+			dev_err(mhcd->dev, "%s: Unable to set LPM of the "
+				"regulator: HSUSB_1p8\n", __func__);
+
+		ret = regulator_disable(mhcd->hsusb_3p3);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to disable the "
+					"hsusb 3p3\n", __func__);
+			return ret;
+		}
+		ret = regulator_set_optimum_mode(mhcd->hsusb_3p3, 0);
+		if (ret < 0)
+			dev_err(mhcd->dev, "%s: Unable to set LPM of the "
+					"regulator: HSUSB_3p3\n", __func__);
+	}
+
+	dev_dbg(mhcd->dev, "reg (%s)\n", on ? "HPM" : "LPM");
+
+	return ret < 0 ? ret : 0;
+}
+
+
+#define ULPI_IO_TIMEOUT_USECS	(10 * 1000)
+static int msm_ulpi_read(struct msm_hcd *mhcd, u32 reg)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+
+	/* initiate read operation */
+	writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USECS);
+	while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(mhcd->dev, "msm_ulpi_read: timeout %08x\n",
+				readl_relaxed(USB_ULPI_VIEWPORT));
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
+}
+
+
+static int msm_ulpi_write(struct msm_hcd *mhcd, u32 val, u32 reg)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+
+	/* initiate write operation */
+	writel_relaxed(ULPI_RUN | ULPI_WRITE |
+	       ULPI_ADDR(reg) | ULPI_DATA(val),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USECS);
+	while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(mhcd->dev, "msm_ulpi_write: timeout\n");
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int msm_ehci_link_clk_reset(struct msm_hcd *mhcd, bool assert)
+{
+	int ret;
+
+	if (assert) {
+		ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_ASSERT);
+		if (ret)
+			dev_err(mhcd->dev, "usb alt_core_clk assert failed\n");
+	} else {
+		ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_DEASSERT);
+		if (ret)
+			dev_err(mhcd->dev, "usb alt_core_clk deassert failed\n");
+	}
+
+	return ret;
+}
+
+static int msm_ehci_phy_reset(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	u32 val;
+	int ret;
+	int retries;
+
+	ret = msm_ehci_link_clk_reset(mhcd, 1);
+	if (ret)
+		return ret;
+
+	udelay(1);
+
+	ret = msm_ehci_link_clk_reset(mhcd, 0);
+	if (ret)
+		return ret;
+
+	val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
+	writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+	for (retries = 3; retries > 0; retries--) {
+		ret = msm_ulpi_write(mhcd, ULPI_FUNC_CTRL_SUSPENDM,
+				ULPI_CLR(ULPI_FUNC_CTRL));
+		if (!ret)
+			break;
+	}
+	if (!retries)
+		return -ETIMEDOUT;
+
+	/* Wakeup the PHY with a reg-access for calibration */
+	for (retries = 3; retries > 0; retries--) {
+		ret = msm_ulpi_read(mhcd, ULPI_DEBUG);
+		if (ret != -ETIMEDOUT)
+			break;
+	}
+	if (!retries)
+		return -ETIMEDOUT;
+
+	dev_info(mhcd->dev, "phy_reset: success\n");
+
+	return 0;
+}
+
+#define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
+static int msm_hsusb_reset(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+	int ret;
+
+	clk_prepare_enable(mhcd->alt_core_clk);
+	ret = msm_ehci_phy_reset(mhcd);
+	if (ret) {
+		dev_err(mhcd->dev, "phy_reset failed\n");
+		return ret;
+	}
+
+	writel_relaxed(USBCMD_RESET, USB_USBCMD);
+
+	timeout = jiffies + usecs_to_jiffies(LINK_RESET_TIMEOUT_USEC);
+	while (readl_relaxed(USB_USBCMD) & USBCMD_RESET) {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+		udelay(1);
+	}
+
+	/* select ULPI phy */
+	writel_relaxed(0x80000000, USB_PORTSC);
+
+	msleep(100);
+
+	writel_relaxed(0x0, USB_AHBBURST);
+	writel_relaxed(0x08, USB_AHBMODE);
+
+	/* Ensure that RESET operation is completed before turning off clock */
+	mb();
+	clk_disable_unprepare(mhcd->alt_core_clk);
+
+	/*rising edge interrupts with Dp rise and fall enabled*/
+	msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_RISE);
+	msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_FALL);
+
+	/*Clear the PHY interrupts by reading the PHY interrupt latch register*/
+	msm_ulpi_read(mhcd, ULPI_USB_INT_LATCH);
+
+	return 0;
+}
+
+#define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
+#define PHY_RESUME_TIMEOUT_USEC		(100 * 1000)
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_ehci_suspend(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+	u32 portsc;
+
+	if (atomic_read(&mhcd->in_lpm)) {
+		dev_dbg(mhcd->dev, "%s called in lpm\n", __func__);
+		return 0;
+	}
+
+	disable_irq(hcd->irq);
+
+	/* Set the PHCD bit, only if it is not set by the controller.
+	 * PHY may take some time or even fail to enter into low power
+	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
+	 * in failure case.
+	 */
+	portsc = readl_relaxed(USB_PORTSC);
+	if (!(portsc & PORTSC_PHCD)) {
+		writel_relaxed(portsc | PORTSC_PHCD,
+				USB_PORTSC);
+
+		timeout = jiffies + usecs_to_jiffies(PHY_SUSPEND_TIMEOUT_USEC);
+		while (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD)) {
+			if (time_after(jiffies, timeout)) {
+				dev_err(mhcd->dev, "Unable to suspend PHY\n");
+				msm_hsusb_reset(mhcd);
+				break;
+			}
+			udelay(1);
+		}
+	}
+
+	/*
+	 * PHY has capability to generate interrupt asynchronously in low
+	 * power mode (LPM). This interrupt is level triggered. So USB IRQ
+	 * line must be disabled till async interrupt enable bit is cleared
+	 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+	 * block data communication from PHY.
+	 */
+	writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
+				ULPI_STP_CTRL, USB_USBCMD);
+
+	/*
+	 * Ensure that hardware is put in low power mode before
+	 * clocks are turned OFF and VDD is allowed to minimize.
+	 */
+	mb();
+
+	clk_disable_unprepare(mhcd->iface_clk);
+	clk_disable_unprepare(mhcd->core_clk);
+
+	msm_ehci_config_vddcx(mhcd, 0);
+
+	atomic_set(&mhcd->in_lpm, 1);
+	enable_irq(hcd->irq);
+	wake_unlock(&mhcd->wlock);
+
+	dev_info(mhcd->dev, "EHCI USB in low power mode\n");
+
+	return 0;
+}
+
+static int msm_ehci_resume(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+	unsigned temp;
+
+	if (!atomic_read(&mhcd->in_lpm)) {
+		dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
+		return 0;
+	}
+
+	wake_lock(&mhcd->wlock);
+
+	clk_prepare_enable(mhcd->core_clk);
+	clk_prepare_enable(mhcd->iface_clk);
+
+	msm_ehci_config_vddcx(mhcd, 1);
+
+	temp = readl_relaxed(USB_USBCMD);
+	temp &= ~ASYNC_INTR_CTRL;
+	temp &= ~ULPI_STP_CTRL;
+	writel_relaxed(temp, USB_USBCMD);
+
+	if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+		goto skip_phy_resume;
+
+	temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
+	writel_relaxed(temp, USB_PORTSC);
+
+	timeout = jiffies + usecs_to_jiffies(PHY_RESUME_TIMEOUT_USEC);
+	while ((readl_relaxed(USB_PORTSC) & PORTSC_PHCD) ||
+			!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE)) {
+		if (time_after(jiffies, timeout)) {
+			/*This is a fatal error. Reset the link and PHY*/
+			dev_err(mhcd->dev, "Unable to resume USB. Resetting the h/w\n");
+			msm_hsusb_reset(mhcd);
+			break;
+		}
+		udelay(1);
+	}
+
+skip_phy_resume:
+
+	atomic_set(&mhcd->in_lpm, 0);
+
+	if (mhcd->async_int) {
+		mhcd->async_int = false;
+		pm_runtime_put_noidle(mhcd->dev);
+		enable_irq(hcd->irq);
+	}
+
+	dev_info(mhcd->dev, "EHCI USB exited from low power mode\n");
+
+	return 0;
+}
+#endif
+
+static irqreturn_t msm_ehci_irq(struct usb_hcd *hcd)
+{
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	if (atomic_read(&mhcd->in_lpm)) {
+		disable_irq_nosync(hcd->irq);
+		mhcd->async_int = true;
+		pm_runtime_get(mhcd->dev);
+		return IRQ_HANDLED;
+	}
+
+	return ehci_irq(hcd);
+}
+
+static int msm_ehci_reset(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int retval;
+
+	ehci->caps = USB_CAPLENGTH;
+	ehci->regs = USB_CAPLENGTH +
+		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	/* cache the data to minimize the chip reads*/
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+	hcd->has_tt = 1;
+	ehci->sbrn = HCD_USB2;
+
+	retval = ehci_halt(ehci);
+	if (retval)
+		return retval;
+
+	/* data structure init */
+	retval = ehci_init(hcd);
+	if (retval)
+		return retval;
+
+	retval = ehci_reset(ehci);
+	if (retval)
+		return retval;
+
+	/* bursts of unspecified length. */
+	writel_relaxed(0, USB_AHBBURST);
+	/* Use the AHB transactor */
+	writel_relaxed(0x08, USB_AHBMODE);
+	/* Disable streaming mode and select host mode */
+	writel_relaxed(0x13, USB_USBMODE);
+
+	ehci_port_power(ehci, 1);
+	return 0;
+}
+
+static struct hc_driver msm_hc2_driver = {
+	.description		= hcd_name,
+	.product_desc		= "Qualcomm EHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct msm_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq			= msm_ehci_irq,
+	.flags			= HCD_USB2 | HCD_MEMORY,
+
+	.reset			= msm_ehci_reset,
+	.start			= ehci_run,
+
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.endpoint_reset		= ehci_endpoint_reset,
+	.clear_tt_buffer_complete	 = ehci_clear_tt_buffer_complete,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number	= ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	/*
+	 * PM support
+	 */
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+};
+
+static int msm_ehci_init_clocks(struct msm_hcd *mhcd, u32 init)
+{
+	int ret = 0;
+
+	if (!init)
+		goto put_clocks;
+
+	/* 60MHz alt_core_clk is for LINK to be used during PHY RESET  */
+	mhcd->alt_core_clk = clk_get(mhcd->dev, "alt_core_clk");
+	if (IS_ERR(mhcd->alt_core_clk)) {
+		dev_err(mhcd->dev, "failed to get alt_core_clk\n");
+		ret = PTR_ERR(mhcd->alt_core_clk);
+		return ret;
+	}
+	clk_set_rate(mhcd->alt_core_clk, 60000000);
+
+	/* iface_clk is required for data transfers */
+	mhcd->iface_clk = clk_get(mhcd->dev, "iface_clk");
+	if (IS_ERR(mhcd->iface_clk)) {
+		dev_err(mhcd->dev, "failed to get iface_clk\n");
+		ret = PTR_ERR(mhcd->iface_clk);
+		goto put_alt_core_clk;
+	}
+
+	/* Link's protocol engine is based on pclk which must
+	 * be running >55Mhz and frequency should also not change.
+	 * Hence, vote for maximum clk frequency on its source
+	 */
+	mhcd->core_clk = clk_get(mhcd->dev, "core_clk");
+	if (IS_ERR(mhcd->core_clk)) {
+		dev_err(mhcd->dev, "failed to get core_clk\n");
+		ret = PTR_ERR(mhcd->core_clk);
+		goto put_iface_clk;
+	}
+	clk_set_rate(mhcd->core_clk, INT_MAX);
+
+	clk_prepare_enable(mhcd->core_clk);
+	clk_prepare_enable(mhcd->iface_clk);
+
+	return 0;
+
+put_clocks:
+	clk_disable_unprepare(mhcd->iface_clk);
+	clk_disable_unprepare(mhcd->core_clk);
+	clk_put(mhcd->core_clk);
+put_iface_clk:
+	clk_put(mhcd->iface_clk);
+put_alt_core_clk:
+	clk_put(mhcd->alt_core_clk);
+
+	return ret;
+}
+
+static int __devinit ehci_msm2_probe(struct platform_device *pdev)
+{
+	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");
+
+	hcd = usb_create_hcd(&msm_hc2_driver, &pdev->dev,
+				dev_name(&pdev->dev));
+	if (!hcd) {
+		dev_err(&pdev->dev, "Unable to create HCD\n");
+		return  -ENOMEM;
+	}
+
+	hcd->irq = platform_get_irq(pdev, 0);
+	if (hcd->irq < 0) {
+		dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+		ret = hcd->irq;
+		goto put_hcd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Unable to get memory resource\n");
+		ret = -ENODEV;
+		goto put_hcd;
+	}
+
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto put_hcd;
+	}
+
+	mhcd = hcd_to_mhcd(hcd);
+	mhcd->dev = &pdev->dev;
+
+	ret = msm_ehci_init_clocks(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to initialize clocks\n");
+		ret = -ENODEV;
+		goto unmap;
+	}
+
+	ret = msm_ehci_init_vddcx(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to initialize VDDCX\n");
+		ret = -ENODEV;
+		goto deinit_clocks;
+	}
+
+	ret = msm_ehci_config_vddcx(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
+		goto deinit_vddcx;
+	}
+
+	ret = msm_ehci_ldo_init(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
+		goto deinit_vddcx;
+	}
+
+	ret = msm_ehci_ldo_enable(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg enable failed\n");
+		goto deinit_ldo;
+	}
+
+	ret = msm_ehci_init_vbus(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to get vbus\n");
+		goto disable_ldo;
+	}
+
+	ret = msm_hsusb_reset(mhcd);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb PHY initialization failed\n");
+		goto vbus_deinit;
+	}
+
+	ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register HCD\n");
+		goto vbus_deinit;
+	}
+
+	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));
+	wake_lock(&mhcd->wlock);
+	/*
+	 * This pdev->dev is assigned parent of root-hub by USB core,
+	 * hence, runtime framework automatically calls this driver's
+	 * runtime APIs based on root-hub's state.
+	 */
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+vbus_deinit:
+	msm_ehci_init_vbus(mhcd, 0);
+disable_ldo:
+	msm_ehci_ldo_enable(mhcd, 0);
+deinit_ldo:
+	msm_ehci_ldo_init(mhcd, 0);
+deinit_vddcx:
+	msm_ehci_init_vddcx(mhcd, 0);
+deinit_clocks:
+	msm_ehci_init_clocks(mhcd, 0);
+unmap:
+	iounmap(hcd->regs);
+put_hcd:
+	usb_put_hcd(hcd);
+
+	return ret;
+}
+
+static int __devexit ehci_msm2_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	device_init_wakeup(&pdev->dev, 0);
+	pm_runtime_disable(&pdev->dev);
+	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);
+	msm_ehci_ldo_init(mhcd, 0);
+	msm_ehci_init_vddcx(mhcd, 0);
+
+	msm_ehci_init_clocks(mhcd, 0);
+	wake_lock_destroy(&mhcd->wlock);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ehci_msm2_pm_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "ehci-msm2 PM suspend\n");
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(hcd->irq);
+
+	return msm_ehci_suspend(mhcd);
+
+}
+
+static int ehci_msm2_pm_resume(struct device *dev)
+{
+	int ret;
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "ehci-msm2 PM resume\n");
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(hcd->irq);
+
+	ret = msm_ehci_resume(mhcd);
+	if (ret)
+		return ret;
+
+	/* Bring the device to full powered state upon system resume */
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int ehci_msm2_runtime_idle(struct device *dev)
+{
+	dev_dbg(dev, "EHCI runtime idle\n");
+
+	return 0;
+}
+
+static int ehci_msm2_runtime_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "EHCI runtime suspend\n");
+	return msm_ehci_suspend(mhcd);
+}
+
+static int ehci_msm2_runtime_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "EHCI runtime resume\n");
+	return msm_ehci_resume(mhcd);
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops ehci_msm2_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(ehci_msm2_pm_suspend, ehci_msm2_pm_resume)
+	SET_RUNTIME_PM_OPS(ehci_msm2_runtime_suspend, ehci_msm2_runtime_resume,
+				ehci_msm2_runtime_idle)
+};
+#endif
+
+static struct platform_driver ehci_msm2_driver = {
+	.probe	= ehci_msm2_probe,
+	.remove	= __devexit_p(ehci_msm2_remove),
+	.driver = {
+		.name = "msm_ehci_host",
+#ifdef CONFIG_PM
+		.pm = &ehci_msm2_dev_pm_ops,
+#endif
+	},
+};
diff --git a/drivers/usb/host/ehci-msm72k.c b/drivers/usb/host/ehci-msm72k.c
index b3939ef..bf2cbd1 100644
--- a/drivers/usb/host/ehci-msm72k.c
+++ b/drivers/usb/host/ehci-msm72k.c
@@ -605,19 +605,6 @@
 	return retval;
 }
 
-#ifdef	CONFIG_USB_OTG
-static void ehci_msm_start_hnp(struct ehci_hcd *ehci)
-{
-	struct usb_hcd *hcd = ehci_to_hcd(ehci);
-	struct msmusb_hcd *mhcd = hcd_to_mhcd(hcd);
-
-	/* OTG driver handles HNP */
-	otg_start_hnp(mhcd->xceiv);
-}
-#else
-#define ehci_msm_start_hnp	NULL
-#endif
-
 static int msm_xusb_init_host(struct platform_device *pdev,
 			      struct msmusb_hcd *mhcd)
 {
@@ -645,9 +632,9 @@
 		otg = container_of(mhcd->xceiv, struct msm_otg, otg);
 		hcd->regs = otg->regs;
 		otg->start_host = msm_hsusb_start_host;
-		ehci->start_hnp = ehci_msm_start_hnp;
 
 		ret = otg_set_host(mhcd->xceiv, &hcd->self);
+		ehci->transceiver = mhcd->xceiv;
 		break;
 	case USB_PHY_SERIAL_PMIC:
 		hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
@@ -753,6 +740,7 @@
 	case USB_PHY_INTEGRATED:
 		if (pdata->vbus_init)
 			pdata->vbus_init(0);
+		hcd_to_ehci(hcd)->transceiver = NULL;
 		otg_set_host(mhcd->xceiv, NULL);
 		otg_put_transceiver(mhcd->xceiv);
 		cancel_work_sync(&mhcd->otg_work);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 1102ce6..1d1caa6 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -224,6 +224,11 @@
 			pci_dev_put(p_smbus);
 		}
 		break;
+	case PCI_VENDOR_ID_NETMOS:
+		/* MosChip frame-index-register bug */
+		ehci_info(ehci, "applying MosChip frame-index workaround\n");
+		ehci->frame_index_bug = 1;
+		break;
 	}
 
 	/* optional debug port, normally in the first BAR */
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 9c24ff4..57ab83e 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -649,7 +649,7 @@
 	/*
 	 * data transfer stage:  buffer setup
 	 */
-	i = urb->num_sgs;
+	i = urb->num_mapped_sgs;
 	if (len > 0 && i > 0) {
 		sg = urb->sg;
 		buf = sg_dma_address(sg);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 6c9fbe3..8949b23 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -36,6 +36,27 @@
 
 static int ehci_get_frame (struct usb_hcd *hcd);
 
+#ifdef CONFIG_PCI
+
+static unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
+{
+	unsigned uf;
+
+	/*
+	 * The MosChip MCS9990 controller updates its microframe counter
+	 * a little before the frame counter, and occasionally we will read
+	 * the invalid intermediate value.  Avoid problems by checking the
+	 * microframe number (the low-order 3 bits); if they are 0 then
+	 * re-read the register to get the correct value.
+	 */
+	uf = ehci_readl(ehci, &ehci->regs->frame_index);
+	if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0)))
+		uf = ehci_readl(ehci, &ehci->regs->frame_index);
+	return uf;
+}
+
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -482,7 +503,7 @@
 	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
 	/* make sure ehci_work scans these */
-	ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+	ehci->next_uframe = ehci_read_frame_index(ehci)
 		% (ehci->periodic_size << 3);
 	if (unlikely(ehci->broken_periodic))
 		ehci->last_periodic_enable = ktime_get_real();
@@ -1412,7 +1433,7 @@
 		goto fail;
 	}
 
-	now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
+	now = ehci_read_frame_index(ehci) & (mod - 1);
 
 	/* Typical case: reuse current schedule, stream is still active.
 	 * Hopefully there are no gaps from the host falling behind
@@ -1458,30 +1479,36 @@
 	 * jump until after the queue is primed.
 	 */
 	else {
+		int done = 0;
 		start = SCHEDULE_SLOP + (now & ~0x07);
 
 		/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
 
-		/* find a uframe slot with enough bandwidth */
-		next = start + period;
-		for (; start < next; start++) {
-
+		/* find a uframe slot with enough bandwidth.
+		 * Early uframes are more precious because full-speed
+		 * iso IN transfers can't use late uframes,
+		 * and therefore they should be allocated last.
+		 */
+		next = start;
+		start += period;
+		do {
+			start--;
 			/* check schedule: enough space? */
 			if (stream->highspeed) {
 				if (itd_slot_ok(ehci, mod, start,
 						stream->usecs, period))
-					break;
+					done = 1;
 			} else {
 				if ((start % 8) >= 6)
 					continue;
 				if (sitd_slot_ok(ehci, mod, stream,
 						start, sched, period))
-					break;
+					done = 1;
 			}
-		}
+		} while (start > next && !done);
 
 		/* no room in the schedule */
-		if (start == next) {
+		if (!done) {
 			ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n",
 				urb, now, now + mod);
 			status = -ENOSPC;
@@ -2279,7 +2306,7 @@
 	 */
 	now_uframe = ehci->next_uframe;
 	if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
-		clock = ehci_readl(ehci, &ehci->regs->frame_index);
+		clock = ehci_read_frame_index(ehci);
 		clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
 	} else  {
 		clock = now_uframe + mod - 1;
@@ -2458,8 +2485,7 @@
 					|| ehci->periodic_sched == 0)
 				break;
 			ehci->next_uframe = now_uframe;
-			now = ehci_readl(ehci, &ehci->regs->frame_index) &
-					(mod - 1);
+			now = ehci_read_frame_index(ehci) & (mod - 1);
 			if (now_uframe == now)
 				break;
 
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 05c7faf..3a5a5cc 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -124,8 +124,6 @@
 	ktime_t			last_periodic_enable;
 	u32			command;
 
-	void (*start_hnp)(struct ehci_hcd *ehci);
-
 	/* SILICON QUIRKS */
 	unsigned		no_selective_suspend:1;
 	unsigned		has_fsl_port_bug:1; /* FreeScale */
@@ -139,6 +137,7 @@
 	unsigned		fs_i_thresh:1;	/* Intel iso scheduling */
 	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/
 	unsigned		has_synopsys_hc_bug:1; /* Synopsys HC */
+	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
 
 	/* required for usb32 quirk */
 	#define OHCI_CTRL_HCFS          (3 << 6)
@@ -757,6 +756,22 @@
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_PCI
+
+/* For working around the MosChip frame-index-register bug */
+static unsigned ehci_read_frame_index(struct ehci_hcd *ehci);
+
+#else
+
+static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
+{
+	return ehci_readl(ehci, &ehci->regs->frame_index);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 #ifndef DEBUG
 #define STUB_DEBUG_FILES
 #endif	/* DEBUG */
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index a42ef38..2df851b 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -1,7 +1,7 @@
 /*
  * Freescale QUICC Engine USB Host Controller Driver
  *
- * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Copyright (c) Freescale Semicondutor, Inc. 2006, 2011.
  *               Shlomi Gridish <gridish@freescale.com>
  *               Jerry Huang <Chang-Ming.Huang@freescale.com>
  * Copyright (c) Logic Product Development, Inc. 2007
@@ -810,9 +810,11 @@
 		ed->dev_addr = usb_pipedevice(urb->pipe);
 		ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe,
 			usb_pipeout(urb->pipe));
+		/* setup stage */
 		td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP,
 			USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true);
 
+		/* data stage */
 		if (data_len > 0) {
 			td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
 				usb_pipeout(urb->pipe) ? FHCI_TA_OUT :
@@ -820,9 +822,18 @@
 				USB_TD_TOGGLE_DATA1, data, data_len, 0, 0,
 				true);
 		}
-		td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
-			usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT,
-			USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
+
+		/* status stage */
+		if (data_len > 0)
+			td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
+				(usb_pipeout(urb->pipe) ? FHCI_TA_IN :
+							  FHCI_TA_OUT),
+				USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
+		else
+			 td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
+				FHCI_TA_IN,
+				USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
+
 		urb_state = US_CTRL_SETUP;
 		break;
 	case FHCI_TF_ISO:
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 55d3d58..840beda 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -1583,6 +1583,9 @@
 	int retval = 0;
 
 	spin_lock_irqsave(&priv->lock, spinflags);
+	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (retval)
+		goto out;
 
 	qh = urb->ep->hcpriv;
 	if (!qh) {
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f9cf3f0..23107e2 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -389,17 +389,14 @@
 	struct ohci_hcd *ohci;
 
 	ohci = hcd_to_ohci (hcd);
-	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-	ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
+	ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable);
 
-	/* If the SHUTDOWN quirk is set, don't put the controller in RESET */
-	ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ?
-			OHCI_CTRL_RWC | OHCI_CTRL_HCFS :
-			OHCI_CTRL_RWC);
-	ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
+	/* Software reset, after which the controller goes into SUSPEND */
+	ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus);
+	ohci_readl(ohci, &ohci->regs->cmdstatus);	/* flush the writes */
+	udelay(10);
 
-	/* flush the writes */
-	(void) ohci_readl (ohci, &ohci->regs->control);
+	ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval);
 }
 
 static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 9154615..2f00040 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -356,10 +356,7 @@
 		msleep(20);
 	}
 
-	/* Does the root hub have a port wakeup pending? */
-	if (ohci_readl(ohci, &ohci->regs->intrstatus) &
-			(OHCI_INTR_RD | OHCI_INTR_RHSC))
-		usb_hcd_resume_root_hub(hcd);
+	usb_hcd_resume_root_hub(hcd);
 }
 
 /* Carry out polling-, autostop-, and autoresume-related state changes */
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index ad8166c..bc01b06 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -175,28 +175,6 @@
 	return 0;
 }
 
-/* nVidia controllers continue to drive Reset signalling on the bus
- * even after system shutdown, wasting power.  This flag tells the
- * shutdown routine to leave the controller OPERATIONAL instead of RESET.
- */
-static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
-{
-	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
-	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
-
-	/* Evidently nVidia fixed their later hardware; this is a guess at
-	 * the changeover point.
-	 */
-#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB		0x026d
-
-	if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) {
-		ohci->flags |= OHCI_QUIRK_SHUTDOWN;
-		ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
-	}
-
-	return 0;
-}
-
 static void sb800_prefetch(struct ohci_hcd *ohci, int on)
 {
 	struct pci_dev *pdev;
@@ -260,10 +238,6 @@
 		PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399),
 		.driver_data = (unsigned long)ohci_quirk_amd700,
 	},
-	{
-		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
-		.driver_data = (unsigned long) ohci_quirk_nvidia_shutdown,
-	},
 
 	/* FIXME for some of the early AMD 760 southbridges, OHCI
 	 * won't work at all.  blacklist them.
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 35e5fd6..0795b93 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -403,7 +403,6 @@
 #define	OHCI_QUIRK_HUB_POWER	0x100			/* distrust firmware power/oc setup */
 #define	OHCI_QUIRK_AMD_PLL	0x200			/* AMD PLL quirk*/
 #define	OHCI_QUIRK_AMD_PREFETCH	0x400			/* pre-fetch for ISO transfer */
-#define	OHCI_QUIRK_SHUTDOWN	0x800			/* nVidia power bug */
 	// there are also chip quirks/bugs in init logic
 
 	struct work_struct	nec_work;	/* Worker for NEC quirk */
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 629a968..20f2f21 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -36,6 +36,7 @@
 #define OHCI_INTRENABLE		0x10
 #define OHCI_INTRDISABLE	0x14
 #define OHCI_FMINTERVAL		0x34
+#define OHCI_HCFS		(3 << 6)	/* hc functional state */
 #define OHCI_HCR		(1 << 0)	/* host controller reset */
 #define OHCI_OCR		(1 << 3)	/* ownership change request */
 #define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
@@ -465,6 +466,8 @@
 {
 	void __iomem *base;
 	u32 control;
+	u32 fminterval;
+	int cnt;
 
 	if (!mmio_resource_enabled(pdev, 0))
 		return;
@@ -497,41 +500,32 @@
 	}
 #endif
 
-	/* reset controller, preserving RWC (and possibly IR) */
-	writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
-	readl(base + OHCI_CONTROL);
+	/* disable interrupts */
+	writel((u32) ~0, base + OHCI_INTRDISABLE);
 
-	/* Some NVIDIA controllers stop working if kept in RESET for too long */
-	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
-		u32 fminterval;
-		int cnt;
+	/* Reset the USB bus, if the controller isn't already in RESET */
+	if (control & OHCI_HCFS) {
+		/* Go into RESET, preserving RWC (and possibly IR) */
+		writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
+		readl(base + OHCI_CONTROL);
 
-		/* drive reset for at least 50 ms (7.1.7.5) */
+		/* drive bus reset for at least 50 ms (7.1.7.5) */
 		msleep(50);
-
-		/* software reset of the controller, preserving HcFmInterval */
-		fminterval = readl(base + OHCI_FMINTERVAL);
-		writel(OHCI_HCR, base + OHCI_CMDSTATUS);
-
-		/* reset requires max 10 us delay */
-		for (cnt = 30; cnt > 0; --cnt) {	/* ... allow extra time */
-			if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
-				break;
-			udelay(1);
-		}
-		writel(fminterval, base + OHCI_FMINTERVAL);
-
-		/* Now we're in the SUSPEND state with all devices reset
-		 * and wakeups and interrupts disabled
-		 */
 	}
 
-	/*
-	 * disable interrupts
-	 */
-	writel(~(u32)0, base + OHCI_INTRDISABLE);
-	writel(~(u32)0, base + OHCI_INTRSTATUS);
+	/* software reset of the controller, preserving HcFmInterval */
+	fminterval = readl(base + OHCI_FMINTERVAL);
+	writel(OHCI_HCR, base + OHCI_CMDSTATUS);
 
+	/* reset requires max 10 us delay */
+	for (cnt = 30; cnt > 0; --cnt) {	/* ... allow extra time */
+		if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
+			break;
+		udelay(1);
+	}
+	writel(fminterval, base + OHCI_FMINTERVAL);
+
+	/* Now the controller is safely in SUSPEND and nothing can wake it up */
 	iounmap(base);
 }
 
@@ -626,7 +620,7 @@
 	void __iomem *base, *op_reg_base;
 	u32	hcc_params, cap, val;
 	u8	offset, cap_length;
-	int	wait_time, delta, count = 256/4;
+	int	wait_time, count = 256/4;
 
 	if (!mmio_resource_enabled(pdev, 0))
 		return;
@@ -672,11 +666,10 @@
 		writel(val, op_reg_base + EHCI_USBCMD);
 
 		wait_time = 2000;
-		delta = 100;
 		do {
 			writel(0x3f, op_reg_base + EHCI_USBSTS);
-			udelay(delta);
-			wait_time -= delta;
+			udelay(100);
+			wait_time -= 100;
 			val = readl(op_reg_base + EHCI_USBSTS);
 			if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
 				break;
@@ -873,6 +866,12 @@
 
 static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
 {
+	/* Skip Netlogic mips SoC's internal PCI USB controller.
+	 * This device does not need/support EHCI/OHCI handoff
+	 */
+	if (pdev->vendor == 0x184e)	/* vendor Netlogic */
+		return;
+
 	if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
 		quirk_usb_handoff_uhci(pdev);
 	else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI)
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 84ed28b..8253991 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -943,7 +943,7 @@
 	if (usb_pipein(urb->pipe))
 		status |= TD_CTRL_SPD;
 
-	i = urb->num_sgs;
+	i = urb->num_mapped_sgs;
 	if (len > 0 && i > 0) {
 		sg = urb->sg;
 		data = sg_dma_address(sg);
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index d6e1754..76083ae 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -124,7 +124,7 @@
 {
 	qset->td_start = qset->td_end = qset->ntds = 0;
 
-	qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T);
+	qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
 	qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
 	qset->qh.err_count = 0;
 	qset->qh.scratch[0] = 0;
@@ -443,7 +443,7 @@
 
 	remaining = urb->transfer_buffer_length;
 
-	for_each_sg(urb->sg, sg, urb->num_sgs, i) {
+	for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
 		dma_addr_t dma_addr;
 		size_t dma_remaining;
 		dma_addr_t sp, ep;
@@ -561,7 +561,7 @@
 
 	remaining = urb->transfer_buffer_length;
 
-	for_each_sg(urb->sg, sg, urb->num_sgs, i) {
+	for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
 		size_t len;
 		size_t sg_remaining;
 		void *orig;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 723f823..ce9f974 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -392,6 +392,20 @@
 	return max_ports;
 }
 
+/* Test and clear port RWC bit */
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+				int port_id, u32 port_bit)
+{
+	u32 temp;
+
+	temp = xhci_readl(xhci, port_array[port_id]);
+	if (temp & port_bit) {
+		temp = xhci_port_state_to_neutral(temp);
+		temp |= port_bit;
+		xhci_writel(xhci, temp, port_array[port_id]);
+	}
+}
+
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 		u16 wIndex, char *buf, u16 wLength)
 {
@@ -938,12 +952,8 @@
 			spin_lock_irqsave(&xhci->lock, flags);
 
 			/* Clear PLC */
-			temp = xhci_readl(xhci, port_array[port_index]);
-			if (temp & PORT_PLC) {
-				temp = xhci_port_state_to_neutral(temp);
-				temp |= PORT_PLC;
-				xhci_writel(xhci, temp, port_array[port_index]);
-			}
+			xhci_test_and_clear_bit(xhci, port_array, port_index,
+						PORT_PLC);
 
 			slot_id = xhci_find_slot_id_by_port(hcd,
 					xhci, port_index + 1);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index fcb7f7e..ffeee57 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -81,7 +81,7 @@
  * related flags, such as End TRB, Toggle Cycle, and no snoop.
  */
 static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
-		struct xhci_segment *next, bool link_trbs)
+		struct xhci_segment *next, bool link_trbs, bool isoc)
 {
 	u32 val;
 
@@ -97,7 +97,9 @@
 		val &= ~TRB_TYPE_BITMASK;
 		val |= TRB_TYPE(TRB_LINK);
 		/* Always set the chain bit with 0.95 hardware */
-		if (xhci_link_trb_quirk(xhci))
+		/* Set chain bit for isoc rings on AMD 0.96 host */
+		if (xhci_link_trb_quirk(xhci) ||
+				(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)))
 			val |= TRB_CHAIN;
 		prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
 	}
@@ -112,18 +114,20 @@
 	struct xhci_segment *seg;
 	struct xhci_segment *first_seg;
 
-	if (!ring || !ring->first_seg)
+	if (!ring)
 		return;
-	first_seg = ring->first_seg;
-	seg = first_seg->next;
-	xhci_dbg(xhci, "Freeing ring at %p\n", ring);
-	while (seg != first_seg) {
-		struct xhci_segment *next = seg->next;
-		xhci_segment_free(xhci, seg);
-		seg = next;
+	if (ring->first_seg) {
+		first_seg = ring->first_seg;
+		seg = first_seg->next;
+		xhci_dbg(xhci, "Freeing ring at %p\n", ring);
+		while (seg != first_seg) {
+			struct xhci_segment *next = seg->next;
+			xhci_segment_free(xhci, seg);
+			seg = next;
+		}
+		xhci_segment_free(xhci, first_seg);
+		ring->first_seg = NULL;
 	}
-	xhci_segment_free(xhci, first_seg);
-	ring->first_seg = NULL;
 	kfree(ring);
 }
 
@@ -152,7 +156,7 @@
  * See section 4.9.1 and figures 15 and 16.
  */
 static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
-		unsigned int num_segs, bool link_trbs, gfp_t flags)
+		unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
 {
 	struct xhci_ring	*ring;
 	struct xhci_segment	*prev;
@@ -178,12 +182,12 @@
 		next = xhci_segment_alloc(xhci, flags);
 		if (!next)
 			goto fail;
-		xhci_link_segments(xhci, prev, next, link_trbs);
+		xhci_link_segments(xhci, prev, next, link_trbs, isoc);
 
 		prev = next;
 		num_segs--;
 	}
-	xhci_link_segments(xhci, prev, ring->first_seg, link_trbs);
+	xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc);
 
 	if (link_trbs) {
 		/* See section 4.9.2.1 and 6.4.4.1 */
@@ -229,14 +233,14 @@
  * pointers to the beginning of the ring.
  */
 static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
-		struct xhci_ring *ring)
+		struct xhci_ring *ring, bool isoc)
 {
 	struct xhci_segment	*seg = ring->first_seg;
 	do {
 		memset(seg->trbs, 0,
 				sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
 		/* All endpoint rings have link TRBs */
-		xhci_link_segments(xhci, seg, seg->next, 1);
+		xhci_link_segments(xhci, seg, seg->next, 1, isoc);
 		seg = seg->next;
 	} while (seg != ring->first_seg);
 	xhci_initialize_ring_info(ring);
@@ -540,7 +544,7 @@
 	 */
 	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
 		stream_info->stream_rings[cur_stream] =
-			xhci_ring_alloc(xhci, 1, true, mem_flags);
+			xhci_ring_alloc(xhci, 1, true, false, mem_flags);
 		cur_ring = stream_info->stream_rings[cur_stream];
 		if (!cur_ring)
 			goto cleanup_rings;
@@ -765,7 +769,7 @@
 	}
 
 	/* Allocate endpoint 0 ring */
-	dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, flags);
+	dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags);
 	if (!dev->eps[0].ring)
 		goto fail;
 
@@ -871,7 +875,6 @@
 	struct xhci_virt_device *dev;
 	struct xhci_ep_ctx	*ep0_ctx;
 	struct xhci_slot_ctx    *slot_ctx;
-	struct xhci_input_control_ctx *ctrl_ctx;
 	u32			port_num;
 	struct usb_device *top_dev;
 
@@ -883,12 +886,8 @@
 		return -EINVAL;
 	}
 	ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0);
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx);
 	slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx);
 
-	/* 2) New slot context and endpoint 0 context are valid*/
-	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
-
 	/* 3) Only the control endpoint is valid - one endpoint context */
 	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route);
 	switch (udev->speed) {
@@ -1175,10 +1174,10 @@
 	 */
 	if (usb_endpoint_xfer_isoc(&ep->desc))
 		virt_dev->eps[ep_index].new_ring =
-			xhci_ring_alloc(xhci, 8, true, mem_flags);
+			xhci_ring_alloc(xhci, 8, true, true, mem_flags);
 	else
 		virt_dev->eps[ep_index].new_ring =
-			xhci_ring_alloc(xhci, 1, true, mem_flags);
+			xhci_ring_alloc(xhci, 1, true, false, mem_flags);
 	if (!virt_dev->eps[ep_index].new_ring) {
 		/* Attempt to use the ring cache */
 		if (virt_dev->num_rings_cached == 0)
@@ -1187,7 +1186,8 @@
 			virt_dev->ring_cache[virt_dev->num_rings_cached];
 		virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
 		virt_dev->num_rings_cached--;
-		xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring);
+		xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
+			usb_endpoint_xfer_isoc(&ep->desc) ? true : false);
 	}
 	virt_dev->eps[ep_index].skip = false;
 	ep_ring = virt_dev->eps[ep_index].new_ring;
@@ -2001,7 +2001,7 @@
 		goto fail;
 
 	/* Set up the command ring to have one segments for now. */
-	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags);
+	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
 	if (!xhci->cmd_ring)
 		goto fail;
 	xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
@@ -2032,7 +2032,8 @@
 	 * the event ring segment table (ERST).  Section 4.9.3.
 	 */
 	xhci_dbg(xhci, "// Allocating event ring\n");
-	xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags);
+	xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false,
+						flags);
 	if (!xhci->event_ring)
 		goto fail;
 	if (xhci_check_trb_in_td_math(xhci, flags) < 0)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index cb16de2..50e7156 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -128,6 +128,9 @@
 	if (pdev->vendor == PCI_VENDOR_ID_NEC)
 		xhci->quirks |= XHCI_NEC_HOST;
 
+	if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96)
+		xhci->quirks |= XHCI_AMD_0x96_HOST;
+
 	/* AMD PLL quirk */
 	if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
 		xhci->quirks |= XHCI_AMD_PLL_FIX;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d0871ea..edcedc4 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -187,7 +187,7 @@
  *			prepare_transfer()?
  */
 static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
-		bool consumer, bool more_trbs_coming)
+		bool consumer, bool more_trbs_coming, bool isoc)
 {
 	u32 chain;
 	union xhci_trb *next;
@@ -214,11 +214,13 @@
 				if (!chain && !more_trbs_coming)
 					break;
 
-				/* If we're not dealing with 0.95 hardware,
+				/* If we're not dealing with 0.95 hardware or
+				 * isoc rings on AMD 0.96 host,
 				 * carry over the chain bit of the previous TRB
 				 * (which may mean the chain bit is cleared).
 				 */
-				if (!xhci_link_trb_quirk(xhci)) {
+				if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))
+						&& !xhci_link_trb_quirk(xhci)) {
 					next->link.control &=
 						cpu_to_le32(~TRB_CHAIN);
 					next->link.control |=
@@ -817,23 +819,24 @@
 	struct xhci_ring *ring;
 	struct xhci_td *cur_td;
 	int ret, i, j;
+	unsigned long flags;
 
 	ep = (struct xhci_virt_ep *) arg;
 	xhci = ep->xhci;
 
-	spin_lock(&xhci->lock);
+	spin_lock_irqsave(&xhci->lock, flags);
 
 	ep->stop_cmds_pending--;
 	if (xhci->xhc_state & XHCI_STATE_DYING) {
 		xhci_dbg(xhci, "Stop EP timer ran, but another timer marked "
 				"xHCI as DYING, exiting.\n");
-		spin_unlock(&xhci->lock);
+		spin_unlock_irqrestore(&xhci->lock, flags);
 		return;
 	}
 	if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
 		xhci_dbg(xhci, "Stop EP timer ran, but no command pending, "
 				"exiting.\n");
-		spin_unlock(&xhci->lock);
+		spin_unlock_irqrestore(&xhci->lock, flags);
 		return;
 	}
 
@@ -845,11 +848,11 @@
 	xhci->xhc_state |= XHCI_STATE_DYING;
 	/* Disable interrupts from the host controller and start halting it */
 	xhci_quiesce(xhci);
-	spin_unlock(&xhci->lock);
+	spin_unlock_irqrestore(&xhci->lock, flags);
 
 	ret = xhci_halt(xhci);
 
-	spin_lock(&xhci->lock);
+	spin_lock_irqsave(&xhci->lock, flags);
 	if (ret < 0) {
 		/* This is bad; the host is not responding to commands and it's
 		 * not allowing itself to be halted.  At least interrupts are
@@ -897,7 +900,7 @@
 			}
 		}
 	}
-	spin_unlock(&xhci->lock);
+	spin_unlock_irqrestore(&xhci->lock, flags);
 	xhci_dbg(xhci, "Calling usb_hc_died()\n");
 	usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
 	xhci_dbg(xhci, "xHCI host controller is dead.\n");
@@ -1215,6 +1218,7 @@
  *
  * Returns a zero-based port number, which is suitable for indexing into each of
  * the split roothubs' port arrays and bus state arrays.
+ * Add one to it in order to call xhci_find_slot_id_by_port.
  */
 static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
 		struct xhci_hcd *xhci, u32 port_id)
@@ -1337,7 +1341,7 @@
 			temp |= PORT_LINK_STROBE | XDEV_U0;
 			xhci_writel(xhci, temp, port_array[faked_port_index]);
 			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-					faked_port_index);
+					faked_port_index + 1);
 			if (!slot_id) {
 				xhci_dbg(xhci, "slot_id is zero\n");
 				goto cleanup;
@@ -1345,10 +1349,8 @@
 			xhci_ring_device(xhci, slot_id);
 			xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
 			/* Clear PORT_PLC */
-			temp = xhci_readl(xhci, port_array[faked_port_index]);
-			temp = xhci_port_state_to_neutral(temp);
-			temp |= PORT_PLC;
-			xhci_writel(xhci, temp, port_array[faked_port_index]);
+			xhci_test_and_clear_bit(xhci, port_array,
+						faked_port_index, PORT_PLC);
 		} else {
 			xhci_dbg(xhci, "resume HS port %d\n", port_id);
 			bus_state->resume_done[faked_port_index] = jiffies +
@@ -1359,6 +1361,10 @@
 		}
 	}
 
+	if (hcd->speed != HCD_USB3)
+		xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
+					PORT_PLC);
+
 cleanup:
 	/* Update event ring dequeue pointer before dropping the lock */
 	inc_deq(xhci, xhci->event_ring, true);
@@ -1940,8 +1946,10 @@
 	int status = -EINPROGRESS;
 	struct urb_priv *urb_priv;
 	struct xhci_ep_ctx *ep_ctx;
+	struct list_head *tmp;
 	u32 trb_comp_code;
 	int ret = 0;
+	int td_num = 0;
 
 	slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
 	xdev = xhci->devs[slot_id];
@@ -1963,6 +1971,12 @@
 		return -ENODEV;
 	}
 
+	/* Count current td numbers if ep->skip is set */
+	if (ep->skip) {
+		list_for_each(tmp, &ep_ring->td_list)
+			td_num++;
+	}
+
 	event_dma = le64_to_cpu(event->buffer);
 	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
 	/* Look for common error cases */
@@ -2074,7 +2088,18 @@
 			goto cleanup;
 		}
 
+		/* We've skipped all the TDs on the ep ring when ep->skip set */
+		if (ep->skip && td_num == 0) {
+			ep->skip = false;
+			xhci_dbg(xhci, "All tds on the ep_ring skipped. "
+						"Clear skip flag.\n");
+			ret = 0;
+			goto cleanup;
+		}
+
 		td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
+		if (ep->skip)
+			td_num--;
 
 		/* Is this a TRB in the currently executing TD? */
 		event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
@@ -2398,7 +2423,7 @@
  *			prepare_transfer()?
  */
 static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
-		bool consumer, bool more_trbs_coming,
+		bool consumer, bool more_trbs_coming, bool isoc,
 		u32 field1, u32 field2, u32 field3, u32 field4)
 {
 	struct xhci_generic_trb *trb;
@@ -2408,7 +2433,7 @@
 	trb->field[1] = cpu_to_le32(field2);
 	trb->field[2] = cpu_to_le32(field3);
 	trb->field[3] = cpu_to_le32(field4);
-	inc_enq(xhci, ring, consumer, more_trbs_coming);
+	inc_enq(xhci, ring, consumer, more_trbs_coming, isoc);
 }
 
 /*
@@ -2416,7 +2441,7 @@
  * FIXME allocate segments if the ring is full.
  */
 static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
-		u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
+		u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags)
 {
 	/* Make sure the endpoint has been added to xHC schedule */
 	switch (ep_state) {
@@ -2458,10 +2483,11 @@
 		next = ring->enqueue;
 
 		while (last_trb(xhci, ring, ring->enq_seg, next)) {
-			/* If we're not dealing with 0.95 hardware,
-			 * clear the chain bit.
+			/* If we're not dealing with 0.95 hardware or isoc rings
+			 * on AMD 0.96 host, clear the chain bit.
 			 */
-			if (!xhci_link_trb_quirk(xhci))
+			if (!xhci_link_trb_quirk(xhci) && !(isoc &&
+					(xhci->quirks & XHCI_AMD_0x96_HOST)))
 				next->link.control &= cpu_to_le32(~TRB_CHAIN);
 			else
 				next->link.control |= cpu_to_le32(TRB_CHAIN);
@@ -2494,6 +2520,7 @@
 		unsigned int num_trbs,
 		struct urb *urb,
 		unsigned int td_index,
+		bool isoc,
 		gfp_t mem_flags)
 {
 	int ret;
@@ -2511,7 +2538,7 @@
 
 	ret = prepare_ring(xhci, ep_ring,
 			   le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, mem_flags);
+			   num_trbs, isoc, mem_flags);
 	if (ret)
 		return ret;
 
@@ -2544,7 +2571,7 @@
 	struct scatterlist *sg;
 
 	sg = NULL;
-	num_sgs = urb->num_sgs;
+	num_sgs = urb->num_mapped_sgs;
 	temp = urb->transfer_buffer_length;
 
 	xhci_dbg(xhci, "count sg list trbs: \n");
@@ -2728,13 +2755,13 @@
 		return -EINVAL;
 
 	num_trbs = count_sg_trbs_needed(xhci, urb);
-	num_sgs = urb->num_sgs;
+	num_sgs = urb->num_mapped_sgs;
 	total_packet_count = roundup(urb->transfer_buffer_length,
 			le16_to_cpu(urb->ep->desc.wMaxPacketSize));
 
 	trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, mem_flags);
+			num_trbs, urb, 0, false, mem_flags);
 	if (trb_buff_len < 0)
 		return trb_buff_len;
 
@@ -2829,7 +2856,7 @@
 			more_trbs_coming = true;
 		else
 			more_trbs_coming = false;
-		queue_trb(xhci, ep_ring, false, more_trbs_coming,
+		queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -2920,7 +2947,7 @@
 
 	ret = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, mem_flags);
+			num_trbs, urb, 0, false, mem_flags);
 	if (ret < 0)
 		return ret;
 
@@ -2992,7 +3019,7 @@
 			more_trbs_coming = true;
 		else
 			more_trbs_coming = false;
-		queue_trb(xhci, ep_ring, false, more_trbs_coming,
+		queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -3052,7 +3079,7 @@
 		num_trbs++;
 	ret = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
-			num_trbs, urb, 0, mem_flags);
+			num_trbs, urb, 0, false, mem_flags);
 	if (ret < 0)
 		return ret;
 
@@ -3085,7 +3112,7 @@
 		}
 	}
 
-	queue_trb(xhci, ep_ring, false, true,
+	queue_trb(xhci, ep_ring, false, true, false,
 		  setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
 		  le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
 		  TRB_LEN(8) | TRB_INTR_TARGET(0),
@@ -3105,7 +3132,7 @@
 	if (urb->transfer_buffer_length > 0) {
 		if (setup->bRequestType & USB_DIR_IN)
 			field |= TRB_DIR_IN;
-		queue_trb(xhci, ep_ring, false, true,
+		queue_trb(xhci, ep_ring, false, true, false,
 				lower_32_bits(urb->transfer_dma),
 				upper_32_bits(urb->transfer_dma),
 				length_field,
@@ -3121,7 +3148,7 @@
 		field = 0;
 	else
 		field = TRB_DIR_IN;
-	queue_trb(xhci, ep_ring, false, false,
+	queue_trb(xhci, ep_ring, false, false, false,
 			0,
 			0,
 			TRB_INTR_TARGET(0),
@@ -3270,7 +3297,8 @@
 		trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
 
 		ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
-				urb->stream_id, trbs_per_td, urb, i, mem_flags);
+				urb->stream_id, trbs_per_td, urb, i, true,
+				mem_flags);
 		if (ret < 0) {
 			if (i == 0)
 				return ret;
@@ -3340,7 +3368,7 @@
 				remainder |
 				TRB_INTR_TARGET(0);
 
-			queue_trb(xhci, ep_ring, false, more_trbs_coming,
+			queue_trb(xhci, ep_ring, false, more_trbs_coming, true,
 				lower_32_bits(addr),
 				upper_32_bits(addr),
 				length_field,
@@ -3354,7 +3382,8 @@
 		/* Check TD length */
 		if (running_total != td_len) {
 			xhci_err(xhci, "ISOC TD length unmatch\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto cleanup;
 		}
 	}
 
@@ -3422,7 +3451,7 @@
 	 * Do not insert any td of the urb to the ring if the check failed.
 	 */
 	ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, mem_flags);
+			   num_trbs, true, mem_flags);
 	if (ret)
 		return ret;
 
@@ -3481,7 +3510,7 @@
 		reserved_trbs++;
 
 	ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
-			reserved_trbs, GFP_ATOMIC);
+			reserved_trbs, false, GFP_ATOMIC);
 	if (ret < 0) {
 		xhci_err(xhci, "ERR: No room for command on command ring\n");
 		if (command_must_succeed)
@@ -3489,8 +3518,8 @@
 					"unfailable commands failed.\n");
 		return ret;
 	}
-	queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3,
-			field4 | xhci->cmd_ring->cycle_state);
+	queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2,
+			field3,	field4 | xhci->cmd_ring->cycle_state);
 	return 0;
 }
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7ea48b3..107438e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -657,7 +657,10 @@
 	ring = xhci->cmd_ring;
 	seg = ring->deq_seg;
 	do {
-		memset(seg->trbs, 0, SEGMENT_SIZE);
+		memset(seg->trbs, 0,
+			sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1));
+		seg->trbs[TRBS_PER_SEGMENT - 1].link.control &=
+			cpu_to_le32(~TRB_CYCLE);
 		seg = seg->next;
 	} while (seg != ring->deq_seg);
 
@@ -749,7 +752,7 @@
 	u32			command, temp = 0;
 	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
 	struct usb_hcd		*secondary_hcd;
-	int			retval;
+	int			retval = 0;
 
 	/* Wait a bit if either of the roothubs need to settle from the
 	 * transition into bus suspend.
@@ -759,6 +762,9 @@
 				xhci->bus_state[1].next_statechange))
 		msleep(100);
 
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
+
 	spin_lock_irq(&xhci->lock);
 	if (xhci->quirks & XHCI_RESET_ON_RESUME)
 		hibernated = true;
@@ -828,20 +834,13 @@
 			return retval;
 		xhci_dbg(xhci, "Start the primary HCD\n");
 		retval = xhci_run(hcd->primary_hcd);
-		if (retval)
-			goto failed_restart;
-
-		xhci_dbg(xhci, "Start the secondary HCD\n");
-		retval = xhci_run(secondary_hcd);
 		if (!retval) {
-			set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-			set_bit(HCD_FLAG_HW_ACCESSIBLE,
-					&xhci->shared_hcd->flags);
+			xhci_dbg(xhci, "Start the secondary HCD\n");
+			retval = xhci_run(secondary_hcd);
 		}
-failed_restart:
 		hcd->state = HC_STATE_SUSPENDED;
 		xhci->shared_hcd->state = HC_STATE_SUSPENDED;
-		return retval;
+		goto done;
 	}
 
 	/* step 4: set Run/Stop bit */
@@ -860,11 +859,14 @@
 	 * Running endpoints by ringing their doorbells
 	 */
 
-	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
-
 	spin_unlock_irq(&xhci->lock);
-	return 0;
+
+ done:
+	if (retval == 0) {
+		usb_hcd_resume_root_hub(hcd);
+		usb_hcd_resume_root_hub(xhci->shared_hcd);
+	}
+	return retval;
 }
 #endif	/* CONFIG_PM */
 
@@ -1566,6 +1568,7 @@
 		/* FIXME: can we allocate more resources for the HC? */
 		break;
 	case COMP_BW_ERR:
+	case COMP_2ND_BW_ERR:
 		dev_warn(&udev->dev, "Not enough bandwidth "
 				"for new device state.\n");
 		ret = -ENOSPC;
@@ -1889,6 +1892,12 @@
 	ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
 	ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG);
 	ctrl_ctx->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
+
+	/* Don't issue the command if there's no endpoints to update. */
+	if (ctrl_ctx->add_flags == cpu_to_le32(SLOT_FLAG) &&
+			ctrl_ctx->drop_flags == 0)
+		return 0;
+
 	xhci_dbg(xhci, "New Input Control Context:\n");
 	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
 	xhci_dbg_ctx(xhci, virt_dev->in_ctx,
@@ -2175,8 +2184,7 @@
 		if (ret < 0)
 			return ret;
 
-		max_streams = USB_SS_MAX_STREAMS(
-				eps[i]->ss_ep_comp.bmAttributes);
+		max_streams = usb_ss_max_streams(&eps[i]->ss_ep_comp);
 		if (max_streams < (*num_streams - 1)) {
 			xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n",
 					eps[i]->desc.bEndpointAddress,
@@ -2869,6 +2877,10 @@
 	/* Otherwise, update the control endpoint ring enqueue pointer. */
 	else
 		xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev);
+	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
+	ctrl_ctx->drop_flags = 0;
+
 	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
 	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
 
@@ -2950,7 +2962,6 @@
 	virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK)
 		+ 1;
 	/* Zero the input context control for later use */
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
 	ctrl_ctx->add_flags = 0;
 	ctrl_ctx->drop_flags = 0;
 
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index d8bbf5c..3e7c3a6 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -900,7 +900,6 @@
 /* Invalid Stream ID Error */
 #define COMP_STRID_ERR	34
 /* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */
-/* FIXME - check for this */
 #define COMP_2ND_BW_ERR	35
 /* Split Transaction Error */
 #define	COMP_SPLIT_ERR	36
@@ -1311,6 +1310,7 @@
 #define XHCI_EP_LIMIT_QUIRK	(1 << 5)
 #define XHCI_BROKEN_MSI		(1 << 6)
 #define XHCI_RESET_ON_RESUME	(1 << 7)
+#define XHCI_AMD_0x96_HOST	(1 << 9)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
@@ -1565,6 +1565,8 @@
 		unsigned int ep_index, unsigned int stream_id);
 
 /* xHCI roothub code */
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+				int port_id, u32 port_bit);
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
 		char *buf, u16 wLength);
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index aab5b98..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[] = {
@@ -390,6 +442,8 @@
 	.driver_info = VALID_INTERFACE_NUM, },
 	{ USB_DEVICE(0x5c6, 0x9048),
 	.driver_info = VALID_INTERFACE_NUM, },
+	{ USB_DEVICE(0x5c6, 0x904C),
+	.driver_info = VALID_INTERFACE_NUM, },
 
 	{} /* terminating entry */
 };
@@ -399,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)
@@ -408,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/isight_firmware.c b/drivers/usb/misc/isight_firmware.c
index fe1d443..8f725f6 100644
--- a/drivers/usb/misc/isight_firmware.c
+++ b/drivers/usb/misc/isight_firmware.c
@@ -55,8 +55,9 @@
 
 	ptr = firmware->data;
 
+	buf[0] = 0x01;
 	if (usb_control_msg
-	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1,
+	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,
 	     300) != 1) {
 		printk(KERN_ERR
 		       "Failed to initialise isight firmware loader\n");
@@ -100,8 +101,9 @@
 		}
 	}
 
+	buf[0] = 0x00;
 	if (usb_control_msg
-	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1,
+	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,
 	     300) != 1) {
 		printk(KERN_ERR "isight firmware loading completion failed\n");
 		ret = -ENODEV;
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 584503a..c23c7b1 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.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
@@ -38,8 +38,9 @@
 #define ACM_CTRL_DTR		(1 << 0)
 #define DEFAULT_READ_URB_LENGTH	4096
 
-struct ctrl_bridge {
+#define SUSPENDED		BIT(0)
 
+struct ctrl_bridge {
 	struct usb_device	*udev;
 	struct usb_interface	*intf;
 
@@ -51,11 +52,14 @@
 	void			*readbuf;
 
 	struct usb_anchor	tx_submitted;
+	struct usb_anchor	tx_deferred;
 	struct usb_ctrlrequest	*in_ctlreq;
 
 	struct bridge		*brdg;
 	struct platform_device	*pdev;
 
+	unsigned long		flags;
+
 	/* input control lines (DSR, CTS, CD, RI) */
 	unsigned int		cbits_tohost;
 
@@ -68,7 +72,6 @@
 	unsigned int		resp_avail;
 	unsigned int		set_ctrl_line_sts;
 	unsigned int		notify_ser_state;
-
 };
 
 static struct ctrl_bridge	*__dev[MAX_BRIDGE_DEVICES];
@@ -157,11 +160,14 @@
 
 	if (resubmit_urb) {
 		/*re- submit int urb to check response available*/
+		usb_anchor_urb(dev->inturb, &dev->tx_submitted);
 		status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
-		if (status)
+		if (status) {
 			dev_err(&udev->dev,
 				"%s: Error re-submitting Int URB %d\n",
 				__func__, status);
+			usb_unanchor_urb(dev->inturb);
+		}
 	}
 }
 
@@ -210,11 +216,13 @@
 					DEFAULT_READ_URB_LENGTH,
 					resp_avail_cb, dev);
 
+		usb_anchor_urb(dev->readurb, &dev->tx_submitted);
 		status = usb_submit_urb(dev->readurb, GFP_ATOMIC);
 		if (status) {
 			dev_err(&udev->dev,
 				"%s: Error submitting Read URB %d\n",
 				__func__, status);
+			usb_unanchor_urb(dev->readurb);
 			goto resubmit_int_urb;
 		}
 		return;
@@ -238,52 +246,42 @@
 	}
 
 resubmit_int_urb:
+	usb_anchor_urb(urb, &dev->tx_submitted);
 	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
+	if (status) {
 		dev_err(&udev->dev, "%s: Error re-submitting Int URB %d\n",
 		__func__, status);
+		usb_unanchor_urb(urb);
+	}
 }
 
 int ctrl_bridge_start_read(struct ctrl_bridge *dev)
 {
-	int			retval = 0;
-	struct usb_device	*udev;
+	int	retval = 0;
 
-	udev = interface_to_usbdev(dev->intf);
-
-	retval = usb_autopm_get_interface_async(dev->intf);
-	if (retval < 0) {
-		dev_err(&udev->dev, "%s resumption fail\n", __func__);
-		goto done_nopm;
+	if (!dev->inturb) {
+		dev_err(&dev->udev->dev, "%s: inturb is NULL\n", __func__);
+		return -ENODEV;
 	}
 
-	retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
-	if (retval < 0)
-		dev_err(&udev->dev, "%s intr submit %d\n", __func__, retval);
+	if (!dev->inturb->anchor) {
+		usb_anchor_urb(dev->inturb, &dev->tx_submitted);
+		retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
+		if (retval < 0) {
+			dev_err(&dev->udev->dev,
+				"%s error submitting int urb %d\n",
+				__func__, retval);
+			usb_unanchor_urb(dev->inturb);
+		}
+	}
 
-	usb_autopm_put_interface_async(dev->intf);
-done_nopm:
 	return retval;
 }
 
-static int ctrl_bridge_stop_read(struct ctrl_bridge *dev)
-{
-	if (dev->readurb) {
-		dev_dbg(&dev->udev->dev, "killing rcv urb\n");
-		usb_unlink_urb(dev->readurb);
-	}
-
-	if (dev->inturb) {
-		dev_dbg(&dev->udev->dev, "killing int urb\n");
-		usb_unlink_urb(dev->inturb);
-	}
-
-	return 0;
-}
-
 int ctrl_bridge_open(struct bridge *brdg)
 {
 	struct ctrl_bridge	*dev;
+	int			ret;
 
 	if (!brdg) {
 		err("bridge is null\n");
@@ -306,7 +304,16 @@
 	dev->set_ctrl_line_sts = 0;
 	dev->notify_ser_state = 0;
 
-	return ctrl_bridge_start_read(dev);
+	ret = usb_autopm_get_interface(dev->intf);
+	if (ret < 0) {
+		dev_err(&dev->udev->dev, "%s autopm_get fail: %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ret = ctrl_bridge_start_read(dev);
+	usb_autopm_put_interface(dev->intf);
+	return ret;
 }
 EXPORT_SYMBOL(ctrl_bridge_open);
 
@@ -325,7 +332,6 @@
 
 	ctrl_bridge_set_cbits(dev->brdg->ch_id, 0);
 	usb_unlink_anchored_urbs(&dev->tx_submitted);
-	ctrl_bridge_stop_read(dev);
 
 	dev->brdg = NULL;
 }
@@ -423,6 +429,11 @@
 		goto free_ctrlreq;
 	}
 
+	if (test_bit(SUSPENDED, &dev->flags)) {
+		usb_anchor_urb(writeurb, &dev->tx_deferred);
+		goto deferred;
+	}
+
 	usb_anchor_urb(writeurb, &dev->tx_submitted);
 	result = usb_submit_urb(writeurb, GFP_ATOMIC);
 	if (result < 0) {
@@ -431,7 +442,7 @@
 		usb_autopm_put_interface_async(dev->intf);
 		goto unanchor_urb;
 	}
-
+deferred:
 	return size;
 
 unanchor_urb:
@@ -458,14 +469,16 @@
 	if (!dev)
 		return -ENODEV;
 
+	set_bit(SUSPENDED, &dev->flags);
 	usb_kill_anchored_urbs(&dev->tx_submitted);
 
-	return ctrl_bridge_stop_read(dev);
+	return 0;
 }
 
 int ctrl_bridge_resume(unsigned int id)
 {
 	struct ctrl_bridge	*dev;
+	struct urb		*urb;
 
 	if (id >= MAX_BRIDGE_DEVICES)
 		return -EINVAL;
@@ -474,7 +487,28 @@
 	if (!dev)
 		return -ENODEV;
 
-	return ctrl_bridge_start_read(dev);
+	if (!test_and_clear_bit(SUSPENDED, &dev->flags))
+		return 0;
+
+	/* submit pending write requests */
+	while ((urb = usb_get_from_anchor(&dev->tx_deferred))) {
+		int ret;
+		usb_anchor_urb(urb, &dev->tx_submitted);
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if (ret < 0) {
+			usb_unanchor_urb(urb);
+			kfree(urb->setup_packet);
+			kfree(urb->transfer_buffer);
+			usb_free_urb(urb);
+			usb_autopm_put_interface_async(dev->intf);
+		}
+	}
+
+	/* if the bridge is open, resume reading */
+	if (dev->brdg)
+		return ctrl_bridge_start_read(dev);
+
+	return 0;
 }
 
 #if defined(CONFIG_DEBUG_FS)
@@ -505,7 +539,8 @@
 				"set ctrlline sts cnt: %u\n"
 				"notify ser state cnt: %u\n"
 				"cbits_tomdm: %d\n"
-				"cbits_tohost: %d\n",
+				"cbits_tohost: %d\n"
+				"suspended: %d\n",
 				dev->pdev->name, dev,
 				dev->snd_encap_cmd,
 				dev->get_encap_res,
@@ -513,8 +548,8 @@
 				dev->set_ctrl_line_sts,
 				dev->notify_ser_state,
 				dev->cbits_tomdm,
-				dev->cbits_tohost);
-
+				dev->cbits_tohost,
+				test_bit(SUSPENDED, &dev->flags));
 	}
 
 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
@@ -608,6 +643,7 @@
 	dev->intf = ifc;
 
 	init_usb_anchor(&dev->tx_submitted);
+	init_usb_anchor(&dev->tx_deferred);
 
 	/*use max pkt size from ep desc*/
 	ep = &dev->intf->cur_altsetting->endpoint[0].desc;
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 687c8c5..bf8e5f4 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -61,6 +61,8 @@
 struct data_bridge {
 	struct usb_interface		*intf;
 	struct usb_device		*udev;
+	int				id;
+
 	unsigned int			bulk_in;
 	unsigned int			bulk_out;
 	int				err;
@@ -264,6 +266,7 @@
 	if (retval)
 		goto fail;
 
+	usb_mark_last_busy(dev->udev);
 	return 0;
 fail:
 	usb_unanchor_urb(rx_urb);
@@ -543,6 +546,9 @@
 	struct urb	*urb;
 	int		retval;
 
+	if (!test_and_clear_bit(SUSPENDED, &dev->flags))
+		return 0;
+
 	while ((urb = usb_get_from_anchor(&dev->delayed))) {
 		usb_anchor_urb(urb, &dev->tx_active);
 		atomic_inc(&dev->pending_txurbs);
@@ -559,8 +565,6 @@
 		dev->txurb_drp_cnt--;
 	}
 
-	clear_bit(SUSPENDED, &dev->flags);
-
 	if (dev->brdg)
 		queue_work(dev->wq, &dev->process_rx_w);
 
@@ -572,16 +576,16 @@
 	int			retval = 0;
 	int			oldstate;
 	struct data_bridge	*dev = usb_get_intfdata(iface);
-	struct bridge		*brdg = dev->brdg;
 
 	oldstate = iface->dev.power.power_state.event;
 	iface->dev.power.power_state.event = PM_EVENT_ON;
 
-	retval = data_bridge_resume(dev);
-	if (!retval) {
-		if (oldstate & PM_EVENT_SUSPEND && brdg)
-			retval = ctrl_bridge_resume(brdg->ch_id);
+	if (oldstate & PM_EVENT_SUSPEND) {
+		retval = data_bridge_resume(dev);
+		if (!retval)
+			retval = ctrl_bridge_resume(dev->id);
 	}
+
 	return retval;
 }
 
@@ -603,19 +607,13 @@
 {
 	int			retval;
 	struct data_bridge	*dev = usb_get_intfdata(intf);
-	struct bridge		*brdg = dev->brdg;
 
 	retval = data_bridge_suspend(dev, message);
 	if (!retval) {
-		if (message.event & PM_EVENT_SUSPEND) {
-			if (brdg)
-				retval = ctrl_bridge_suspend(brdg->ch_id);
-			intf->dev.power.power_state.event = message.event;
-		}
-	} else {
-		dev_dbg(&dev->udev->dev, "%s: device is busy,cannot suspend\n",
-			__func__);
+		retval = ctrl_bridge_suspend(dev->id);
+		intf->dev.power.power_state.event = message.event;
 	}
+
 	return retval;
 }
 
@@ -646,7 +644,7 @@
 	skb_queue_head_init(&dev->rx_done);
 
 	dev->wq = bridge_wq;
-
+	dev->id = id;
 	dev->udev = interface_to_usbdev(iface);
 	dev->intf = iface;
 
@@ -1016,6 +1014,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),
@@ -1027,6 +1026,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/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c
index 417b8f2..59689fa 100644
--- a/drivers/usb/misc/usbsevseg.c
+++ b/drivers/usb/misc/usbsevseg.c
@@ -24,7 +24,7 @@
 
 #define VENDOR_ID	0x0fc5
 #define PRODUCT_ID	0x1227
-#define MAXLEN		6
+#define MAXLEN		8
 
 /* table of devices that work with this driver */
 static const struct usb_device_id id_table[] = {
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index a09dbd2..a04b2ff 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -1101,7 +1101,7 @@
 		nevents = mon_bin_queued(rp);
 
 		sp = (struct mon_bin_stats __user *)arg;
-		if (put_user(rp->cnt_lost, &sp->dropped))
+		if (put_user(ndropped, &sp->dropped))
 			return -EFAULT;
 		if (put_user(nevents, &sp->queued))
 			return -EFAULT;
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 9cc6cb0..ef373b3 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -8,13 +8,13 @@
 
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
-	depends on (USB || USB_GADGET)
+	depends on USB && USB_GADGET
 	depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
 	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
 	select USB_OTG_UTILS
-	bool 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
 	help
 	  Say Y here if your system has a dual role high speed USB
 	  controller based on the Mentor Graphics silicon IP.  Then
@@ -30,8 +30,8 @@
 
 	  If you do not know what this is, please say N.
 
-#	  To compile this driver as a module, choose M here; the
-#	  module will be called "musb-hdrc".
+	  To compile this driver as a module, choose M here; the
+	  module will be called "musb-hdrc".
 
 choice
 	prompt "Platform Glue Layer"
@@ -126,7 +126,7 @@
 
 # enable peripheral support (including with OTG)
 config USB_GADGET_MUSB_HDRC
-	bool
+	tristate
 	depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
 #	default y
 #	select USB_GADGET_DUALSPEED
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index dce7182..a0232a7 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2078,8 +2078,6 @@
 	if (status < 0)
 		goto fail3;
 
-	pm_runtime_put(musb->controller);
-
 	status = musb_init_debugfs(musb);
 	if (status < 0)
 		goto fail4;
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..7aa0430 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -33,6 +33,7 @@
 #include <linux/usb/ulpi.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/hcd.h>
+#include <linux/usb/quirks.h>
 #include <linux/usb/msm_hsusb.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/regulator/consumer.h>
@@ -48,9 +49,8 @@
 #define MSM_USB_BASE	(motg->regs)
 #define DRIVER_NAME	"msm_otg"
 
-#define ID_TIMER_FREQ		(jiffies + msecs_to_jiffies(2000))
+#define ID_TIMER_FREQ		(jiffies + msecs_to_jiffies(500))
 #define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
-
 #define USB_PHY_3P3_VOL_MIN	3050000 /* uV */
 #define USB_PHY_3P3_VOL_MAX	3300000 /* uV */
 #define USB_PHY_3P3_HPM_LOAD	50000	/* uA */
@@ -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)
@@ -91,6 +92,7 @@
 static struct regulator *hsusb_1p8;
 static struct regulator *hsusb_vddcx;
 static struct regulator *vbus_otg;
+static struct regulator *mhl_analog_switch;
 
 static bool aca_id_turned_on;
 static inline bool aca_enabled(void)
@@ -107,7 +109,7 @@
 	int ret = 0;
 
 	if (init) {
-		hsusb_vddcx = regulator_get(motg->otg.dev, "HSUSB_VDDCX");
+		hsusb_vddcx = devm_regulator_get(motg->otg.dev, "HSUSB_VDDCX");
 		if (IS_ERR(hsusb_vddcx)) {
 			dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
 			return PTR_ERR(hsusb_vddcx);
@@ -119,7 +121,6 @@
 		if (ret) {
 			dev_err(motg->otg.dev, "unable to set the voltage "
 					"for hsusb vddcx\n");
-			regulator_put(hsusb_vddcx);
 			return ret;
 		}
 
@@ -127,7 +128,6 @@
 		if (ret) {
 			regulator_set_voltage(hsusb_vddcx, 0,
 			USB_PHY_VDD_DIG_VOL_MIN);
-			regulator_put(hsusb_vddcx);
 			dev_err(motg->otg.dev, "unable to enable the hsusb vddcx\n");
 			return ret;
 		}
@@ -147,8 +147,6 @@
 					"for hsusb vddcx\n");
 			return ret;
 		}
-
-		regulator_put(hsusb_vddcx);
 	}
 
 	return ret;
@@ -159,7 +157,7 @@
 	int rc = 0;
 
 	if (init) {
-		hsusb_3p3 = regulator_get(motg->otg.dev, "HSUSB_3p3");
+		hsusb_3p3 = devm_regulator_get(motg->otg.dev, "HSUSB_3p3");
 		if (IS_ERR(hsusb_3p3)) {
 			dev_err(motg->otg.dev, "unable to get hsusb 3p3\n");
 			return PTR_ERR(hsusb_3p3);
@@ -170,9 +168,9 @@
 		if (rc) {
 			dev_err(motg->otg.dev, "unable to set voltage level for"
 					"hsusb 3p3\n");
-			goto put_3p3;
+			return rc;
 		}
-		hsusb_1p8 = regulator_get(motg->otg.dev, "HSUSB_1p8");
+		hsusb_1p8 = devm_regulator_get(motg->otg.dev, "HSUSB_1p8");
 		if (IS_ERR(hsusb_1p8)) {
 			dev_err(motg->otg.dev, "unable to get hsusb 1p8\n");
 			rc = PTR_ERR(hsusb_1p8);
@@ -191,11 +189,8 @@
 
 put_1p8:
 	regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
-	regulator_put(hsusb_1p8);
 put_3p3_lpm:
 	regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
-put_3p3:
-	regulator_put(hsusb_3p3);
 	return rc;
 }
 
@@ -312,30 +307,22 @@
 
 static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
 {
-	static struct regulator *mhl_analog_switch;
 	struct msm_otg_platform_data *pdata = motg->pdata;
 
 	if (!pdata->mhl_enable)
 		return;
 
-	if (on) {
-		mhl_analog_switch = regulator_get(motg->otg.dev,
-					       "mhl_ext_3p3v");
-		if (IS_ERR(mhl_analog_switch)) {
-			pr_err("Unable to get mhl_analog_switch\n");
-			return;
-		}
-
-		if (regulator_enable(mhl_analog_switch)) {
-			pr_err("unable to enable mhl_analog_switch\n");
-			goto put_analog_switch;
-		}
+	if (!mhl_analog_switch) {
+		pr_err("%s: mhl_analog_switch is NULL.\n", __func__);
 		return;
 	}
 
-	regulator_disable(mhl_analog_switch);
-put_analog_switch:
-	regulator_put(mhl_analog_switch);
+	if (on) {
+		if (regulator_enable(mhl_analog_switch))
+			pr_err("unable to enable mhl_analog_switch\n");
+	} else {
+		regulator_disable(mhl_analog_switch);
+	}
 }
 
 static int ulpi_read(struct otg_transceiver *otg, u32 reg)
@@ -513,7 +500,7 @@
 	/* select ULPI phy */
 	writel_relaxed(0x80000000, USB_PORTSC);
 	writel_relaxed(0x0, USB_AHBBURST);
-	writel_relaxed(0x00, USB_AHBMODE);
+	writel_relaxed(0x08, USB_AHBMODE);
 
 	return 0;
 }
@@ -580,25 +567,190 @@
 	return 0;
 }
 
+static const char *timer_string(int bit)
+{
+	switch (bit) {
+	case A_WAIT_VRISE:		return "a_wait_vrise";
+	case A_WAIT_VFALL:		return "a_wait_vfall";
+	case B_SRP_FAIL:		return "b_srp_fail";
+	case A_WAIT_BCON:		return "a_wait_bcon";
+	case A_AIDL_BDIS:		return "a_aidl_bdis";
+	case A_BIDL_ADIS:		return "a_bidl_adis";
+	case B_ASE0_BRST:		return "b_ase0_brst";
+	case A_TST_MAINT:		return "a_tst_maint";
+	case B_TST_SRP:			return "b_tst_srp";
+	case B_TST_CONFIG:		return "b_tst_config";
+	default:			return "UNDEFINED";
+	}
+}
+
+static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
+{
+	struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
+
+	switch (motg->active_tmout) {
+	case A_WAIT_VRISE:
+		/* TODO: use vbus_vld interrupt */
+		set_bit(A_VBUS_VLD, &motg->inputs);
+		break;
+	case A_TST_MAINT:
+		/* OTG PET: End session after TA_TST_MAINT */
+		set_bit(A_BUS_DROP, &motg->inputs);
+		break;
+	case B_TST_SRP:
+		/*
+		 * OTG PET: Initiate SRP after TB_TST_SRP of
+		 * previous session end.
+		 */
+		set_bit(B_BUS_REQ, &motg->inputs);
+		break;
+	case B_TST_CONFIG:
+		clear_bit(A_CONN, &motg->inputs);
+		break;
+	default:
+		set_bit(motg->active_tmout, &motg->tmouts);
+	}
+
+	pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
+	queue_work(system_nrt_wq, &motg->sm_work);
+	return HRTIMER_NORESTART;
+}
+
+static void msm_otg_del_timer(struct msm_otg *motg)
+{
+	int bit = motg->active_tmout;
+
+	pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
+			div_s64(ktime_to_us(hrtimer_get_remaining(
+					&motg->timer)), 1000));
+	hrtimer_cancel(&motg->timer);
+	clear_bit(bit, &motg->tmouts);
+}
+
+static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
+{
+	clear_bit(bit, &motg->tmouts);
+	motg->active_tmout = bit;
+	pr_debug("starting %s timer\n", timer_string(bit));
+	hrtimer_start(&motg->timer,
+			ktime_set(time / 1000, (time % 1000) * 1000000),
+			HRTIMER_MODE_REL);
+}
+
+static void msm_otg_init_timer(struct msm_otg *motg)
+{
+	hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	motg->timer.function = msm_otg_timer_func;
+}
+
+static int msm_otg_start_hnp(struct otg_transceiver *otg)
+{
+	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+
+	if (otg->state != OTG_STATE_A_HOST) {
+		pr_err("HNP can not be initiated in %s state\n",
+				otg_state_string(otg->state));
+		return -EINVAL;
+	}
+
+	pr_debug("A-Host: HNP initiated\n");
+	clear_bit(A_BUS_REQ, &motg->inputs);
+	queue_work(system_nrt_wq, &motg->sm_work);
+	return 0;
+}
+
+static int msm_otg_start_srp(struct otg_transceiver *otg)
+{
+	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	u32 val;
+	int ret = 0;
+
+	if (otg->state != OTG_STATE_B_IDLE) {
+		pr_err("SRP can not be initiated in %s state\n",
+				otg_state_string(otg->state));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
+		pr_debug("initial conditions of SRP are not met. Try again"
+				"after some time\n");
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	pr_debug("B-Device SRP started\n");
+
+	/*
+	 * PHY won't pull D+ high unless it detects Vbus valid.
+	 * Since by definition, SRP is only done when Vbus is not valid,
+	 * software work-around needs to be used to spoof the PHY into
+	 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
+	 * VBUSVLDEXT register bits.
+	 */
+	ulpi_write(otg, 0x03, 0x97);
+	/*
+	 * Harware auto assist data pulsing: Data pulse is given
+	 * for 7msec; wait for vbus
+	 */
+	val = readl_relaxed(USB_OTGSC);
+	writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
+
+	/* VBUS plusing is obsoleted in OTG 2.0 supplement */
+out:
+	return ret;
+}
+
+static void msm_otg_host_hnp_enable(struct otg_transceiver *otg, bool enable)
+{
+	struct usb_hcd *hcd = bus_to_hcd(otg->host);
+	struct usb_device *rhub = otg->host->root_hub;
+
+	if (enable) {
+		pm_runtime_disable(&rhub->dev);
+		rhub->state = USB_STATE_NOTATTACHED;
+		hcd->driver->bus_suspend(hcd);
+		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	} else {
+		usb_remove_hcd(hcd);
+		msm_otg_reset(otg);
+		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+	}
+}
+
 static int msm_otg_set_suspend(struct otg_transceiver *otg, int suspend)
 {
 	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
 
-	/*
-	 * Allow bus suspend only for host mode.  Device mode bus suspend
-	 * is not implemented yet.
-	 */
-	if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs)) {
-		/*
-		 * ID_GND --> ID_A transition can not be detected in LPM.
-		 * Disallow host bus suspend when ACA is enabled.
-		 */
-		if (suspend && !aca_enabled())
-			pm_runtime_put(otg->dev);
-		else
-			pm_runtime_resume(otg->dev);
-	}
+	if (aca_enabled() || (test_bit(ID, &motg->inputs) &&
+				 !test_bit(ID_A, &motg->inputs)))
+		return 0;
 
+	if (suspend) {
+		switch (otg->state) {
+		case OTG_STATE_A_WAIT_BCON:
+			if (TA_WAIT_BCON > 0)
+				break;
+			/* fall through */
+		case OTG_STATE_A_HOST:
+			pr_debug("host bus suspend\n");
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			queue_work(system_nrt_wq, &motg->sm_work);
+			break;
+		default:
+			break;
+		}
+	} else {
+		switch (otg->state) {
+		case OTG_STATE_A_SUSPEND:
+			/* Remote wakeup or resume */
+			set_bit(A_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_A_HOST;
+			break;
+		default:
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -614,6 +766,7 @@
 	int cnt = 0;
 	bool host_bus_suspend, dcp;
 	u32 phy_ctrl_val = 0, cmd_val;
+	unsigned ret;
 	u32 portsc;
 
 	if (atomic_read(&motg->in_lpm))
@@ -715,7 +868,10 @@
 	clk_disable_unprepare(motg->core_clk);
 
 	/* usb phy no more require TCXO clock, hence vote for TCXO disable */
-	clk_disable_unprepare(motg->xo_handle);
+	ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+	if (ret)
+		dev_err(otg->dev, "%s failed to devote for "
+			"TCXO D0 buffer%d\n", __func__, ret);
 
 	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
 			!host_bus_suspend && !dcp) {
@@ -760,7 +916,7 @@
 	wake_lock(&motg->wlock);
 
 	/* Vote for TCXO when waking up the phy */
-	ret = clk_prepare_enable(motg->xo_handle);
+	ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
 	if (ret)
 		dev_err(otg->dev, "%s failed to vote for "
 			"TCXO D0 buffer%d\n", __func__, ret);
@@ -846,33 +1002,6 @@
 }
 #endif
 
-static int msm_otg_notify_chg_type(struct msm_otg *motg)
-{
-	static int charger_type;
-	/*
-	 * TODO
-	 * Unify OTG driver charger types and power supply charger types
-	 */
-	if (charger_type == motg->chg_type)
-		return 0;
-
-	if (motg->chg_type == USB_SDP_CHARGER)
-		charger_type = POWER_SUPPLY_TYPE_USB;
-	else if (motg->chg_type == USB_CDP_CHARGER)
-		charger_type = POWER_SUPPLY_TYPE_USB_CDP;
-	else if (motg->chg_type == USB_DCP_CHARGER)
-		charger_type = POWER_SUPPLY_TYPE_USB_DCP;
-	else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
-		motg->chg_type == USB_ACA_A_CHARGER ||
-		motg->chg_type == USB_ACA_B_CHARGER ||
-		motg->chg_type == USB_ACA_C_CHARGER))
-		charger_type = POWER_SUPPLY_TYPE_USB_ACA;
-	else
-		charger_type = POWER_SUPPLY_TYPE_BATTERY;
-
-	return pm8921_set_usb_power_supply_type(charger_type);
-}
-
 static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
 {
 	struct power_supply *psy;
@@ -904,6 +1033,11 @@
 
 static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
 {
+	struct usb_gadget *g = motg->otg.gadget;
+
+	if (g && g->is_a_peripheral)
+		return;
+
 	if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
 		motg->chg_type == USB_ACA_A_CHARGER ||
 		motg->chg_type == USB_ACA_B_CHARGER ||
@@ -911,11 +1045,6 @@
 			mA > IDEV_ACA_CHG_LIMIT)
 		mA = IDEV_ACA_CHG_LIMIT;
 
-	if (msm_otg_notify_chg_type(motg))
-		dev_err(motg->otg.dev,
-			"Failed notifying %d charger type to PMIC\n",
-							motg->chg_type);
-
 	if (motg->cur_power == mA)
 		return;
 
@@ -986,11 +1115,9 @@
 			unsigned long action, void *priv)
 {
 	struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
+	struct otg_transceiver *otg = &motg->otg;
 	struct usb_device *udev = priv;
 
-	if (!aca_enabled())
-		goto out;
-
 	if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
 		goto out;
 
@@ -1007,17 +1134,47 @@
 
 	switch (action) {
 	case USB_DEVICE_ADD:
-		usb_disable_autosuspend(udev);
+		if (aca_enabled())
+			usb_disable_autosuspend(udev);
+		if (otg->state == OTG_STATE_A_WAIT_BCON) {
+			pr_debug("B_CONN set\n");
+			set_bit(B_CONN, &motg->inputs);
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_HOST;
+			/*
+			 * OTG PET: A-device must end session within
+			 * 10 sec after PET enumeration.
+			 */
+			if (udev->quirks & USB_QUIRK_OTG_PET)
+				msm_otg_start_timer(motg, TA_TST_MAINT,
+						A_TST_MAINT);
+		}
 		/* fall through */
 	case USB_DEVICE_CONFIG:
 		if (udev->actconfig)
 			motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
 		else
 			motg->mA_port = IUNIT;
+		if (otg->state == OTG_STATE_B_HOST)
+			msm_otg_del_timer(motg);
 		break;
 	case USB_DEVICE_REMOVE:
-		motg->mA_port = IUNIT;
-		break;
+		if ((otg->state == OTG_STATE_A_HOST) ||
+			(otg->state == OTG_STATE_A_SUSPEND)) {
+			pr_debug("B_CONN clear\n");
+			clear_bit(B_CONN, &motg->inputs);
+			/*
+			 * OTG PET: A-device must end session after
+			 * PET disconnection if it is enumerated
+			 * with bcdDevice[0] = 1. USB core sets
+			 * bus->otg_vbus_off for us. clear it here.
+			 */
+			if (udev->bus->otg_vbus_off) {
+				udev->bus->otg_vbus_off = 0;
+				set_bit(A_BUS_DROP, &motg->inputs);
+			}
+			queue_work(system_nrt_wq, &motg->sm_work);
+		}
 	default:
 		break;
 	}
@@ -1085,7 +1242,7 @@
 	}
 
 	if (!motg->pdata->vbus_power && host) {
-		vbus_otg = regulator_get(motg->otg.dev, "vbus_otg");
+		vbus_otg = devm_regulator_get(motg->otg.dev, "vbus_otg");
 		if (IS_ERR(vbus_otg)) {
 			pr_err("Unable to get vbus_otg\n");
 			return -ENODEV;
@@ -1100,20 +1257,20 @@
 			msm_hsusb_vbus_power(motg, 0);
 			otg->host = NULL;
 			otg->state = OTG_STATE_UNDEFINED;
-			schedule_work(&motg->sm_work);
+			queue_work(system_nrt_wq, &motg->sm_work);
 		} else {
 			otg->host = NULL;
 		}
 
-		if (vbus_otg)
-			regulator_put(vbus_otg);
-
 		return 0;
 	}
 
 	hcd = bus_to_hcd(host);
 	hcd->power_budget = motg->pdata->power_budget;
 
+#ifdef CONFIG_USB_OTG
+	host->otg_port = 1;
+#endif
 	motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
 	usb_register_notify(&motg->usbdev_nb);
 	otg->host = host;
@@ -1125,7 +1282,7 @@
 	 */
 	if (motg->pdata->mode == USB_HOST || otg->gadget) {
 		pm_runtime_get_sync(otg->dev);
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 	}
 
 	return 0;
@@ -1155,7 +1312,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)
@@ -1201,7 +1358,7 @@
 			msm_otg_start_peripheral(otg, 0);
 			otg->gadget = NULL;
 			otg->state = OTG_STATE_UNDEFINED;
-			schedule_work(&motg->sm_work);
+			queue_work(system_nrt_wq, &motg->sm_work);
 		} else {
 			otg->gadget = NULL;
 		}
@@ -1217,7 +1374,7 @@
 	 */
 	if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
 		pm_runtime_get_sync(otg->dev);
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 	}
 
 	return 0;
@@ -1379,6 +1536,7 @@
 static void msm_otg_id_timer_func(unsigned long data)
 {
 	struct msm_otg *motg = (struct msm_otg *) data;
+	struct otg_transceiver *otg = &motg->otg;
 
 	if (!aca_enabled())
 		return;
@@ -1388,11 +1546,15 @@
 		return;
 	}
 
+	if (otg->state == OTG_STATE_A_SUSPEND)
+		goto out;
+
 	if (msm_chg_check_aca_intr(motg)) {
 		dev_dbg(motg->otg.dev, "timer: aca work\n");
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 	}
 
+out:
 	if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
 		mod_timer(&motg->id_timer, ID_TIMER_FREQ);
 }
@@ -1733,16 +1895,22 @@
 	case USB_CHG_STATE_DETECTED:
 		msm_chg_block_off(motg);
 		msm_chg_enable_aca_det(motg);
+		/*
+		 * Spurious interrupt is seen after enabling ACA detection
+		 * due to which charger detection fails in case of PET.
+		 * Add delay of 100 microsec to avoid that.
+		 */
+		udelay(100);
 		msm_chg_enable_aca_intr(motg);
 		dev_dbg(otg->dev, "chg_type = %s\n",
 			chg_to_string(motg->chg_type));
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 		return;
 	default:
 		return;
 	}
 
-	schedule_delayed_work(&motg->chg_work, delay);
+	queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
 }
 
 /*
@@ -1770,10 +1938,12 @@
 				clear_bit(B_SESS_VLD, &motg->inputs);
 			}
 		} else if (pdata->otg_control == OTG_PHY_CONTROL) {
-			if (otgsc & OTGSC_ID)
+			if (otgsc & OTGSC_ID) {
 				set_bit(ID, &motg->inputs);
-			else
+			} else {
 				clear_bit(ID, &motg->inputs);
+				set_bit(A_BUS_REQ, &motg->inputs);
+			}
 			if (otgsc & OTGSC_BSV)
 				set_bit(B_SESS_VLD, &motg->inputs);
 			else
@@ -1819,11 +1989,12 @@
 {
 	struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
 	struct otg_transceiver *otg = &motg->otg;
+	bool work = 0, srp_reqd;
 
 	pm_runtime_resume(otg->dev);
+	pr_debug("%s work\n", otg_state_string(otg->state));
 	switch (otg->state) {
 	case OTG_STATE_UNDEFINED:
-		dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n");
 		msm_otg_reset(otg);
 		msm_otg_init_sm(motg);
 		otg->state = OTG_STATE_B_IDLE;
@@ -1835,31 +2006,15 @@
 		}
 		/* FALL THROUGH */
 	case OTG_STATE_B_IDLE:
-		dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
 		if ((!test_bit(ID, &motg->inputs) ||
 				test_bit(ID_A, &motg->inputs)) && otg->host) {
-			if (motg->chg_type == USB_ACA_DOCK_CHARGER)
-				msm_otg_notify_charger(motg,
-						IDEV_ACA_CHG_MAX);
-			else if (test_bit(ID_A, &motg->inputs))
-				msm_otg_notify_charger(motg,
-						IDEV_ACA_CHG_MAX - IUNIT);
-			else
-				msm_hsusb_vbus_power(motg, 1);
-			msm_otg_start_host(otg, 1);
-			/*
-			 * Link can not generate PHY_ALT interrupt
-			 * in host mode when no device is attached
-			 * to the port.  It is also observed PHY_ALT
-			 * interrupt missing upon Micro-A cable disconnect.
-			 * Hence disable PHY_ALT interrupt and perform
-			 * polling to detect RID change.
-			 */
-			msm_chg_enable_aca_det(motg);
-			msm_chg_disable_aca_intr(motg);
-			mod_timer(&motg->id_timer, ID_TIMER_FREQ);
-			otg->state = OTG_STATE_A_HOST;
+			pr_debug("!id || id_A\n");
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			set_bit(A_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_A_IDLE;
+			work = 1;
 		} else if (test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("b_sess_vld\n");
 			switch (motg->chg_state) {
 			case USB_CHG_STATE_UNDEFINED:
 				msm_chg_detect_work(&motg->chg_work.work);
@@ -1905,7 +2060,18 @@
 			default:
 				break;
 			}
+		} else if (test_bit(B_BUS_REQ, &motg->inputs)) {
+			pr_debug("b_sess_end && b_bus_req\n");
+			if (msm_otg_start_srp(otg) < 0) {
+				clear_bit(B_BUS_REQ, &motg->inputs);
+				work = 1;
+				break;
+			}
+			otg->state = OTG_STATE_B_SRP_INIT;
+			msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
+			break;
 		} else {
+			pr_debug("chg_work cancel");
 			cancel_delayed_work_sync(&motg->chg_work);
 			msm_otg_notify_charger(motg, 0);
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
@@ -1915,64 +2081,451 @@
 			pm_runtime_suspend(otg->dev);
 		}
 		break;
-	case OTG_STATE_B_PERIPHERAL:
-		dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
-		if (!test_bit(B_SESS_VLD, &motg->inputs) ||
-				!test_bit(ID, &motg->inputs) ||
-				!test_bit(ID_C, &motg->inputs)) {
-			msm_otg_start_peripheral(otg, 0);
+	case OTG_STATE_B_SRP_INIT:
+		if (!test_bit(ID, &motg->inputs) ||
+				test_bit(ID_A, &motg->inputs) ||
+				test_bit(ID_C, &motg->inputs) ||
+				(test_bit(B_SESS_VLD, &motg->inputs) &&
+				!test_bit(ID_B, &motg->inputs))) {
+			pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
+			msm_otg_del_timer(motg);
 			otg->state = OTG_STATE_B_IDLE;
-			schedule_work(w);
+			/*
+			 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
+			 * bits after SRP initiation.
+			 */
+			ulpi_write(otg, 0x0, 0x98);
+			work = 1;
+		} else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
+			pr_debug("b_srp_fail\n");
+			pr_info("A-device did not respond to SRP\n");
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			clear_bit(B_SRP_FAIL, &motg->tmouts);
+			otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
+			ulpi_write(otg, 0x0, 0x98);
+			otg->state = OTG_STATE_B_IDLE;
+			motg->b_last_se0_sess = jiffies;
+			work = 1;
+		}
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!test_bit(ID, &motg->inputs) ||
+				test_bit(ID_A, &motg->inputs) ||
+				test_bit(ID_B, &motg->inputs) ||
+				!test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("!id  || id_a/b || !b_sess_vld\n");
+			msm_otg_notify_charger(motg, 0);
+			srp_reqd = otg->gadget->otg_srp_reqd;
+			msm_otg_start_peripheral(otg, 0);
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			if (test_bit(ID_B, &motg->inputs))
+				clear_bit(ID_B, &motg->inputs);
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_B_IDLE;
+			motg->b_last_se0_sess = jiffies;
+			if (srp_reqd)
+				msm_otg_start_timer(motg,
+					TB_TST_SRP, B_TST_SRP);
+			else
+				work = 1;
+		} else if (test_bit(B_BUS_REQ, &motg->inputs) &&
+				otg->gadget->b_hnp_enable &&
+				test_bit(A_BUS_SUSPEND, &motg->inputs)) {
+			pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
+			msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
+			/* D+ pullup should not be disconnected within 4msec
+			 * after A device suspends the bus. Otherwise PET will
+			 * fail the compliance test.
+			 */
+			udelay(1000);
+			msm_otg_start_peripheral(otg, 0);
+			otg->state = OTG_STATE_B_WAIT_ACON;
+			/*
+			 * start HCD even before A-device enable
+			 * pull-up to meet HNP timings.
+			 */
+			otg->host->is_b_host = 1;
+			msm_otg_start_host(otg, 1);
 		} else if (test_bit(ID_C, &motg->inputs)) {
 			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
 		}
 		break;
-	case OTG_STATE_A_HOST:
-		dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n");
-		if (test_bit(ID, &motg->inputs) &&
-				!test_bit(ID_A, &motg->inputs)) {
-			msm_otg_start_host(otg, 0);
-			msm_hsusb_vbus_power(motg, 0);
-			msleep(100); /* TA_WAIT_VFALL */
+	case OTG_STATE_B_WAIT_ACON:
+		if (!test_bit(ID, &motg->inputs) ||
+				test_bit(ID_A, &motg->inputs) ||
+				test_bit(ID_B, &motg->inputs) ||
+				!test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("!id || id_a/b || !b_sess_vld\n");
+			msm_otg_del_timer(motg);
 			/*
-			 * Exit point of host mode.
-			 *
-			 * 1. Micro-A cable disconnect: Just schedule
-			 * the work. PHY is reset in B_IDLE and LPM
-			 * is allowed.
-			 * 2. ID_GND --> ID_B: No need to reset the PHY.
-			 * HCD core clears all PORTSC bits and initializes
-			 * the controller to host mode in remove_hcd.
-			 * Restore PORTSC transceiver select bits (ULPI)
-			 * and reset the controller to change MODE bits.
-			 * PHY_ALT interrupt can not occur in host mode.
+			 * A-device is physically disconnected during
+			 * HNP. Remove HCD.
 			 */
-			del_timer_sync(&motg->id_timer);
-			if (motg->chg_state != USB_CHG_STATE_UNDEFINED) {
-				msm_otg_link_reset(motg);
-				msm_chg_enable_aca_intr(motg);
-			}
+			msm_otg_start_host(otg, 0);
+			otg->host->is_b_host = 0;
+
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+			motg->b_last_se0_sess = jiffies;
 			otg->state = OTG_STATE_B_IDLE;
-			schedule_work(w);
+			msm_otg_reset(otg);
+			work = 1;
+		} else if (test_bit(A_CONN, &motg->inputs)) {
+			pr_debug("a_conn\n");
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+			otg->state = OTG_STATE_B_HOST;
+			/*
+			 * PET disconnects D+ pullup after reset is generated
+			 * by B device in B_HOST role which is not detected by
+			 * B device. As workaorund , start timer of 300msec
+			 * and stop timer if A device is enumerated else clear
+			 * A_CONN.
+			 */
+			msm_otg_start_timer(motg, TB_TST_CONFIG,
+						B_TST_CONFIG);
+		} else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
+			pr_debug("b_ase0_brst_tmout\n");
+			pr_info("B HNP fail:No response from A device\n");
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+			otg->host->is_b_host = 0;
+			clear_bit(B_ASE0_BRST, &motg->tmouts);
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			otg_send_event(OTG_EVENT_HNP_FAILED);
+			otg->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else if (test_bit(ID_C, &motg->inputs)) {
+			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
+		}
+		break;
+	case OTG_STATE_B_HOST:
+		if (!test_bit(B_BUS_REQ, &motg->inputs) ||
+				!test_bit(A_CONN, &motg->inputs) ||
+				!test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
+			clear_bit(A_CONN, &motg->inputs);
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			msm_otg_start_host(otg, 0);
+			otg->host->is_b_host = 0;
+			otg->state = OTG_STATE_B_IDLE;
+			msm_otg_reset(otg);
+			work = 1;
+		} else if (test_bit(ID_C, &motg->inputs)) {
+			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
+		}
+		break;
+	case OTG_STATE_A_IDLE:
+		otg->default_a = 1;
+		if (test_bit(ID, &motg->inputs) &&
+			!test_bit(ID_A, &motg->inputs)) {
+			pr_debug("id && !id_a\n");
+			otg->default_a = 0;
+			clear_bit(A_BUS_DROP, &motg->inputs);
+			otg->state = OTG_STATE_B_IDLE;
+			del_timer_sync(&motg->id_timer);
+			msm_otg_link_reset(motg);
+			msm_chg_enable_aca_intr(motg);
+			msm_otg_notify_charger(motg, 0);
+			work = 1;
+		} else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
+				(test_bit(A_SRP_DET, &motg->inputs) ||
+				 test_bit(A_BUS_REQ, &motg->inputs))) {
+			pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
+
+			clear_bit(A_SRP_DET, &motg->inputs);
+			/* Disable SRP detection */
+			writel_relaxed((readl_relaxed(USB_OTGSC) &
+					~OTGSC_INTSTS_MASK) &
+					~OTGSC_DPIE, USB_OTGSC);
+
+			otg->state = OTG_STATE_A_WAIT_VRISE;
+			/* VBUS should not be supplied before end of SRP pulse
+			 * generated by PET, if not complaince test fail.
+			 */
+			usleep_range(10000, 12000);
+			/* ACA: ID_A: Stop charging untill enumeration */
+			if (test_bit(ID_A, &motg->inputs))
+				msm_otg_notify_charger(motg, 0);
+			else
+				msm_hsusb_vbus_power(motg, 1);
+			msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
+		} else {
+			pr_debug("No session requested\n");
+			clear_bit(A_BUS_DROP, &motg->inputs);
+			if (test_bit(ID_A, &motg->inputs)) {
+					msm_otg_notify_charger(motg,
+							IDEV_ACA_CHG_MAX);
+			} else if (!test_bit(ID, &motg->inputs)) {
+				msm_otg_notify_charger(motg, 0);
+				/*
+				 * A-device is not providing power on VBUS.
+				 * Enable SRP detection.
+				 */
+				writel_relaxed(0x13, USB_USBMODE);
+				writel_relaxed((readl_relaxed(USB_OTGSC) &
+						~OTGSC_INTSTS_MASK) |
+						OTGSC_DPIE, USB_OTGSC);
+				mb();
+			}
+		}
+		break;
+	case OTG_STATE_A_WAIT_VRISE:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_WAIT_VRISE, &motg->tmouts)) {
+			pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			msm_otg_del_timer(motg);
+			msm_hsusb_vbus_power(motg, 0);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("a_vbus_vld\n");
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
+			msm_otg_start_host(otg, 1);
+			msm_chg_enable_aca_det(motg);
+			msm_chg_disable_aca_intr(motg);
+			mod_timer(&motg->id_timer, ID_TIMER_FREQ);
+			if (msm_chg_check_aca_intr(motg))
+				work = 1;
+		}
+		break;
+	case OTG_STATE_A_WAIT_BCON:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_WAIT_BCON, &motg->tmouts)) {
+			pr_debug("(id && id_a/b/c) || a_bus_drop ||"
+					"a_wait_bcon_tmout\n");
+			if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
+				pr_info("Device No Response\n");
+				otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
+			}
+			msm_otg_del_timer(motg);
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			clear_bit(B_CONN, &motg->inputs);
+			msm_otg_start_host(otg, 0);
+			/*
+			 * ACA: ID_A with NO accessory, just the A plug is
+			 * attached to ACA: Use IDCHG_MAX for charging
+			 */
+			if (test_bit(ID_A, &motg->inputs))
+				msm_otg_notify_charger(motg, IDEV_CHG_MIN);
+			else
+				msm_hsusb_vbus_power(motg, 0);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			clear_bit(B_CONN, &motg->inputs);
+			msm_otg_del_timer(motg);
+			msm_otg_start_host(otg, 0);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_reset(otg);
+		} else if (test_bit(ID_A, &motg->inputs)) {
+			msm_hsusb_vbus_power(motg, 0);
+		} else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
+			/*
+			 * If TA_WAIT_BCON is infinite, we don;t
+			 * turn off VBUS. Enter low power mode.
+			 */
+			if (TA_WAIT_BCON < 0)
+				pm_runtime_put_sync(otg->dev);
+		} else if (!test_bit(ID, &motg->inputs)) {
+			msm_hsusb_vbus_power(motg, 1);
+		}
+		break;
+	case OTG_STATE_A_HOST:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs)) {
+			pr_debug("id_a/b/c || a_bus_drop\n");
+			clear_bit(B_CONN, &motg->inputs);
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_host(otg, 0);
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			clear_bit(B_CONN, &motg->inputs);
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+		} else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
+			/*
+			 * a_bus_req is de-asserted when root hub is
+			 * suspended or HNP is in progress.
+			 */
+			pr_debug("!a_bus_req\n");
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_SUSPEND;
+			if (otg->host->b_hnp_enable)
+				msm_otg_start_timer(motg, TA_AIDL_BDIS,
+						A_AIDL_BDIS);
+			else
+				pm_runtime_put_sync(otg->dev);
+		} else if (!test_bit(B_CONN, &motg->inputs)) {
+			pr_debug("!b_conn\n");
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
+			if (msm_chg_check_aca_intr(motg))
+				work = 1;
+		} else if (test_bit(ID_A, &motg->inputs)) {
+			msm_otg_del_timer(motg);
+			msm_hsusb_vbus_power(motg, 0);
+			if (motg->chg_type == USB_ACA_DOCK_CHARGER)
+				msm_otg_notify_charger(motg,
+						IDEV_ACA_CHG_MAX);
+			else
+				msm_otg_notify_charger(motg,
+						IDEV_CHG_MIN - motg->mA_port);
+		} else if (!test_bit(ID, &motg->inputs)) {
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			msm_otg_notify_charger(motg, 0);
+			msm_hsusb_vbus_power(motg, 1);
+		}
+		break;
+	case OTG_STATE_A_SUSPEND:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_AIDL_BDIS, &motg->tmouts)) {
+			pr_debug("id_a/b/c || a_bus_drop ||"
+					"a_aidl_bdis_tmout\n");
+			msm_otg_del_timer(motg);
+			clear_bit(B_CONN, &motg->inputs);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			msm_otg_del_timer(motg);
+			clear_bit(B_CONN, &motg->inputs);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+		} else if (!test_bit(B_CONN, &motg->inputs) &&
+				otg->host->b_hnp_enable) {
+			pr_debug("!b_conn && b_hnp_enable");
+			otg->state = OTG_STATE_A_PERIPHERAL;
+			msm_otg_host_hnp_enable(otg, 1);
+			otg->gadget->is_a_peripheral = 1;
+			msm_otg_start_peripheral(otg, 1);
+		} else if (!test_bit(B_CONN, &motg->inputs) &&
+				!otg->host->b_hnp_enable) {
+			pr_debug("!b_conn && !b_hnp_enable");
+			/*
+			 * bus request is dropped during suspend.
+			 * acquire again for next device.
+			 */
+			set_bit(A_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
 		} else if (test_bit(ID_A, &motg->inputs)) {
 			msm_hsusb_vbus_power(motg, 0);
 			msm_otg_notify_charger(motg,
-					IDEV_ACA_CHG_MAX - motg->mA_port);
+					IDEV_CHG_MIN - motg->mA_port);
 		} else if (!test_bit(ID, &motg->inputs)) {
 			msm_otg_notify_charger(motg, 0);
 			msm_hsusb_vbus_power(motg, 1);
 		}
 		break;
+	case OTG_STATE_A_PERIPHERAL:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs)) {
+			pr_debug("id _f/b/c || a_bus_drop\n");
+			/* Clear BIDL_ADIS timer */
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget->is_a_peripheral = 0;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			/* Clear BIDL_ADIS timer */
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget->is_a_peripheral = 0;
+			msm_otg_start_host(otg, 0);
+		} else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
+			pr_debug("a_bidl_adis_tmout\n");
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget->is_a_peripheral = 0;
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			set_bit(A_BUS_REQ, &motg->inputs);
+			msm_otg_host_hnp_enable(otg, 0);
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
+		} else if (test_bit(ID_A, &motg->inputs)) {
+			msm_hsusb_vbus_power(motg, 0);
+			msm_otg_notify_charger(motg,
+					IDEV_CHG_MIN - motg->mA_port);
+		} else if (!test_bit(ID, &motg->inputs)) {
+			msm_otg_notify_charger(motg, 0);
+			msm_hsusb_vbus_power(motg, 1);
+		}
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
+			clear_bit(A_VBUS_VLD, &motg->inputs);
+			otg->state = OTG_STATE_A_IDLE;
+			work = 1;
+		}
+		break;
+	case OTG_STATE_A_VBUS_ERR:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_CLR_ERR, &motg->inputs)) {
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			msm_otg_notify_charger(motg, 0);
+		}
+		break;
 	default:
 		break;
 	}
+	if (work)
+		queue_work(system_nrt_wq, &motg->sm_work);
 }
 
 static irqreturn_t msm_otg_irq(int irq, void *data)
 {
 	struct msm_otg *motg = data;
 	struct otg_transceiver *otg = &motg->otg;
-	u32 otgsc = 0, usbsts;
+	u32 otgsc = 0, usbsts, pc;
+	bool work = 0;
+	irqreturn_t ret = IRQ_HANDLED;
 
 	if (atomic_read(&motg->in_lpm)) {
 		pr_debug("OTG IRQ: in LPM\n");
@@ -1983,44 +2536,144 @@
 	}
 
 	usbsts = readl(USB_USBSTS);
-	if ((usbsts & PHY_ALT_INT)) {
-		dev_dbg(otg->dev, "PHY_ALT interrupt\n");
-		writel(PHY_ALT_INT, USB_USBSTS);
-		if (msm_chg_check_aca_intr(motg)) {
-			dev_dbg(otg->dev, "ACA work from IRQ\n");
-			schedule_work(&motg->sm_work);
-		}
-		return IRQ_HANDLED;
-	}
-
 	otgsc = readl(USB_OTGSC);
-	if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
+
+	if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
 		return IRQ_NONE;
 
 	if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
 		if (otgsc & OTGSC_ID) {
-			dev_dbg(otg->dev, "ID set\n");
+			pr_debug("Id set\n");
 			set_bit(ID, &motg->inputs);
 		} else {
-			dev_dbg(otg->dev, "ID clear\n");
+			pr_debug("Id clear\n");
+			/*
+			 * Assert a_bus_req to supply power on
+			 * VBUS when Micro/Mini-A cable is connected
+			 * with out user intervention.
+			 */
+			set_bit(A_BUS_REQ, &motg->inputs);
 			clear_bit(ID, &motg->inputs);
 			msm_chg_enable_aca_det(motg);
 		}
-		schedule_work(&motg->sm_work);
-	} else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
+		writel_relaxed(otgsc, USB_OTGSC);
+		work = 1;
+	} else if (otgsc & OTGSC_DPIS) {
+		pr_debug("DPIS detected\n");
+		writel_relaxed(otgsc, USB_OTGSC);
+		set_bit(A_SRP_DET, &motg->inputs);
+		set_bit(A_BUS_REQ, &motg->inputs);
+		work = 1;
+	} else if (otgsc & OTGSC_BSVIS) {
+		writel_relaxed(otgsc, USB_OTGSC);
+		/*
+		 * BSV interrupt comes when operating as an A-device
+		 * (VBUS on/off).
+		 * But, handle BSV when charger is removed from ACA in ID_A
+		 */
+		if ((otg->state >= OTG_STATE_A_IDLE) &&
+			!test_bit(ID_A, &motg->inputs))
+			return IRQ_HANDLED;
 		if (otgsc & OTGSC_BSV) {
-			dev_dbg(otg->dev, "BSV set\n");
+			pr_debug("BSV set\n");
 			set_bit(B_SESS_VLD, &motg->inputs);
 		} else {
-			dev_dbg(otg->dev, "BSV clear\n");
+			pr_debug("BSV clear\n");
 			clear_bit(B_SESS_VLD, &motg->inputs);
 			msm_chg_check_aca_intr(motg);
 		}
-		schedule_work(&motg->sm_work);
+		work = 1;
+	} else if (usbsts & STS_PCI) {
+		pc = readl_relaxed(USB_PORTSC);
+		pr_debug("portsc = %x\n", pc);
+		ret = IRQ_NONE;
+		/*
+		 * HCD Acks PCI interrupt. We use this to switch
+		 * between different OTG states.
+		 */
+		work = 1;
+		switch (otg->state) {
+		case OTG_STATE_A_SUSPEND:
+			if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
+					!(pc & PORTSC_CCS)) {
+				pr_debug("B_CONN clear\n");
+				clear_bit(B_CONN, &motg->inputs);
+				msm_otg_del_timer(motg);
+			}
+			break;
+		case OTG_STATE_A_PERIPHERAL:
+			/*
+			 * A-peripheral observed activity on bus.
+			 * clear A_BIDL_ADIS timer.
+			 */
+			msm_otg_del_timer(motg);
+			work = 0;
+			break;
+		case OTG_STATE_B_WAIT_ACON:
+			if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
+				pr_debug("A_CONN set\n");
+				set_bit(A_CONN, &motg->inputs);
+				/* Clear ASE0_BRST timer */
+				msm_otg_del_timer(motg);
+			}
+			break;
+		case OTG_STATE_B_HOST:
+			if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
+				pr_debug("A_CONN clear\n");
+				clear_bit(A_CONN, &motg->inputs);
+				msm_otg_del_timer(motg);
+			}
+			break;
+		case OTG_STATE_A_WAIT_BCON:
+			if (TA_WAIT_BCON < 0)
+				set_bit(A_BUS_REQ, &motg->inputs);
+		default:
+			work = 0;
+			break;
+		}
+	} else if (usbsts & STS_URI) {
+		ret = IRQ_NONE;
+		switch (otg->state) {
+		case OTG_STATE_A_PERIPHERAL:
+			/*
+			 * A-peripheral observed activity on bus.
+			 * clear A_BIDL_ADIS timer.
+			 */
+			msm_otg_del_timer(motg);
+			work = 0;
+			break;
+		default:
+			work = 0;
+			break;
+		}
+	} else if (usbsts & STS_SLI) {
+		ret = IRQ_NONE;
+		work = 0;
+		switch (otg->state) {
+		case OTG_STATE_B_PERIPHERAL:
+			if (otg->gadget->b_hnp_enable) {
+				set_bit(A_BUS_SUSPEND, &motg->inputs);
+				set_bit(B_BUS_REQ, &motg->inputs);
+				work = 1;
+			}
+			break;
+		case OTG_STATE_A_PERIPHERAL:
+			msm_otg_start_timer(motg, TA_BIDL_ADIS,
+					A_BIDL_ADIS);
+			break;
+		default:
+			break;
+		}
+	} else if ((usbsts & PHY_ALT_INT)) {
+		writel_relaxed(PHY_ALT_INT, USB_USBSTS);
+		if (msm_chg_check_aca_intr(motg))
+			work = 1;
+		ret = IRQ_HANDLED;
 	}
+	if (work)
+		queue_work(system_nrt_wq, &motg->sm_work);
 
-	writel(otgsc, USB_OTGSC);
-	return IRQ_HANDLED;
+	return ret;
 }
 
 static void msm_otg_set_vbus_state(int online)
@@ -2043,7 +2696,7 @@
 		return;
 	}
 
-	schedule_work(&motg->sm_work);
+	queue_work(system_nrt_wq, &motg->sm_work);
 }
 
 static irqreturn_t msm_pmic_id_irq(int irq, void *data)
@@ -2059,10 +2712,11 @@
 	} else {
 		pr_debug("PMIC: ID clear\n");
 		clear_bit(ID, &motg->inputs);
+		set_bit(A_BUS_REQ, &motg->inputs);
 	}
 
 	if (motg->otg.state != OTG_STATE_UNDEFINED)
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 
 	return IRQ_HANDLED;
 }
@@ -2158,7 +2812,7 @@
 	}
 
 	pm_runtime_resume(otg->dev);
-	schedule_work(&motg->sm_work);
+	queue_work(system_nrt_wq, &motg->sm_work);
 out:
 	return status;
 }
@@ -2171,6 +2825,27 @@
 	.release = single_release,
 };
 
+static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+	struct otg_transceiver *otg = &motg->otg;
+
+	seq_printf(s, "%s\n", otg_state_string(otg->state));
+	return 0;
+}
+
+static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_show_otg_state, inode->i_private);
+}
+
+const struct file_operations msm_otg_state_fops = {
+	.open = msm_otg_otg_state_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
 {
 	struct msm_otg *motg = s->private;
@@ -2232,13 +2907,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 +2974,51 @@
 	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;
+	}
+
+	msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
+				msm_otg_dbg_root, motg, &msm_otg_state_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
 	return 0;
 }
 
@@ -2514,7 +3256,7 @@
 		goto free_regs;
 	}
 
-	motg->xo_handle = clk_get(&pdev->dev, "xo");
+	motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
 	if (IS_ERR(motg->xo_handle)) {
 		dev_err(&pdev->dev, "%s not able to get the handle "
 			"to vote for TCXO D0 buffer\n", __func__);
@@ -2522,7 +3264,7 @@
 		goto free_regs;
 	}
 
-	ret = clk_prepare_enable(motg->xo_handle);
+	ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
 	if (ret) {
 		dev_err(&pdev->dev, "%s failed to vote for TCXO "
 			"D0 buffer%d\n", __func__, ret);
@@ -2549,6 +3291,15 @@
 		goto free_init_vddcx;
 	}
 
+	if (pdata->mhl_enable) {
+		mhl_analog_switch = devm_regulator_get(motg->otg.dev,
+							"mhl_ext_3p3v");
+		if (IS_ERR(mhl_analog_switch)) {
+			dev_err(&pdev->dev, "Unable to get mhl_analog_switch\n");
+			goto free_ldo_init;
+		}
+	}
+
 	ret = msm_hsusb_ldo_enable(motg, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vreg enable failed\n");
@@ -2562,6 +3313,7 @@
 	mb();
 
 	wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
+	msm_otg_init_timer(motg);
 	INIT_WORK(&motg->sm_work, msm_otg_sm_work);
 	INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
 	setup_timer(&motg->id_timer, msm_otg_id_timer_func,
@@ -2577,6 +3329,8 @@
 	otg->set_host = msm_otg_set_host;
 	otg->set_peripheral = msm_otg_set_peripheral;
 	otg->set_power = msm_otg_set_power;
+	otg->start_hnp = msm_otg_start_hnp;
+	otg->start_srp = msm_otg_start_srp;
 	otg->set_suspend = msm_otg_set_suspend;
 
 	otg->io_ops = &msm_otg_io_ops;
@@ -2642,6 +3396,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;
@@ -2660,9 +3416,9 @@
 	msm_hsusb_init_vddcx(motg, 0);
 devote_xo_handle:
 	clk_disable_unprepare(motg->pclk);
-	clk_disable_unprepare(motg->xo_handle);
+	msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
 free_xo_handle:
-	clk_put(motg->xo_handle);
+	msm_xo_put(motg->xo_handle);
 free_regs:
 	iounmap(motg->regs);
 put_pclk:
@@ -2728,7 +3484,7 @@
 
 	clk_disable_unprepare(motg->pclk);
 	clk_disable_unprepare(motg->core_clk);
-	clk_put(motg->xo_handle);
+	msm_xo_put(motg->xo_handle);
 	msm_hsusb_ldo_enable(motg, 0);
 	msm_hsusb_ldo_init(motg, 0);
 	msm_hsusb_init_vddcx(motg, 0);
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
deleted file mode 100644
index b2e6491..0000000
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Renesas USB Controller Drivers
-#
-
-config USB_RENESAS_USBHS
-	tristate 'Renesas USBHS controller'
-	depends on SUPERH || ARCH_SHMOBILE
-	default n
-	help
-	   Renesas USBHS is a discrete USB host and peripheral controller chip
-	   that supports both full and high speed USB 2.0 data transfers.
-	   It has nine or more configurable endpoints, and endpoint zero.
-
-	   Say "y" to link the driver statically, or "m" to build a
-	   dynamically linked module called "renesas_usbhs" and force all
-	   gadget drivers to also be dynamically linked.
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/Kconfig b/drivers/usb/serial/Kconfig
index b71e309..caa5fda 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -651,6 +651,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ssu100.
 
+config USB_SERIAL_CSVT
+	tristate "USB serial driver for Circuit-Switched Video Telephony"
+	help
+	  Say Y here if you want to use usb serial driver for Circuit-Switched
+	  Video Telephony
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called csvt.
+
 config USB_SERIAL_DEBUG
 	tristate "USB Debugging Device"
 	help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 9e536ee..2d085b2 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -60,3 +60,4 @@
 obj-$(CONFIG_USB_SERIAL_XIRCOM)			+= keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)		+= vivopay-serial.o
 obj-$(CONFIG_USB_SERIAL_ZIO)			+= zio.o
+obj-$(CONFIG_USB_SERIAL_CSVT)			+= csvt.o
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 5cdb9d9..18e875b 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -42,7 +42,7 @@
  * Version information
  */
 
-#define DRIVER_VERSION "v0.6"
+#define DRIVER_VERSION "v0.7"
 #define DRIVER_AUTHOR "Bart Hartgers <bart.hartgers+ark3116@gmail.com>"
 #define DRIVER_DESC "USB ARK3116 serial/IrDA driver"
 #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA"
@@ -380,10 +380,6 @@
 		goto err_out;
 	}
 
-	/* setup termios */
-	if (tty)
-		ark3116_set_termios(tty, port, NULL);
-
 	/* remove any data still left: also clears error state */
 	ark3116_read_reg(serial, UART_RX, buf);
 
@@ -406,6 +402,10 @@
 	/* enable DMA */
 	ark3116_write_reg(port->serial, UART_FCR, UART_FCR_DMA_SELECT);
 
+	/* setup termios */
+	if (tty)
+		ark3116_set_termios(tty, port, NULL);
+
 err_out:
 	kfree(buf);
 	return result;
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fd67cc5..a515237 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -39,6 +39,8 @@
 	struct usb_serial_port *port);
 static void cp210x_get_termios_port(struct usb_serial_port *port,
 	unsigned int *cflagp, unsigned int *baudp);
+static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
+							struct ktermios *);
 static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
 							struct ktermios*);
 static int cp210x_tiocmget(struct tty_struct *);
@@ -92,6 +94,7 @@
 	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
 	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
 	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
+	{ USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
 	{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
 	{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
 	{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
@@ -137,6 +140,7 @@
 	{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
 	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
 	{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
+	{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
 	{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
 	{ } /* Terminating Entry */
 };
@@ -200,6 +204,8 @@
 #define CP210X_EMBED_EVENTS	0x15
 #define CP210X_GET_EVENTSTATE	0x16
 #define CP210X_SET_CHARS	0x19
+#define CP210X_GET_BAUDRATE	0x1D
+#define CP210X_SET_BAUDRATE	0x1E
 
 /* CP210X_IFC_ENABLE */
 #define UART_ENABLE		0x0001
@@ -353,8 +359,8 @@
  * Quantises the baud rate as per AN205 Table 1
  */
 static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
-	if      (baud <= 56)       baud = 0;
-	else if (baud <= 300)      baud = 300;
+	if (baud <= 300)
+		baud = 300;
 	else if (baud <= 600)      baud = 600;
 	else if (baud <= 1200)     baud = 1200;
 	else if (baud <= 1800)     baud = 1800;
@@ -382,17 +388,15 @@
 	else if (baud <= 491520)   baud = 460800;
 	else if (baud <= 567138)   baud = 500000;
 	else if (baud <= 670254)   baud = 576000;
-	else if (baud <= 1053257)  baud = 921600;
-	else if (baud <= 1474560)  baud = 1228800;
-	else if (baud <= 2457600)  baud = 1843200;
-	else                       baud = 3686400;
+	else if (baud < 1000000)
+		baud = 921600;
+	else if (baud > 2000000)
+		baud = 2000000;
 	return baud;
 }
 
 static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	int result;
-
 	dbg("%s - port %d", __func__, port->number);
 
 	if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) {
@@ -401,13 +405,14 @@
 		return -EPROTO;
 	}
 
-	result = usb_serial_generic_open(tty, port);
-	if (result)
-		return result;
-
 	/* Configure the termios structure */
 	cp210x_get_termios(tty, port);
-	return 0;
+
+	/* The baud rate must be initialised on cp2104 */
+	if (tty)
+		cp210x_change_speed(tty, port, NULL);
+
+	return usb_serial_generic_open(tty, port);
 }
 
 static void cp210x_close(struct usb_serial_port *port)
@@ -459,10 +464,7 @@
 
 	dbg("%s - port %d", __func__, port->number);
 
-	cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2);
-	/* Convert to baudrate */
-	if (baud)
-		baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
+	cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
 
 	dbg("%s - baud rate = %d", __func__, baud);
 	*baudp = baud;
@@ -576,11 +578,64 @@
 	*cflagp = cflag;
 }
 
+/*
+ * CP2101 supports the following baud rates:
+ *
+ *	300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
+ *	38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
+ *
+ * CP2102 and CP2103 support the following additional rates:
+ *
+ *	4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
+ *	576000
+ *
+ * The device will map a requested rate to a supported one, but the result
+ * of requests for rates greater than 1053257 is undefined (see AN205).
+ *
+ * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
+ * respectively, with an error less than 1%. The actual rates are determined
+ * by
+ *
+ *	div = round(freq / (2 x prescale x request))
+ *	actual = freq / (2 x prescale x div)
+ *
+ * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
+ * or 1 otherwise.
+ * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
+ * otherwise.
+ */
+static void cp210x_change_speed(struct tty_struct *tty,
+		struct usb_serial_port *port, struct ktermios *old_termios)
+{
+	u32 baud;
+
+	baud = tty->termios->c_ospeed;
+
+	/* This maps the requested rate to a rate valid on cp2102 or cp2103,
+	 * or to an arbitrary rate in [1M,2M].
+	 *
+	 * NOTE: B0 is not implemented.
+	 */
+	baud = cp210x_quantise_baudrate(baud);
+
+	dbg("%s - setting baud rate to %u", __func__, baud);
+	if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud,
+							sizeof(baud))) {
+		dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
+		if (old_termios)
+			baud = old_termios->c_ospeed;
+		else
+			baud = 9600;
+	}
+
+	tty_encode_baud_rate(tty, baud, baud);
+}
+
 static void cp210x_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
 	unsigned int cflag, old_cflag;
-	unsigned int baud = 0, bits;
+	unsigned int bits;
 	unsigned int modem_ctl[4];
 
 	dbg("%s - port %d", __func__, port->number);
@@ -591,20 +646,9 @@
 	tty->termios->c_cflag &= ~CMSPAR;
 	cflag = tty->termios->c_cflag;
 	old_cflag = old_termios->c_cflag;
-	baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty));
 
-	/* If the baud rate is to be updated*/
-	if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
-		dbg("%s - Setting baud rate to %d baud", __func__,
-				baud);
-		if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
-					((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
-			dbg("Baud rate requested not supported by device");
-			baud = tty_termios_baud_rate(old_termios);
-		}
-	}
-	/* Report back the resulting baud rate */
-	tty_encode_baud_rate(tty, baud, baud);
+	if (tty->termios->c_ospeed != old_termios->c_ospeed)
+		cp210x_change_speed(tty, port, old_termios);
 
 	/* If the number of data bits is to be updated */
 	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
diff --git a/drivers/usb/serial/csvt.c b/drivers/usb/serial/csvt.c
new file mode 100644
index 0000000..28eba8a
--- /dev/null
+++ b/drivers/usb/serial/csvt.c
@@ -0,0 +1,446 @@
+/* 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/slab.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/serial.h>
+#include <asm/unaligned.h>
+
+
+/* output control lines*/
+#define CSVT_CTRL_DTR		0x01
+#define CSVT_CTRL_RTS		0x02
+
+/* input control lines*/
+#define CSVT_CTRL_CTS		0x01
+#define CSVT_CTRL_DSR		0x02
+#define CSVT_CTRL_RI		0x04
+#define CSVT_CTRL_CD		0x08
+
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+struct csvt_ctrl_dev {
+	struct mutex		dev_lock;
+
+	/* input control lines (DSR, CTS, CD, RI) */
+	unsigned int		cbits_tolocal;
+
+	/* output control lines (DTR, RTS) */
+	unsigned int		cbits_tomdm;
+};
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0xfe, 0xff)},
+	{}, /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver csvt_driver = {
+	.name			= "qc_csvt",
+	.probe			= usb_serial_probe,
+	.disconnect		= usb_serial_disconnect,
+	.id_table		= id_table,
+	.suspend		= usb_serial_suspend,
+	.resume			= usb_serial_resume,
+	.supports_autosuspend	= true,
+};
+
+#define CSVT_IFC_NUM	4
+
+static int csvt_probe(struct usb_serial *serial, const struct usb_device_id *id)
+{
+	struct usb_host_interface	*intf =
+		serial->interface->cur_altsetting;
+
+	pr_debug("%s:\n", __func__);
+
+	if (intf->desc.bInterfaceNumber != CSVT_IFC_NUM)
+		return -ENODEV;
+
+	usb_enable_autosuspend(serial->dev);
+
+	return 0;
+}
+
+static int csvt_ctrl_write_cmd(struct csvt_ctrl_dev	*dev,
+	struct usb_serial_port *port)
+{
+	struct usb_device	*udev = port->serial->dev;
+	struct usb_interface	*iface = port->serial->interface;
+	unsigned int		iface_num;
+	int			retval = 0;
+
+	retval = usb_autopm_get_interface(iface);
+	if (retval < 0) {
+		dev_err(&port->dev, "%s: Unable to resume interface: %d\n",
+			__func__, retval);
+		return retval;
+	}
+
+	dev_dbg(&port->dev, "%s: cbits to mdm 0x%x\n", __func__,
+		dev->cbits_tomdm);
+
+	iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
+	retval = 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,
+		iface_num,
+		NULL, 0, USB_CTRL_SET_TIMEOUT);
+	usb_autopm_put_interface(iface);
+
+	return retval;
+}
+
+static void csvt_ctrl_dtr_rts(struct usb_serial_port *port, int on)
+{
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	if (!dev)
+		return;
+
+	dev_dbg(&port->dev, "%s", __func__);
+
+	mutex_lock(&dev->dev_lock);
+	if (on) {
+		dev->cbits_tomdm |= CSVT_CTRL_DTR;
+		dev->cbits_tomdm |= CSVT_CTRL_RTS;
+	} else {
+		dev->cbits_tomdm &= ~CSVT_CTRL_DTR;
+		dev->cbits_tomdm &= ~CSVT_CTRL_RTS;
+	}
+	mutex_unlock(&dev->dev_lock);
+
+	csvt_ctrl_write_cmd(dev, port);
+}
+
+static int get_serial_info(struct usb_serial_port *port,
+			   struct serial_struct __user *retinfo)
+{
+	struct serial_struct	tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.line            = port->serial->minor;
+	tmp.port            = port->number;
+	tmp.baud_base       = tty_get_baud_rate(port->port.tty);
+	tmp.close_delay	    = port->port.close_delay / 10;
+	tmp.closing_wait    =
+		port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+				 ASYNC_CLOSING_WAIT_NONE :
+				 port->port.closing_wait / 10;
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_serial_info(struct usb_serial_port *port,
+			   struct serial_struct __user *newinfo)
+{
+	struct serial_struct	new_serial;
+	unsigned int		closing_wait;
+	unsigned int		close_delay;
+	int			retval = 0;
+
+	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+		return -EFAULT;
+
+	close_delay = new_serial.close_delay * 10;
+	closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+			ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+	mutex_lock(&port->port.mutex);
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((close_delay != port->port.close_delay) ||
+		    (closing_wait != port->port.closing_wait))
+			retval = -EPERM;
+		else
+			retval = -EOPNOTSUPP;
+	} else {
+		port->port.close_delay  = close_delay;
+		port->port.closing_wait = closing_wait;
+	}
+
+	mutex_unlock(&port->port.mutex);
+	return retval;
+}
+
+static int csvt_ctrl_ioctl(struct tty_struct *tty, unsigned int cmd,
+	unsigned long arg)
+{
+	struct usb_serial_port	*port = tty->driver_data;
+
+	dev_dbg(&port->dev, "%s cmd 0x%04x", __func__, cmd);
+
+	switch (cmd) {
+	case TIOCGSERIAL:
+		return get_serial_info(port,
+				       (struct serial_struct __user *) arg);
+	case TIOCSSERIAL:
+		return set_serial_info(port,
+				       (struct serial_struct __user *) arg);
+	default:
+		break;
+	}
+
+	dev_err(&port->dev, "%s arg not supported", __func__);
+
+	return -ENOIOCTLCMD;
+}
+
+static int csvt_ctrl_tiocmget(struct tty_struct *tty)
+{
+	struct usb_serial_port	*port = tty->driver_data;
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+	unsigned int		control_state = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->dev_lock);
+	control_state = (dev->cbits_tomdm & CSVT_CTRL_DTR ? TIOCM_DTR : 0) |
+		(dev->cbits_tomdm & CSVT_CTRL_RTS ? TIOCM_RTS : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_DSR ? TIOCM_DSR : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_RI ? TIOCM_RI : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_CD ? TIOCM_CD : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_CTS ? TIOCM_CTS : 0);
+	mutex_unlock(&dev->dev_lock);
+
+	dev_dbg(&port->dev, "%s -- %x", __func__, control_state);
+
+	return control_state;
+}
+
+static int csvt_ctrl_tiocmset(struct tty_struct *tty,
+			       unsigned int set, unsigned int clear)
+{
+	struct usb_serial_port	*port = tty->driver_data;
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	if (!dev)
+		return -ENODEV;
+
+	dev_dbg(&port->dev, "%s\n", __func__);
+
+	mutex_lock(&dev->dev_lock);
+	if (set & CSVT_CTRL_DTR)
+		dev->cbits_tomdm |= TIOCM_DTR;
+	if (set & CSVT_CTRL_RTS)
+		dev->cbits_tomdm |= TIOCM_RTS;
+
+	if (clear & CSVT_CTRL_DTR)
+		dev->cbits_tomdm &= ~TIOCM_DTR;
+	if (clear & CSVT_CTRL_RTS)
+		dev->cbits_tomdm &= ~TIOCM_RTS;
+	mutex_unlock(&dev->dev_lock);
+
+	return csvt_ctrl_write_cmd(dev, port);
+}
+
+static void csvt_ctrl_set_termios(struct tty_struct *tty,
+			  struct usb_serial_port *port,
+			  struct ktermios *old_termios)
+{
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	if (!dev)
+		return;
+
+	dev_dbg(&port->dev, "%s", __func__);
+
+	/* Doesn't support option setting */
+	tty_termios_copy_hw(tty->termios, old_termios);
+
+	csvt_ctrl_write_cmd(dev, port);
+}
+
+static void csvt_ctrl_int_cb(struct urb *urb)
+{
+	int				status;
+	struct usb_cdc_notification	*ctrl;
+	struct usb_serial_port		*port = urb->context;
+	struct csvt_ctrl_dev		*dev;
+	unsigned int			ctrl_bits;
+	unsigned char			*data;
+
+	switch (urb->status) {
+	case 0:
+		/*success*/
+		break;
+	case -ESHUTDOWN:
+	case -ENOENT:
+	case -ECONNRESET:
+	case -EPROTO:
+		 /* unplug */
+		 return;
+	case -EPIPE:
+		dev_err(&port->dev, "%s: stall on int endpoint\n", __func__);
+		/* TBD : halt to be cleared in work */
+	case -EOVERFLOW:
+	default:
+		pr_debug_ratelimited("%s: non zero urb status = %d\n",
+					__func__, urb->status);
+		goto resubmit_int_urb;
+	}
+
+	dev = usb_get_serial_port_data(port);
+	if (!dev)
+		return;
+
+	ctrl = urb->transfer_buffer;
+	data = (unsigned char *)(ctrl + 1);
+
+	usb_serial_debug_data(debug, &port->dev, __func__,
+					urb->actual_length, data);
+
+	switch (ctrl->bNotificationType) {
+	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+		dev_dbg(&port->dev, "%s network\n", ctrl->wValue ?
+					"connected to" : "disconnected from");
+		break;
+	case USB_CDC_NOTIFY_SERIAL_STATE:
+		ctrl_bits = get_unaligned_le16(data);
+		dev_dbg(&port->dev, "serial state: %d\n", ctrl_bits);
+		dev->cbits_tolocal = ctrl_bits;
+		break;
+	default:
+		dev_err(&port->dev, "%s: unknown notification %d received:"
+			"index %d len %d data0 %d data1 %d",
+			__func__, ctrl->bNotificationType, ctrl->wIndex,
+			ctrl->wLength, data[0], data[1]);
+	}
+
+resubmit_int_urb:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status)
+		dev_err(&port->dev, "%s: Error re-submitting Int URB %d\n",
+		__func__, status);
+
+}
+
+static int csvt_ctrl_open(struct tty_struct *tty,
+					struct usb_serial_port *port)
+{
+	int	retval;
+
+	dev_dbg(&port->dev, "%s port %d", __func__, port->number);
+
+	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (retval) {
+		dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
+		return retval;
+	}
+
+	retval = usb_serial_generic_open(tty, port);
+	if (retval)
+		usb_kill_urb(port->interrupt_in_urb);
+
+	return retval;
+}
+
+static void csvt_ctrl_close(struct usb_serial_port *port)
+{
+	dev_dbg(&port->dev, "%s port %d", __func__, port->number);
+
+	usb_serial_generic_close(port);
+	usb_kill_urb(port->interrupt_in_urb);
+}
+
+static int csvt_ctrl_attach(struct usb_serial *serial)
+{
+	struct csvt_ctrl_dev	*dev;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	mutex_init(&dev->dev_lock);
+	usb_set_serial_port_data(serial->port[0], dev);
+
+	return 0;
+}
+
+static void csvt_ctrl_release(struct usb_serial *serial)
+{
+	struct usb_serial_port	*port = serial->port[0];
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	dev_dbg(&port->dev, "%s", __func__);
+
+	kfree(dev);
+	usb_set_serial_port_data(port, NULL);
+}
+
+static struct usb_serial_driver csvt_device = {
+	.driver			= {
+		.owner	= THIS_MODULE,
+		.name	= "qc_csvt",
+	},
+	.description		= "qc_csvt",
+	.id_table		= id_table,
+	.usb_driver		= &csvt_driver,
+	.num_ports		= 1,
+	.open			= csvt_ctrl_open,
+	.close			= csvt_ctrl_close,
+	.probe			= csvt_probe,
+	.dtr_rts		= csvt_ctrl_dtr_rts,
+	.tiocmget		= csvt_ctrl_tiocmget,
+	.tiocmset		= csvt_ctrl_tiocmset,
+	.ioctl			= csvt_ctrl_ioctl,
+	.set_termios		= csvt_ctrl_set_termios,
+	.read_int_callback	= csvt_ctrl_int_cb,
+	.attach			= csvt_ctrl_attach,
+	.release		= csvt_ctrl_release,
+};
+
+static int __init csvt_init(void)
+{
+	int	retval;
+
+	retval = usb_serial_register(&csvt_device);
+	if (retval) {
+		err("%s: usb serial register failed\n", __func__);
+		return retval;
+	}
+
+	retval = usb_register(&csvt_driver);
+	if (retval) {
+		usb_serial_deregister(&csvt_device);
+		err("%s: usb register failed\n", __func__);
+		return retval;
+	}
+
+	return 0;
+}
+
+static void __exit csvt_exit(void)
+{
+	usb_deregister(&csvt_driver);
+	usb_serial_deregister(&csvt_device);
+}
+
+module_init(csvt_init);
+module_exit(csvt_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index f968a3d..78c7d42 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -156,6 +156,7 @@
  * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
  */
 static struct usb_device_id id_table_combined [] = {
+	{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
@@ -206,6 +207,8 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) },
 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
@@ -732,6 +735,7 @@
 	{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
 	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID),
@@ -744,6 +748,8 @@
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID),
+		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
@@ -790,6 +796,7 @@
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE(HORNBY_VID, HORNBY_ELITE_PID) },
 	{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
 	{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -798,6 +805,8 @@
 	{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
 	{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+	{ USB_DEVICE(FTDI_VID, TI_XDS100V2_PID),
+		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
 	{ USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
 	{ USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
@@ -829,11 +838,13 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
 	{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
+	{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
 	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -1320,8 +1331,7 @@
 		goto check_and_exit;
 	}
 
-	if ((new_serial.baud_base != priv->baud_base) &&
-	    (new_serial.baud_base < 9600)) {
+	if (new_serial.baud_base != priv->baud_base) {
 		mutex_unlock(&priv->cfg_lock);
 		return -EINVAL;
 	}
@@ -1810,6 +1820,7 @@
 
 static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
+	struct ktermios dummy;
 	struct usb_device *dev = port->serial->dev;
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	int result;
@@ -1828,8 +1839,10 @@
 	   This is same behaviour as serial.c/rs_open() - Kuba */
 
 	/* ftdi_set_termios  will send usb control messages */
-	if (tty)
-		ftdi_set_termios(tty, port, tty->termios);
+	if (tty) {
+		memset(&dummy, 0, sizeof(dummy));
+		ftdi_set_termios(tty, port, &dummy);
+	}
 
 	/* Start reading from the device */
 	result = usb_serial_generic_open(tty, port);
@@ -2075,13 +2088,19 @@
 
 	cflag = termios->c_cflag;
 
-	/* FIXME -For this cut I don't care if the line is really changing or
-	   not  - so just do the change regardless  - should be able to
-	   compare old_termios and tty->termios */
+	if (old_termios->c_cflag == termios->c_cflag
+	    && old_termios->c_ispeed == termios->c_ispeed
+	    && old_termios->c_ospeed == termios->c_ospeed)
+		goto no_c_cflag_changes;
+
 	/* NOTE These routines can get interrupted by
 	   ftdi_sio_read_bulk_callback  - need to examine what this means -
 	   don't see any problems yet */
 
+	if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) ==
+	    (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)))
+		goto no_data_parity_stop_changes;
+
 	/* Set number of data bits, parity, stop bits */
 
 	urb_value = 0;
@@ -2122,6 +2141,7 @@
 	}
 
 	/* Now do the baudrate */
+no_data_parity_stop_changes:
 	if ((cflag & CBAUD) == B0) {
 		/* Disable flow control */
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -2149,6 +2169,7 @@
 
 	/* Set flow control */
 	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
+no_c_cflag_changes:
 	if (cflag & CRTSCTS) {
 		dbg("%s Setting to CRTSCTS flow control", __func__);
 		if (usb_control_msg(dev,
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 19156d1..4eb7715 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -39,6 +39,13 @@
 /* www.candapter.com Ewert Energy Systems CANdapter device */
 #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
 
+/*
+ * Texas Instruments XDS100v2 JTAG / BeagleBone A3
+ * http://processors.wiki.ti.com/index.php/XDS100
+ * http://beagleboard.org/bone
+ */
+#define TI_XDS100V2_PID		0xa6d0
+
 #define FTDI_NXTCAM_PID		0xABB8 /* NXTCam for Mindstorms NXT */
 
 /* US Interface Navigator (http://www.usinterface.com/) */
@@ -54,6 +61,7 @@
 /* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */
 #define LMI_LM3S_DEVEL_BOARD_PID	0xbcd8
 #define LMI_LM3S_EVAL_BOARD_PID		0xbcd9
+#define LMI_LM3S_ICDI_BOARD_PID		0xbcda
 
 #define FTDI_TURTELIZER_PID	0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */
 
@@ -111,6 +119,7 @@
 
 /* Propox devices */
 #define FTDI_PROPOX_JTAGCABLEII_PID	0xD738
+#define FTDI_PROPOX_ISPCABLEIII_PID	0xD739
 
 /* Lenz LI-USB Computer Interface. */
 #define FTDI_LENZ_LIUSB_PID	0xD780
@@ -420,9 +429,11 @@
 #define PROTEGO_SPECIAL_4	0xFC73	/* special/unknown device */
 
 /*
- * DSS-20 Sync Station for Sony Ericsson P800
+ * Sony Ericsson product ids
  */
-#define FTDI_DSS20_PID          0xFC82
+#define FTDI_DSS20_PID		0xFC82	/* DSS-20 Sync Station for Sony Ericsson P800 */
+#define FTDI_URBAN_0_PID	0xFC8A	/* Sony Ericsson Urban, uart #0 */
+#define FTDI_URBAN_1_PID	0xFC8B	/* Sony Ericsson Urban, uart #1 */
 
 /* www.irtrans.de device */
 #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
@@ -521,6 +532,12 @@
 #define ADI_GNICEPLUS_PID	0xF001
 
 /*
+ * Hornby Elite
+ */
+#define HORNBY_VID		0x04D8
+#define HORNBY_ELITE_PID	0x000A
+
+/*
  * RATOC REX-USB60F
  */
 #define RATOC_VENDOR_ID		0x0584
@@ -1159,4 +1176,21 @@
 /* USB-Nano-485*/
 #define FTDI_CTI_NANO_PID	0xF60B
 
+/*
+ * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de
+ */
+/* TagTracer MIFARE*/
+#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID	0xF7C0
 
+/*
+ * Rainforest Automation
+ */
+/* ZigBee controller */
+#define FTDI_RF_R106		0x8A28
+
+/*
+ * Product: HCP HIT GPRS modem
+ * Manufacturer: HCP d.o.o.
+ * ATI command output: Cinterion MC55i
+ */
+#define FTDI_CINTERION_MC55I_PID	0xA951
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 0aac00a..8a90d58 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2677,15 +2677,7 @@
 
 static void edge_disconnect(struct usb_serial *serial)
 {
-	int i;
-	struct edgeport_port *edge_port;
-
 	dbg("%s", __func__);
-
-	for (i = 0; i < serial->num_ports; ++i) {
-		edge_port = usb_get_serial_port_data(serial->port[i]);
-		edge_remove_sysfs_attrs(edge_port->port);
-	}
 }
 
 static void edge_release(struct usb_serial *serial)
@@ -2764,6 +2756,7 @@
 	.disconnect		= edge_disconnect,
 	.release		= edge_release,
 	.port_probe		= edge_create_sysfs_attrs,
+	.port_remove		= edge_remove_sysfs_attrs,
 	.ioctl			= edge_ioctl,
 	.set_termios		= edge_set_termios,
 	.tiocmget		= edge_tiocmget,
@@ -2795,6 +2788,7 @@
 	.disconnect		= edge_disconnect,
 	.release		= edge_release,
 	.port_probe		= edge_create_sysfs_attrs,
+	.port_remove		= edge_remove_sysfs_attrs,
 	.ioctl			= edge_ioctl,
 	.set_termios		= edge_set_termios,
 	.tiocmget		= edge_tiocmget,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 60f38d5..0a8c1e6 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -315,7 +315,7 @@
 	int room = 0; /* Default: no room */
 
 	/* FIXME: no consistent locking for write_urb_busy */
-	if (wport->write_urb_busy)
+	if (!wport->write_urb_busy)
 		room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
 	dbg("%s - returns %d", __func__, room);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index fe22e90..338d082 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -156,6 +156,7 @@
 #define HUAWEI_PRODUCT_K4511			0x14CC
 #define HUAWEI_PRODUCT_ETS1220			0x1803
 #define HUAWEI_PRODUCT_E353			0x1506
+#define HUAWEI_PRODUCT_E173S			0x1C05
 
 #define QUANTA_VENDOR_ID			0x0408
 #define QUANTA_PRODUCT_Q101			0xEA02
@@ -316,6 +317,9 @@
 #define ZTE_PRODUCT_AC8710			0xfff1
 #define ZTE_PRODUCT_AC2726			0xfff5
 #define ZTE_PRODUCT_AC8710T			0xffff
+#define ZTE_PRODUCT_MC2718			0xffe8
+#define ZTE_PRODUCT_AD3812			0xffeb
+#define ZTE_PRODUCT_MC2716			0xffed
 
 #define BENQ_VENDOR_ID				0x04a5
 #define BENQ_PRODUCT_H10			0x4068
@@ -468,6 +472,18 @@
 #define YUGA_PRODUCT_CLU528			0x260D
 #define YUGA_PRODUCT_CLU526			0x260F
 
+/* Viettel products */
+#define VIETTEL_VENDOR_ID			0x2262
+#define VIETTEL_PRODUCT_VT1000			0x0002
+
+/* ZD Incorporated */
+#define ZD_VENDOR_ID				0x0685
+#define ZD_PRODUCT_7000				0x7000
+
+/* LG products */
+#define LG_VENDOR_ID				0x1004
+#define LG_PRODUCT_L02C				0x618f
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
 		OPTION_BLACKLIST_NONE = 0,
@@ -475,31 +491,66 @@
 		OPTION_BLACKLIST_RESERVED_IF = 2
 };
 
+#define MAX_BL_NUM  8
 struct option_blacklist_info {
-	const u32 infolen;	/* number of interface numbers on blacklist */
-	const u8  *ifaceinfo;	/* pointer to the array holding the numbers */
-	enum option_blacklist_reason reason;
+	/* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */
+	const unsigned long sendsetup;
+	/* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */
+	const unsigned long reserved;
 };
 
-static const u8 four_g_w14_no_sendsetup[] = { 0, 1 };
 static const struct option_blacklist_info four_g_w14_blacklist = {
-	.infolen = ARRAY_SIZE(four_g_w14_no_sendsetup),
-	.ifaceinfo = four_g_w14_no_sendsetup,
-	.reason = OPTION_BLACKLIST_SENDSETUP
+	.sendsetup = BIT(0) | BIT(1),
 };
 
-static const u8 alcatel_x200_no_sendsetup[] = { 0, 1 };
 static const struct option_blacklist_info alcatel_x200_blacklist = {
-	.infolen = ARRAY_SIZE(alcatel_x200_no_sendsetup),
-	.ifaceinfo = alcatel_x200_no_sendsetup,
-	.reason = OPTION_BLACKLIST_SENDSETUP
+	.sendsetup = BIT(0) | BIT(1),
 };
 
-static const u8 zte_k3765_z_no_sendsetup[] = { 0, 1, 2 };
+static const struct option_blacklist_info zte_0037_blacklist = {
+	.sendsetup = BIT(0) | BIT(1),
+};
+
 static const struct option_blacklist_info zte_k3765_z_blacklist = {
-	.infolen = ARRAY_SIZE(zte_k3765_z_no_sendsetup),
-	.ifaceinfo = zte_k3765_z_no_sendsetup,
-	.reason = OPTION_BLACKLIST_SENDSETUP
+	.sendsetup = BIT(0) | BIT(1) | BIT(2),
+	.reserved = BIT(4),
+};
+
+static const struct option_blacklist_info zte_ad3812_z_blacklist = {
+	.sendsetup = BIT(0) | BIT(1) | BIT(2),
+};
+
+static const struct option_blacklist_info zte_mc2718_z_blacklist = {
+	.sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4),
+};
+
+static const struct option_blacklist_info zte_mc2716_z_blacklist = {
+	.sendsetup = BIT(1) | BIT(2) | BIT(3),
+};
+
+static const struct option_blacklist_info huawei_cdc12_blacklist = {
+	.reserved = BIT(1) | BIT(2),
+};
+
+static const struct option_blacklist_info net_intf1_blacklist = {
+	.reserved = BIT(1),
+};
+
+static const struct option_blacklist_info net_intf3_blacklist = {
+	.reserved = BIT(3),
+};
+
+static const struct option_blacklist_info net_intf4_blacklist = {
+	.reserved = BIT(4),
+};
+
+static const struct option_blacklist_info net_intf5_blacklist = {
+	.reserved = BIT(5),
+};
+
+static const struct option_blacklist_info zte_mf626_blacklist = {
+	.sendsetup = BIT(0) | BIT(1),
+	.reserved = BIT(4),
 };
 
 static const struct usb_device_id option_ids[] = {
@@ -599,12 +650,16 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
@@ -614,6 +669,14 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) },  /* E398 3G Modem */
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) },  /* E398 3G PC UI Interface */
+	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) },  /* E398 3G Application Interface */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) },
@@ -700,12 +763,14 @@
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
@@ -720,51 +785,62 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
 	/* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) }, */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff,
-	  0xff, 0xff), .driver_info = (kernel_ulong_t)&four_g_w14_blacklist },
+	  0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&zte_0037_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	/* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0053, 0xff, 0xff, 0xff) }, */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) },
@@ -779,11 +855,25 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0083, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0087, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0088, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0089, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0090, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0091, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0092, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0093, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0095, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0098, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0099, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff),
+		.driver_info = (kernel_ulong_t)&net_intf5_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) },
@@ -805,7 +895,6 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0151, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0154, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) },
@@ -814,6 +903,12 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
@@ -988,6 +1083,116 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1403, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1404, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1405, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1406, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1407, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1408, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1409, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1410, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1411, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1412, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1413, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1414, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1415, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1416, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1417, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1418, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1419, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1420, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1421, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1422, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1423, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1427, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1429, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1430, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1431, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1432, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1433, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1434, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1435, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1436, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1437, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1438, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1439, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1440, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1441, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1442, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1443, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1444, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1445, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1446, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1447, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1448, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1449, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1450, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1451, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1452, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1453, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1454, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1455, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1456, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1457, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1458, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1459, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1460, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1461, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1462, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1463, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1464, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1465, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1466, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1467, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1468, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1469, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1470, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1471, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1472, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1473, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1474, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1475, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1476, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1477, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1478, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1479, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1480, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1482, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1483, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1484, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1485, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1486, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1487, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1488, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1489, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1490, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1491, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1492, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1493, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1494, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1495, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1496, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1497, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1498, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1499, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1500, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1501, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1502, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1503, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1504, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1505, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1506, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1507, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1508, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1509, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1510, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) },
@@ -1003,6 +1208,12 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff),
+	 .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff),
+	 .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
+	 .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
 	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
 	{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
 	{ USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */
@@ -1101,6 +1312,9 @@
 	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) },
 	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) },
 	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1214,10 +1428,35 @@
 module_init(option_init);
 module_exit(option_exit);
 
+static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
+			   const struct option_blacklist_info *blacklist)
+{
+	unsigned long num;
+	const unsigned long *intf_list;
+
+	if (blacklist) {
+		if (reason == OPTION_BLACKLIST_SENDSETUP)
+			intf_list = &blacklist->sendsetup;
+		else if (reason == OPTION_BLACKLIST_RESERVED_IF)
+			intf_list = &blacklist->reserved;
+		else {
+			BUG_ON(reason);
+			return false;
+		}
+
+		for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) {
+			if (num == ifnum)
+				return true;
+		}
+	}
+	return false;
+}
+
 static int option_probe(struct usb_serial *serial,
 			const struct usb_device_id *id)
 {
 	struct usb_wwan_intf_private *data;
+
 	/* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
 	if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
 		serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
@@ -1230,14 +1469,14 @@
 		serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
 		return -ENODEV;
 
-	/* Don't bind network interfaces on Huawei K3765, K4505 & K4605 */
-	if (serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID &&
-		(serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K3765 ||
-			serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505 ||
-			serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4605) &&
-		(serial->interface->cur_altsetting->desc.bInterfaceNumber == 1 ||
-			serial->interface->cur_altsetting->desc.bInterfaceNumber == 2))
-		return -ENODEV;
+	/* Don't bind reserved interfaces (like network ones) which often have
+	 * the same class/subclass/protocol as the serial interfaces.  Look at
+	 * the Windows driver .INF files for reserved interface numbers.
+	 */
+	if (is_blacklisted(
+		serial->interface->cur_altsetting->desc.bInterfaceNumber,
+		OPTION_BLACKLIST_RESERVED_IF,
+		(const struct option_blacklist_info *) id->driver_info))
 
 	/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
 	if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID &&
@@ -1246,7 +1485,6 @@
 		return -ENODEV;
 
 	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
-
 	if (!data)
 		return -ENOMEM;
 	data->send_setup = option_send_setup;
@@ -1255,23 +1493,6 @@
 	return 0;
 }
 
-static enum option_blacklist_reason is_blacklisted(const u8 ifnum,
-				const struct option_blacklist_info *blacklist)
-{
-	const u8  *info;
-	int i;
-
-	if (blacklist) {
-		info = blacklist->ifaceinfo;
-
-		for (i = 0; i < blacklist->infolen; i++) {
-			if (info[i] == ifnum)
-				return blacklist->reason;
-		}
-	}
-	return OPTION_BLACKLIST_NONE;
-}
-
 static void option_instat_callback(struct urb *urb)
 {
 	int err;
@@ -1343,9 +1564,8 @@
 	int val = 0;
 	dbg("%s", __func__);
 
-	if (is_blacklisted(ifNum,
-			   (struct option_blacklist_info *) intfdata->private)
-	    == OPTION_BLACKLIST_SENDSETUP) {
+	if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
+			(struct option_blacklist_info *) intfdata->private)) {
 		dbg("No send_setup on blacklisted interface #%d\n", ifNum);
 		return -EIO;
 	}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1d33260..d44c669 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -91,7 +91,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
 	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
 	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
-	{ USB_DEVICE(WINCHIPHEAD_VENDOR_ID, WINCHIPHEAD_USBSER_PRODUCT_ID) },
+	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index ca0d237..c38b8c0 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -145,6 +145,7 @@
 #define ADLINK_VENDOR_ID		0x0b63
 #define ADLINK_ND6530_PRODUCT_ID	0x6530
 
-/* WinChipHead USB->RS 232 adapter */
-#define WINCHIPHEAD_VENDOR_ID		0x4348
-#define WINCHIPHEAD_USBSER_PRODUCT_ID	0x5523
+/* SMART USB Serial Adapter */
+#define SMART_VENDOR_ID	0x0b8c
+#define SMART_PRODUCT_ID	0x2303
+
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index 30b73e6..a348198 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -36,6 +36,7 @@
 #define UTSTARCOM_PRODUCT_UM175_V1		0x3712
 #define UTSTARCOM_PRODUCT_UM175_V2		0x3714
 #define UTSTARCOM_PRODUCT_UM175_ALLTEL		0x3715
+#define PANTECH_PRODUCT_UML190_VZW		0x3716
 #define PANTECH_PRODUCT_UML290_VZW		0x3718
 
 /* CMOTECH devices */
@@ -67,7 +68,11 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) },  /* NMEA */
+	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) },  /* WMC */
+	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) },  /* DIAG */
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index b29a974..851840e 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -1,7 +1,7 @@
 /*
  * Qualcomm Serial USB driver
  *
- *	Copyright (c) 2008 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.
  *
@@ -28,6 +28,7 @@
 	{USB_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
 	{USB_DEVICE(0x03f0, 0x1f1d)},	/* HP un2400 Gobi Modem Device */
 	{USB_DEVICE(0x03f0, 0x201d)},	/* HP un2400 Gobi QDL Device */
+	{USB_DEVICE(0x03f0, 0x371d)},	/* HP un2430 Mobile Broadband Module */
 	{USB_DEVICE(0x04da, 0x250d)},	/* Panasonic Gobi Modem device */
 	{USB_DEVICE(0x04da, 0x250c)},	/* Panasonic Gobi QDL device */
 	{USB_DEVICE(0x413c, 0x8172)},	/* Dell Gobi Modem device */
@@ -78,11 +79,14 @@
 	{USB_DEVICE(0x1199, 0x9008)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
 	{USB_DEVICE(0x1199, 0x9009)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
 	{USB_DEVICE(0x1199, 0x900a)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
+	{USB_DEVICE(0x1199, 0x9011)},   /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
 	{USB_DEVICE(0x16d8, 0x8001)},	/* CMDTech Gobi 2000 QDL device (VU922) */
 	{USB_DEVICE(0x16d8, 0x8002)},	/* CMDTech Gobi 2000 Modem device (VU922) */
 	{USB_DEVICE(0x05c6, 0x9204)},	/* Gobi 2000 QDL device */
 	{USB_DEVICE(0x05c6, 0x9205)},	/* Gobi 2000 Modem device */
-	{USB_DEVICE(0x05c6, 0x9048)},
+	{USB_DEVICE(0x05c6, 0x9048)},	/* MDM9x15 device */
+	{USB_DEVICE(0x05c6, 0x904C)},	/* MDM9x15 device */
+	{USB_DEVICE(0x1199, 0x9013)},	/* Sierra Wireless Gobi 3000 Modem device (MC8355) */
 	{ }				/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index fc310f7..0fded39 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -58,7 +58,9 @@
 
 void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
 {
-	/* Pad the SCSI command with zeros out to 12 bytes
+	/*
+	 * Pad the SCSI command with zeros out to 12 bytes.  If the
+	 * command already is 12 bytes or longer, leave it alone.
 	 *
 	 * NOTE: This only works because a scsi_cmnd struct field contains
 	 * a unsigned char cmnd[16], so we know we have storage available
@@ -66,9 +68,6 @@
 	for (; srb->cmd_len<12; srb->cmd_len++)
 		srb->cmnd[srb->cmd_len] = 0;
 
-	/* set command length to 12 bytes */
-	srb->cmd_len = 12;
-
 	/* send the command to the transport layer */
 	usb_stor_invoke_transport(srb, us);
 }
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index e8ae21b..ff32390 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -691,6 +691,9 @@
 		int temp_result;
 		struct scsi_eh_save ses;
 		int sense_size = US_SENSE_SIZE;
+		struct scsi_sense_hdr sshdr;
+		const u8 *scdd;
+		u8 fm_ili;
 
 		/* device supports and needs bigger sense buffer */
 		if (us->fflags & US_FL_SANE_SENSE)
@@ -774,32 +777,30 @@
 			srb->sense_buffer[7] = (US_SENSE_SIZE - 8);
 		}
 
+		scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+				     &sshdr);
+
 		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
 		US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-			  srb->sense_buffer[0],
-			  srb->sense_buffer[2] & 0xf,
-			  srb->sense_buffer[12], 
-			  srb->sense_buffer[13]);
+			  sshdr.response_code, sshdr.sense_key,
+			  sshdr.asc, sshdr.ascq);
 #ifdef CONFIG_USB_STORAGE_DEBUG
-		usb_stor_show_sense(
-			  srb->sense_buffer[2] & 0xf,
-			  srb->sense_buffer[12], 
-			  srb->sense_buffer[13]);
+		usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq);
 #endif
 
 		/* set the result so the higher layers expect this data */
 		srb->result = SAM_STAT_CHECK_CONDITION;
 
+		scdd = scsi_sense_desc_find(srb->sense_buffer,
+					    SCSI_SENSE_BUFFERSIZE, 4);
+		fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0;
+
 		/* We often get empty sense data.  This could indicate that
 		 * everything worked or that there was an unspecified
 		 * problem.  We have to decide which.
 		 */
-		if (	/* Filemark 0, ignore EOM, ILI 0, no sense */
-				(srb->sense_buffer[2] & 0xaf) == 0 &&
-			/* No ASC or ASCQ */
-				srb->sense_buffer[12] == 0 &&
-				srb->sense_buffer[13] == 0) {
-
+		if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 &&
+		    fm_ili == 0) {
 			/* If things are really okay, then let's show that.
 			 * Zero out the sense buffer so the higher layers
 			 * won't realize we did an unsolicited auto-sense.
@@ -814,7 +815,10 @@
 			 */
 			} else {
 				srb->result = DID_ERROR << 16;
-				srb->sense_buffer[2] = HARDWARE_ERROR;
+				if ((sshdr.response_code & 0x72) == 0x72)
+					srb->sense_buffer[1] = HARDWARE_ERROR;
+				else
+					srb->sense_buffer[2] = HARDWARE_ERROR;
 			}
 		}
 	}
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 3041a97..24caba7 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1854,6 +1854,13 @@
 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Qinglin Ye <yestyle@gmail.com> */
+UNUSUAL_DEV(  0x13fe, 0x3600, 0x0100, 0x0100,
+		"Kingston",
+		"DT 101 G2",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BULK_IGNORE_TAG ),
+
 /* Reported by Francesco Foresti <frafore@tiscali.it> */
 UNUSUAL_DEV(  0x14cd, 0x6600, 0x0201, 0x0201,
 		"Super Top",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 0ca0958..9e069ef 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -831,12 +831,22 @@
 
 	dev_dbg(dev, "device found\n");
 
-	set_freezable();
-	/* Wait for the timeout to expire or for a disconnect */
+	set_freezable_with_signal();
+	/*
+	 * Wait for the timeout to expire or for a disconnect
+	 *
+	 * We can't freeze in this thread or we risk causing khubd to
+	 * fail to freeze, but we can't be non-freezable either. Nor can
+	 * khubd freeze while waiting for scanning to complete as it may
+	 * hold the device lock, causing a hang when suspending devices.
+	 * So we request a fake signal when freezing and use
+	 * interruptible sleep to kick us out of our wait early when
+	 * freezing happens.
+	 */
 	if (delay_use > 0) {
 		dev_dbg(dev, "waiting for device to settle "
 				"before scanning\n");
-		wait_event_freezable_timeout(us->delay_wait,
+		wait_event_interruptible_timeout(us->delay_wait,
 				test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
 				delay_use * HZ);
 	}
@@ -1063,6 +1073,7 @@
 	.id_table =	usb_storage_usb_ids,
 	.supports_autosuspend = 1,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 static int __init usb_stor_init(void)
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 4484c72..c2ceae4 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -1085,7 +1085,7 @@
 	 */
 	lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
 
-	sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+	sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
 	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
 	if (sinfo->atmel_lcdfb_power_control)
 		sinfo->atmel_lcdfb_power_control(0);
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
index caaa27d..cb09aa1f 100644
--- a/drivers/video/carminefb.c
+++ b/drivers/video/carminefb.c
@@ -32,11 +32,11 @@
 #define CARMINEFB_DEFAULT_VIDEO_MODE	1
 
 static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
-module_param(fb_mode, uint, 444);
+module_param(fb_mode, uint, 0444);
 MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
 
 static char *fb_mode_str;
-module_param(fb_mode_str, charp, 444);
+module_param(fb_mode_str, charp, 0444);
 MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
 
 /*
@@ -46,7 +46,7 @@
  * 0b010 Display 1
  */
 static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
-module_param(fb_displays, int, 444);
+module_param(fb_displays, int, 0444);
 MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
 
 struct carmine_hw {
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index a024064..c2b32c4 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1735,8 +1735,6 @@
 {
 	struct fb_event event;
 
-	if (!lock_fb_info(info))
-		return;
 	event.info = info;
 	if (state) {
 		fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
@@ -1745,7 +1743,6 @@
 		info->state = FBINFO_STATE_RUNNING;
 		fb_notifier_call_chain(FB_EVENT_RESUME, &event);
 	}
-	unlock_fb_info(info);
 }
 
 /**
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 04251ce..67afa9c 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -399,9 +399,12 @@
 
 	state = simple_strtoul(buf, &last, 0);
 
+	if (!lock_fb_info(fb_info))
+		return -ENODEV;
 	console_lock();
 	fb_set_suspend(fb_info, (int)state);
 	console_unlock();
+	unlock_fb_info(fb_info);
 
 	return count;
 }
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 0110df9..b3b4d53 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -35,11 +35,16 @@
 	bool "Support for triple frame buffer"
 	default n
 
+config FB_MSM_MDP_HW
+	bool
+	default n
+
 choice
 	prompt "MDP HW version"
 	default FB_MSM_MDP22
 
 config FB_MSM_MDP22
+	select FB_MSM_MDP_HW
 	bool "MDP HW ver2.2"
 	---help---
 	  Support for MSM MDP HW revision 2.2
@@ -54,6 +59,7 @@
 
 config FB_MSM_MDP303
 	depends on FB_MSM_MDP30
+	select FB_MSM_MDP_HW
 	bool "MDP HW ver3.03"
 	default n
 	---help---
@@ -64,6 +70,7 @@
 
 config FB_MSM_MDP31
 	select FB_MSM_LCDC_HW
+	select FB_MSM_MDP_HW
 	bool "MDP HW ver3.1"
 	---help---
 	  Support for MSM MDP HW revision 3.1
@@ -71,10 +78,17 @@
 
 config FB_MSM_MDP40
 	select FB_MSM_LCDC_HW
+	select FB_MSM_MDP_HW
 	bool "MDP HW ver4.0"
 	---help---
 	  Support for MSM MDP HW revision 4.0
 	  Say Y here if this is msm7x30 variant platform.
+
+config FB_MSM_MDP_NONE
+	bool "MDP HW None"
+	---help---
+	  Say Y here if this is mdm platform.
+
 endchoice
 
 config FB_MSM_EBI2
@@ -178,6 +192,15 @@
 	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_NT35516
+	bool
+	select FB_MSM_MIPI_DSI
+
 config FB_MSM_MIPI_DSI_TC358764_DSI2LVDS
 	bool
 	select FB_MSM_MIPI_DSI
@@ -240,6 +263,20 @@
 	select FB_MSM_LCDC_PANEL
 	default n
 
+config FB_MSM_LCDC_TRULY_HVGA_IPS3P2335
+        bool
+        select FB_MSM_LCDC_PANEL
+        default n
+
+config FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL
+        depends on FB_MSM_LCDC_HW
+        bool "LCDC Truly HVGA PT Panel"
+        select FB_MSM_LCDC_TRULY_HVGA_IPS3P2335
+        default n
+        ---help---
+        Support for LCDC Truly HVGA PT panel
+
+
 config FB_MSM_LCDC_SAMSUNG_OLED_PT
 	bool
 	select FB_MSM_LCDC_PANEL
@@ -285,6 +322,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
@@ -305,6 +352,17 @@
 	select FB_MSM_MIPI_DSI_NT35510
 	default n
 
+config FB_MSM_MIPI_NT35516_VIDEO_QHD_PT
+        bool
+        select FB_MSM_MIPI_DSI_NT35516
+        default n
+
+config FB_MSM_MIPI_NT35516_CMD_QHD_PT
+        bool
+        select FB_MSM_MIPI_DSI_NT35516
+        default n
+
+
 config FB_MSM_MIPI_CHIMEI_WXGA
 	bool "LVDS Chimei WXGA Panel using Toshiba MIPI DSI-to-LVDS bridge."
 	select FB_MSM_MIPI_DSI_TC358764_DSI2LVDS
@@ -459,6 +517,10 @@
 	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_NT35516_VIDEO_QHD_PT
+	select FB_MSM_MIPI_NT35516_CMD_QHD_PT
 	select FB_MSM_MIPI_SIMULATOR_VIDEO
 	select FB_MSM_MIPI_CHIMEI_WXGA
 	select FB_MSM_MIPI_CHIMEI_WUXGA
@@ -497,6 +559,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_NT35516_VIDEO_QHD_PT
+	select FM_MSM_MIPI_NT35516_CMD_QHD_PT
 	select FB_MSM_MIPI_SIMULATOR_VIDEO
 	---help---
 	  Support for LCDC + MIPI panel auto detect
@@ -514,6 +578,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 +636,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
@@ -598,6 +672,14 @@
 	bool "MIPI NT35510 Command WVGA PT Panel"
 	select FB_MSM_MIPI_NT35510_CMD_WVGA_PT
 
+config FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL
+        bool "MIPI NT35516 Video qHD PT Panel"
+        select FB_MSM_MIPI_NT35516_VIDEO_QHD_PT
+
+config FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL
+        bool "MIPI NT35516 Command qHD PT Panel"
+        select FB_MSM_MIPI_NT35516_CMD_QHD_PT
+
 config FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL
 	bool "MIPI Simulator Video Panel"
 	select FB_MSM_MIPI_SIMULATOR_VIDEO
@@ -609,6 +691,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
@@ -816,4 +899,17 @@
 
 endchoice
 
+config FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL
+	bool "EBI2 Epson QVGA Panel"
+	select FB_MSM_EBI2
+	default n
+	---help---
+	  Support for EBI2 Epson QVGA (240x320) panel
+
+config FB_MSM_EBI2_PANEL_DETECT
+	bool "EBI2 Panel Detect"
+	select FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL
+	default n
+	---help---
+	  Support for EBI2 panel auto detect
 endif
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index 2bdab74..5a72ad4 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -3,6 +3,8 @@
 obj-$(CONFIG_FB_MSM_LOGO) += logo.o
 obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
 
+ifeq ($(CONFIG_FB_MSM_MDP_HW),y)
+
 # MDP
 obj-y += mdp.o
 
@@ -74,9 +76,11 @@
 # 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
+obj-$(CONFIG_FB_MSM_MIPI_DSI_NT35516) += mipi_truly_tft540960_1_e.o
 obj-$(CONFIG_FB_MSM_MIPI_DSI_SIMULATOR) += mipi_simulator.o
 
 # MIPI Bridge
@@ -116,8 +120,10 @@
 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_truly_tft540960_1_e_video_qhd_pt.o mipi_truly_tft540960_1_e_cmd_qhd_pt.o
 obj-y += mipi_chimei_wxga_pt.o
 obj-y += mipi_chimei_wuxga.o
 obj-y += mipi_truly_video_wvga_pt.o
@@ -126,6 +132,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
@@ -133,6 +141,8 @@
 obj-$(CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT) += mipi_truly_video_wvga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT) += mipi_NT35510_cmd_wvga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT) += mipi_NT35510_video_wvga_pt.o
+obj-$(CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT) += mipi_truly_tft540960_1_e_cmd_qhd_pt.o
+obj-$(CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT) += mipi_truly_tft540960_1_e_video_qhd_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO) += mipi_simulator_video.o
 obj-$(CONFIG_FB_MSM_MIPI_CHIMEI_WXGA) += mipi_chimei_wxga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA) += mipi_chimei_wuxga.o
@@ -157,6 +167,7 @@
 obj-$(CONFIG_FB_MSM_LVDS_CHIMEI_WXGA) += lvds_chimei_wxga.o
 obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += hdmi_msm.o
 obj-$(CONFIG_FB_MSM_EXT_INTERFACE_COMMON) += external_common.o
+obj-$(CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335) += lcdc_truly_ips3p2335.o
 
 obj-$(CONFIG_FB_MSM_TVOUT) += tvout_msm.o
 
@@ -168,6 +179,12 @@
 
 obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
 obj-$(CONFIG_MSM_VIDC_720P) += vidc/
+else
+obj-$(CONFIG_FB_MSM_EBI2) += ebi2_host.o
+obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
+obj-y += msm_fb_panel.o
+obj-$(CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL) += ebi2_epson_s1d_qvga.o
+endif
 
 clean:
 	rm *.o .*cmd
diff --git a/drivers/video/msm/adv7520.c b/drivers/video/msm/adv7520.c
index b3b34bb..df501dd 100644
--- a/drivers/video/msm/adv7520.c
+++ b/drivers/video/msm/adv7520.c
@@ -874,7 +874,11 @@
 	} else
 		DEV_ERR("adv7520_probe: failed to add fb device\n");
 
-	external_common_state->sdev.name = "hdmi";
+	if (hdmi_prim_display)
+		external_common_state->sdev.name = "hdmi_as_primary";
+	else
+		external_common_state->sdev.name = "hdmi";
+
 	if (switch_dev_register(&external_common_state->sdev) < 0)
 		DEV_ERR("Hdmi switch registration failed\n");
 
diff --git a/drivers/video/msm/ebi2_epson_s1d_qvga.c b/drivers/video/msm/ebi2_epson_s1d_qvga.c
new file mode 100644
index 0000000..8821eab
--- /dev/null
+++ b/drivers/video/msm/ebi2_epson_s1d_qvga.c
@@ -0,0 +1,374 @@
+/* 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 <linux/memory.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include "linux/proc_fs.h"
+
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#define CMD_NOP_C							0x00
+#define CMD_SOFT_RESET_C					0x99
+#define CMD_DISPLAY_ON_C					0xAF
+#define CMD_DISPLAY_OFF_C					0xAE
+#define CMD_SET_DISPLAY_C					0xCA
+#define CMD_SET_DISPLAY_TIMING_C			0xA1
+#define CMD_SET_DATA_C						0xBC
+#define CMD_SET_START_ADDRESS_C				0x15
+#define CMD_SET_END_ADDRESS_C				0x75
+#define CMD_RAM_WRITE_C						0x5C
+#define CMD_RAM_READ_C						0x5D
+#define CMD_SET_AREA_SCROLLING_C			0xAA
+#define CMD_SET_DISPLAY_START_LINE_C		0xAB
+#define CMD_PARTIAL_DISPLAY_IN_C			0xA8
+#define CMD_PARTIAL_DISPLAY_OUT_C			0xA9
+#define CMD_SET_DISPLAY_DATA_INTERFACE_C	0x31
+#define CMD_SET_DISPLAY_COLOR_MODE_C		0x8B
+#define CMD_SELECT_MTP_ROM_MODE_C			0x65
+#define CMD_MTP_ROM_MODE_IN_C				0x67
+#define CMD_MTP_ROM_MODE_OUT_C				0x68
+#define CMD_MTP_ROM_OPERATION_IN_C			0x69
+#define CMD_MTP_ROM_OPERATION_OUT_C			0x70
+#define CMD_GATE_LINE_SCAN_MODE_C			0x6F
+#define CMD_SET_AC_OPERATION_DRIVE_C		0x8C
+#define CMD_SET_ELECTRONIC_CONTROL_C		0x20
+#define CMD_SET_POSITIVE_CORRECTION_CHARS_C	0x22
+#define CMD_SET_NEGATIVE_CORRECTION_CHARS_C	0x25
+#define CMD_SET_POWER_CONTROL_C				0x21
+#define CMD_SET_PARTIAL_POWER_CONTROL_C		0x23
+#define CMD_SET_8_COLOR_CONTROL_C			0x24
+#define CMD_SLEEP_IN_C						0x95
+#define CMD_SLEEP_OUT_C						0x94
+#define CMD_VDD_OFF_C						0x97
+#define CMD_VDD_ON_C						0x96
+#define CMD_STOP_OSCILLATION_C				0x93
+#define CMD_START_OSCILLATION_C				0x92
+#define CMD_TEST_SOURCE_C					0xFD
+#define CMD_TEST_FUSE_C						0xFE
+#define CMD_TEST_C							0xFF
+#define CMD_STATUS_READ_C					0xE8
+#define CMD_REVISION_READ_C					0xE9
+
+#define PANEL_WIDTH			240
+#define PANEL_HEIGHT		320
+#define ACTIVE_WIN_WIDTH	PANEL_WIDTH
+#define ACTIVE_WIN_HEIGHT	PANEL_HEIGHT
+
+#define ACTIVE_WIN_H_START	0
+#define ACTIVE_WIN_V_START	0
+
+#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, (cmd << 1));
+#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, (data << 1));
+#define DISP_DATA_IN() inpw(DISP_DATA_PORT);
+
+static void *DISP_CMD_PORT;
+static void *DISP_DATA_PORT;
+static boolean disp_initialized;
+static boolean display_on;
+static struct msm_panel_common_pdata *ebi2_epson_pdata;
+
+static void epson_s1d_disp_init(struct platform_device *pdev);
+static int epson_s1d_disp_off(struct platform_device *pdev);
+static int epson_s1d_disp_on(struct platform_device *pdev);
+static void epson_s1d_disp_set_rect(int x, int y, int xres, int yres);
+
+static void epson_s1d_disp_set_rect(int x, int y, int xres, int yres)
+{
+	int right, bottom;
+
+	if (!disp_initialized)
+		return;
+
+	right = x + xres - 1;
+	bottom = y + yres - 1;
+
+	x += ACTIVE_WIN_H_START;
+	y += ACTIVE_WIN_V_START;
+	right += ACTIVE_WIN_H_START;
+	bottom += ACTIVE_WIN_V_START;
+
+	if ((PANEL_WIDTH  > x) &&
+		(PANEL_HEIGHT > y) &&
+		(PANEL_WIDTH > right) &&
+		(PANEL_HEIGHT > bottom)) {
+		DISP_CMD_OUT(CMD_SET_START_ADDRESS_C);
+		DISP_DATA_OUT((uint8)x);
+		DISP_DATA_OUT((uint8)(y>>8));
+		DISP_DATA_OUT((uint8)y);
+
+		DISP_CMD_OUT(CMD_SET_END_ADDRESS_C);
+		DISP_DATA_OUT((uint8)right);
+		DISP_DATA_OUT((uint8)(bottom>>8));
+		DISP_DATA_OUT((uint8)bottom);
+		DISP_CMD_OUT(CMD_RAM_WRITE_C);
+	}
+}
+
+static void epson_s1d_disp_init(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+
+	if (disp_initialized)
+		return;
+
+	mfd = platform_get_drvdata(pdev);
+
+	DISP_CMD_PORT = mfd->cmd_port;
+	DISP_DATA_PORT = mfd->data_port;
+
+	disp_initialized = TRUE;
+}
+
+static int epson_s1d_disp_off(struct platform_device *pdev)
+{
+	if (!disp_initialized)
+		epson_s1d_disp_init(pdev);
+
+	if (display_on) {
+		DISP_CMD_OUT(CMD_SOFT_RESET_C);
+		DISP_CMD_OUT(CMD_VDD_OFF_C);
+		display_on = FALSE;
+	}
+
+	return 0;
+}
+
+static int epson_s1d_disp_on(struct platform_device *pdev)
+{
+	int i;
+	if (!disp_initialized)
+		epson_s1d_disp_init(pdev);
+
+	if (!display_on) {
+		/* Enable Vdd regulator */
+		DISP_CMD_OUT(CMD_VDD_ON_C);
+		msleep(20);
+
+		/* Soft Reset before configuring display */
+		DISP_CMD_OUT(CMD_SOFT_RESET_C);
+		msleep(20);
+
+		/* Set display attributes */
+
+		/* GATESCAN */
+		DISP_CMD_OUT(CMD_GATE_LINE_SCAN_MODE_C);
+		DISP_DATA_OUT(0x0);
+
+		/* DISSET */
+		DISP_CMD_OUT(CMD_SET_DISPLAY_C);
+		DISP_DATA_OUT(0x31);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT((uint8)((PANEL_HEIGHT - 1)>>8));
+		DISP_DATA_OUT((uint8)(PANEL_HEIGHT - 1));
+		DISP_DATA_OUT(0x03);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x08);
+
+		/* VOLSET */
+		DISP_CMD_OUT(
+				   CMD_SET_ELECTRONIC_CONTROL_C);
+		DISP_DATA_OUT(0x10);
+		DISP_DATA_OUT(0x80);
+		DISP_DATA_OUT(0x11);
+		DISP_DATA_OUT(0x1B);
+		DISP_DATA_OUT(0x02);
+		DISP_DATA_OUT(0x0D);
+		DISP_DATA_OUT(0x00);
+
+		/* PWRCTL */
+		DISP_CMD_OUT(CMD_SET_POWER_CONTROL_C);
+		DISP_DATA_OUT(0x01);
+		DISP_DATA_OUT(0x24);
+		DISP_DATA_OUT(0x0F);
+		DISP_DATA_OUT(0xFE);
+		DISP_DATA_OUT(0x33);
+		DISP_DATA_OUT(0x31);
+		DISP_DATA_OUT(0xFF);
+		DISP_DATA_OUT(0x03);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x77);
+		DISP_DATA_OUT(0x33);
+		DISP_DATA_OUT(0x11);
+		DISP_DATA_OUT(0x44);
+		DISP_DATA_OUT(0x00);
+
+		/* PPWRCTL */
+		DISP_CMD_OUT(CMD_SET_PARTIAL_POWER_CONTROL_C);
+		DISP_DATA_OUT(0x33);
+		DISP_DATA_OUT(0xFF);
+		DISP_DATA_OUT(0x03);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x44);
+		DISP_DATA_OUT(0x00);
+
+		/* SPLOUT */
+		DISP_CMD_OUT(CMD_SLEEP_OUT_C);
+		msleep(100);
+
+		/* DATSET */
+		DISP_CMD_OUT(CMD_SET_DATA_C);
+		DISP_DATA_OUT(0x00);
+
+		/* DISTMEMSET */
+		DISP_CMD_OUT(CMD_SET_DISPLAY_TIMING_C);
+		DISP_DATA_OUT(0x01);
+		DISP_DATA_OUT(0x2E);
+		DISP_DATA_OUT(0x0A);
+		DISP_DATA_OUT(0x2C);
+		DISP_DATA_OUT(0x23);
+		DISP_DATA_OUT(0x2F);
+		DISP_DATA_OUT(0x00);
+
+		/* GAMSETP */
+		DISP_CMD_OUT(CMD_SET_POSITIVE_CORRECTION_CHARS_C);
+		DISP_DATA_OUT(0x37);
+		DISP_DATA_OUT(0xFF);
+		DISP_DATA_OUT(0x7F);
+		DISP_DATA_OUT(0x15);
+		DISP_DATA_OUT(0x37);
+		DISP_DATA_OUT(0x05);
+
+		/* GAMSETN */
+		DISP_CMD_OUT(CMD_SET_NEGATIVE_CORRECTION_CHARS_C);
+		DISP_DATA_OUT(0x37);
+		DISP_DATA_OUT(0xFF);
+		DISP_DATA_OUT(0x7F);
+		DISP_DATA_OUT(0x15);
+		DISP_DATA_OUT(0x37);
+		DISP_DATA_OUT(0x05);
+
+		/* ACDRIVE */
+		DISP_CMD_OUT(CMD_SET_AC_OPERATION_DRIVE_C);
+		DISP_DATA_OUT(0x00);
+
+		/* TEST */
+		DISP_CMD_OUT(CMD_TEST_C);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x01);
+
+		/* COLMOD */
+		DISP_CMD_OUT(CMD_SET_DISPLAY_COLOR_MODE_C);
+		DISP_DATA_OUT(0x00);
+
+		/* STADDSET */
+		DISP_CMD_OUT(CMD_SET_START_ADDRESS_C);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x00);
+
+		/* EDADDSET */
+		DISP_CMD_OUT(CMD_SET_END_ADDRESS_C);
+		DISP_DATA_OUT(0xEF);
+		DISP_DATA_OUT(0x01);
+		DISP_DATA_OUT(0x3F);
+
+		/* Set Display Start Line */
+		DISP_CMD_OUT(CMD_SET_DISPLAY_START_LINE_C);
+		DISP_DATA_OUT(0x00);
+
+		/* Set Display Data Interface */
+		DISP_CMD_OUT(CMD_SET_DISPLAY_DATA_INTERFACE_C);
+		DISP_DATA_OUT(0x00);
+		DISP_DATA_OUT(0x04);
+
+		epson_s1d_disp_set_rect(0,
+						 0,
+						 ACTIVE_WIN_WIDTH,
+						 ACTIVE_WIN_HEIGHT);
+
+		for (i = 0; i < (ACTIVE_WIN_WIDTH * ACTIVE_WIN_HEIGHT); i++)
+			outpdw(DISP_DATA_PORT, 0);
+
+		/* DISON */
+		DISP_CMD_OUT(CMD_DISPLAY_ON_C);
+		msleep(60);
+
+		display_on = TRUE;
+	}
+
+	return 0;
+}
+
+static int epson_s1d_probe(struct platform_device *pdev)
+{
+	if (pdev->id == 0) {
+		ebi2_epson_pdata = pdev->dev.platform_data;
+		return 0;
+	}
+
+	msm_fb_add_device(pdev);
+	return 0;
+}
+
+static struct platform_driver this_driver = {
+	.probe  = epson_s1d_probe,
+	.driver = {
+		.name   = "ebi2_epson_s1d_qvga",
+	},
+};
+
+static struct msm_fb_panel_data epson_s1d_panel_data = {
+	.on = epson_s1d_disp_on,
+	.off = epson_s1d_disp_off,
+	.set_rect = epson_s1d_disp_set_rect,
+};
+
+static struct platform_device this_device = {
+	.name   = "ebi2_epson_s1d_qvga",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &epson_s1d_panel_data,
+	}
+};
+
+static int __init epson_s1d_init(void)
+{
+	int ret;
+	struct msm_panel_info *pinfo;
+
+	ret = platform_driver_register(&this_driver);
+	if (!ret) {
+		pinfo = &epson_s1d_panel_data.panel_info;
+		pinfo->xres = PANEL_WIDTH;
+		pinfo->yres = PANEL_HEIGHT;
+		MSM_FB_SINGLE_MODE_PANEL(pinfo);
+		pinfo->type = EBI2_PANEL;
+		pinfo->pdest = DISPLAY_1;
+		pinfo->wait_cycle = 0x048423E8;
+		pinfo->bpp = 18;
+		pinfo->fb_num = 2;
+		pinfo->lcd.vsync_enable = FALSE;
+
+		ret = platform_device_register(&this_device);
+		if (ret)
+			platform_driver_unregister(&this_driver);
+	}
+
+	return ret;
+}
+
+module_init(epson_s1d_init);
diff --git a/drivers/video/msm/ebi2_host.c b/drivers/video/msm/ebi2_host.c
new file mode 100644
index 0000000..8ba5506
--- /dev/null
+++ b/drivers/video/msm/ebi2_host.c
@@ -0,0 +1,307 @@
+/* Copyright (c) 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <mach/clk.h>
+#include <mach/hardware.h>
+#include "msm_fb.h"
+
+struct mdp_ccs mdp_ccs_rgb2yuv;
+struct mdp_ccs mdp_ccs_yuv2rgb;
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+static int ebi2_host_resource_initialized;
+static struct msm_panel_common_pdata *ebi2_host_pdata;
+
+static int ebi2_host_probe(struct platform_device *pdev);
+static int ebi2_host_remove(struct platform_device *pdev);
+
+static int ebi2_host_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
+
+static int ebi2_host_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+
+static const struct dev_pm_ops ebi2_host_dev_pm_ops = {
+	.runtime_suspend = ebi2_host_runtime_suspend,
+	.runtime_resume = ebi2_host_runtime_resume,
+};
+
+
+static struct platform_driver ebi2_host_driver = {
+	.probe = ebi2_host_probe,
+	.remove = ebi2_host_remove,
+	.shutdown = NULL,
+	.driver = {
+		/*
+		 * Simulate mdp hw
+		 */
+		.name = "mdp",
+		.pm = &ebi2_host_dev_pm_ops,
+	},
+};
+
+void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
+		   boolean isr)
+{
+	return;
+}
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req)
+{
+	return 0;
+}
+int mdp_start_histogram(struct fb_info *info)
+{
+	return 0;
+}
+int mdp_stop_histogram(struct fb_info *info)
+{
+	return 0;
+}
+void mdp_refresh_screen(unsigned long data)
+{
+	return;
+}
+
+static int ebi2_host_off(struct platform_device *pdev)
+{
+	int ret;
+	ret = panel_next_off(pdev);
+	return ret;
+}
+
+static int ebi2_host_on(struct platform_device *pdev)
+{
+	int ret;
+	ret = panel_next_on(pdev);
+	return ret;
+}
+
+
+static int ebi2_host_probe(struct platform_device *pdev)
+{
+	struct platform_device *msm_fb_dev = NULL;
+	struct msm_fb_data_type *mfd;
+	struct msm_fb_panel_data *pdata = NULL;
+	int rc;
+
+	if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+
+		ebi2_host_pdata = pdev->dev.platform_data;
+
+		ebi2_host_resource_initialized = 1;
+		return 0;
+	}
+
+	ebi2_host_resource_initialized = 1;
+	if (!ebi2_host_resource_initialized)
+		return -EPERM;
+
+	mfd = platform_get_drvdata(pdev);
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+		return -ENOMEM;
+
+	msm_fb_dev = platform_device_alloc("msm_fb", pdev->id);
+	if (!msm_fb_dev)
+		return -ENOMEM;
+
+	/* link to the latest pdev */
+	mfd->pdev = msm_fb_dev;
+
+	if (ebi2_host_pdata) {
+		mfd->mdp_rev = ebi2_host_pdata->mdp_rev;
+		mfd->mem_hid = ebi2_host_pdata->mem_hid;
+	}
+
+	/* add panel data */
+	if (platform_device_add_data
+	    (msm_fb_dev, pdev->dev.platform_data,
+	     sizeof(struct msm_fb_panel_data))) {
+		pr_err("ebi2_host_probe: platform_device_add_data failed!\n");
+		rc = -ENOMEM;
+		goto ebi2_host_probe_err;
+	}
+	/* data chain */
+	pdata = msm_fb_dev->dev.platform_data;
+	pdata->on = ebi2_host_on;
+	pdata->off = ebi2_host_off;
+	pdata->next = pdev;
+
+	/* set driver data */
+	platform_set_drvdata(msm_fb_dev, mfd);
+
+	rc = platform_device_add(msm_fb_dev);
+	if (rc)
+		goto ebi2_host_probe_err;
+
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	pdev_list[pdev_list_cnt++] = pdev;
+	return 0;
+
+ebi2_host_probe_err:
+	platform_device_put(msm_fb_dev);
+	return rc;
+}
+
+void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
+			  boolean sync)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_info *fbi = mfd->fbi;
+	struct msm_panel_info *panel_info = &mfd->panel_info;
+	MDPIBUF *iBuf;
+	int bpp = info->var.bits_per_pixel / 8;
+	int yres, remainder;
+
+	if (panel_info->mode2_yres != 0) {
+		yres = panel_info->mode2_yres;
+		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
+	} else {
+		yres = panel_info->yres;
+		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
+	}
+
+	if (!remainder)
+		remainder = PAGE_SIZE;
+
+	down(&mfd->sem);
+
+	iBuf = &mfd->ibuf;
+	/* use virtual address */
+	iBuf->buf = (uint8 *) fbi->screen_base;
+
+	if (fbi->var.yoffset < yres) {
+		iBuf->buf += fbi->var.xoffset * bpp;
+	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
+		iBuf->buf += fbi->var.xoffset * bpp + yres *
+		fbi->fix.line_length + PAGE_SIZE - remainder;
+	} else {
+		iBuf->buf += fbi->var.xoffset * bpp + 2 * yres *
+		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
+	}
+
+	iBuf->ibuf_width = info->var.xres_virtual;
+	iBuf->bpp = bpp;
+
+	iBuf->vsync_enable = sync;
+
+	if (dirty) {
+		/*
+		 * ToDo: dirty region check inside var.xoffset+xres
+		 * <-> var.yoffset+yres
+		 */
+		iBuf->dma_x = dirty->xoffset % info->var.xres;
+		iBuf->dma_y = dirty->yoffset % info->var.yres;
+		iBuf->dma_w = dirty->width;
+		iBuf->dma_h = dirty->height;
+	} else {
+		iBuf->dma_x = 0;
+		iBuf->dma_y = 0;
+		iBuf->dma_w = info->var.xres;
+		iBuf->dma_h = info->var.yres;
+	}
+	mfd->ibuf_flushed = FALSE;
+	up(&mfd->sem);
+}
+
+void mdp_dma_pan_update(struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	MDPIBUF *iBuf;
+	int i, j;
+	uint32 data;
+	uint8 *src;
+	struct msm_fb_panel_data *pdata =
+	    (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+	struct fb_info *fbi = mfd->fbi;
+
+	iBuf = &mfd->ibuf;
+
+	invalidate_caches((unsigned long)fbi->screen_base,
+		(unsigned long)info->fix.smem_len,
+		(unsigned long)info->fix.smem_start);
+
+	pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
+			iBuf->dma_h);
+	for (i = 0; i < iBuf->dma_h; i++) {
+		src = iBuf->buf + (fbi->fix.line_length * (iBuf->dma_y + i))
+			+ (iBuf->dma_x * iBuf->bpp);
+		for (j = 0; j < iBuf->dma_w; j++) {
+			data = (uint32)(*src++ >> 2) << 12;
+			data |= (uint32)(*src++ >> 2) << 6;
+			data |= (uint32)(*src++ >> 2);
+			data = ((data&0x1FF)<<16) | ((data&0x3FE00)>>9);
+			outpdw(mfd->data_port, data);
+		}
+	}
+}
+
+static int ebi2_host_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static int ebi2_host_register_driver(void)
+{
+	return platform_driver_register(&ebi2_host_driver);
+}
+
+static int __init ebi2_host_driver_init(void)
+{
+	int ret;
+
+	ret = ebi2_host_register_driver();
+	if (ret) {
+		pr_err("ebi2_host_register_driver() failed!\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+module_init(ebi2_host_driver_init);
diff --git a/drivers/video/msm/ebi2_lcd.c b/drivers/video/msm/ebi2_lcd.c
index 68590af..966f974 100644
--- a/drivers/video/msm/ebi2_lcd.c
+++ b/drivers/video/msm/ebi2_lcd.c
@@ -56,8 +56,6 @@
 	.probe = ebi2_lcd_probe,
 	.remove = ebi2_lcd_remove,
 	.suspend = NULL,
-	.suspend_late = NULL,
-	.resume_early = NULL,
 	.resume = NULL,
 	.shutdown = NULL,
 	.driver = {
@@ -71,17 +69,42 @@
 static void *ebi2_lcd_cfg1;
 static void __iomem *lcd01_base;
 static void __iomem *lcd02_base;
+static int lcd01_base_phys;
 static int ebi2_lcd_resource_initialized;
 
 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
 static int pdev_list_cnt;
+static struct lcdc_platform_data *ebi2_pdata;
+
+static int ebi2_lcd_on(struct platform_device *pdev)
+{
+	int ret;
+
+	if (ebi2_pdata && ebi2_pdata->lcdc_power_save)
+		ebi2_pdata->lcdc_power_save(1);
+
+	ret = panel_next_on(pdev);
+	return ret;
+}
+
+static int ebi2_lcd_off(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = panel_next_off(pdev);
+
+	if (ebi2_pdata && ebi2_pdata->lcdc_power_save)
+		ebi2_pdata->lcdc_power_save(0);
+
+	return ret;
+}
 
 static int ebi2_lcd_probe(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
 	struct platform_device *mdp_dev = NULL;
 	struct msm_fb_panel_data *pdata = NULL;
-	int rc, i;
+	int rc, i, hw_version;
 
 	if (pdev->id == 0) {
 		for (i = 0; i < pdev->num_resources; i++) {
@@ -98,6 +121,7 @@
 				ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24);
 			} else if (!strncmp(pdev->resource[i].name,
 						"lcd01", 5)) {
+				lcd01_base_phys = pdev->resource[i].start;
 				lcd01_base = ioremap(pdev->resource[i].start,
 						pdev->resource[i].end -
 						pdev->resource[i].start + 1);
@@ -118,7 +142,9 @@
 				}
 			}
 		}
+		ebi2_pdata = pdev->dev.platform_data;
 		ebi2_lcd_resource_initialized = 1;
+
 		return 0;
 	}
 
@@ -158,15 +184,19 @@
 
 	/* data chain */
 	pdata = mdp_dev->dev.platform_data;
-	pdata->on = panel_next_on;
-	pdata->off = panel_next_off;
+	pdata->on = ebi2_lcd_on;
+	pdata->off = ebi2_lcd_off;
 	pdata->next = pdev;
 
 	/* get/set panel specific fb info */
 	mfd->panel_info = pdata->panel_info;
 
+	hw_version = inp32((int)ebi2_base + 8);
+
 	if (mfd->panel_info.bpp == 24)
 		mfd->fb_imgType = MDP_RGB_888;
+	else if (mfd->panel_info.bpp == 18)
+		mfd->fb_imgType = MDP_RGB_888;
 	else
 		mfd->fb_imgType = MDP_RGB_565;
 
@@ -181,10 +211,12 @@
 		 * configure both.
 		 */
 		outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle);
-		if (mfd->panel_info.bpp == 18)
-			outp32(ebi2_lcd_cfg1, 0x01000000);
-		else
-			outp32(ebi2_lcd_cfg1, 0x0);
+		if (hw_version < 0x2020) {
+			if (mfd->panel_info.bpp == 18)
+				outp32(ebi2_lcd_cfg1, 0x01000000);
+			else
+				outp32(ebi2_lcd_cfg1, 0x0);
+		}
 	} else {
 #ifdef DEBUG_EBI2_LCD
 		/*
@@ -201,10 +233,18 @@
 	 */
 	if (mfd->panel_info.pdest == DISPLAY_1) {
 		mfd->cmd_port = lcd01_base;
-		mfd->data_port =
-		    (void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN);
-		mfd->data_port_phys =
-		    (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
+		if (hw_version >= 0x2020) {
+			mfd->data_port =
+				(void *)((uint32) mfd->cmd_port + 0x80);
+			mfd->data_port_phys =
+				(void *)(lcd01_base_phys + 0x80);
+		} else {
+			mfd->data_port =
+			    (void *)((uint32) mfd->cmd_port +
+				    EBI2_PRIM_LCD_RS_PIN);
+			mfd->data_port_phys =
+			    (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
+		}
 	} else {
 		mfd->cmd_port = lcd01_base;
 		mfd->data_port =
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 0a86a50..061e69c 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -18,6 +18,9 @@
 /* #define DEBUG */
 #define DEV_DBG_PREFIX "EXT_COMMON: "
 
+/* The start of the data block collection within the CEA Extension Version 3 */
+#define DBC_START_OFFSET 4
+
 #include "msm_fb.h"
 #include "hdmi_msm.h"
 #include "external_common.h"
@@ -317,6 +320,29 @@
 	return ret;
 }
 
+static ssize_t hdmi_common_rda_edid_physical_address(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n",
+		external_common_state->physical_address);
+
+	DEV_DBG("%s: '%d'\n", __func__,
+			external_common_state->physical_address);
+	return ret;
+}
+
+
+static ssize_t hdmi_common_rda_edid_scan_info(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n",
+		external_common_state->pt_scan_info,
+		external_common_state->it_scan_info,
+		external_common_state->ce_scan_info);
+	DEV_DBG("%s: '%s'\n", __func__, buf);
+	return ret;
+}
+
 static ssize_t hdmi_common_rda_hdcp(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -347,11 +373,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);
@@ -399,6 +426,14 @@
 		mutex_lock(&hdmi_msm_state_mutex);
 		hdmi_msm_state->cec_enabled = true;
 		hdmi_msm_state->cec_logical_addr = 4;
+
+		/* flush CEC queue */
+		hdmi_msm_state->cec_queue_wr = hdmi_msm_state->cec_queue_start;
+		hdmi_msm_state->cec_queue_rd = hdmi_msm_state->cec_queue_start;
+		hdmi_msm_state->cec_queue_full = false;
+		memset(hdmi_msm_state->cec_queue_rd, 0,
+			sizeof(struct hdmi_msm_cec_msg)*CEC_QUEUE_SIZE);
+
 		mutex_unlock(&hdmi_msm_state_mutex);
 		hdmi_msm_cec_init();
 		hdmi_msm_cec_write_logical_addr(
@@ -491,7 +526,7 @@
 			if (hdmi_msm_state->fsm_reset_done)
 				retry++;
 			mutex_unlock(&hdmi_msm_state_mutex);
-			msleep(360);
+			msleep(20);
 		} else
 			break;
 	}
@@ -652,6 +687,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);
@@ -664,6 +707,10 @@
 static DEVICE_ATTR(hpd, S_IRUGO | S_IWUGO, hdmi_common_rda_hpd,
 	hdmi_common_wta_hpd);
 static DEVICE_ATTR(hdcp, S_IRUGO, hdmi_common_rda_hdcp, NULL);
+static DEVICE_ATTR(pa, S_IRUGO,
+	hdmi_common_rda_edid_physical_address, NULL);
+static DEVICE_ATTR(scan_info, S_IRUGO,
+	hdmi_common_rda_edid_scan_info, NULL);
 static DEVICE_ATTR(3d_present, S_IRUGO, hdmi_common_rda_3d_present, NULL);
 static DEVICE_ATTR(hdcp_present, S_IRUGO, hdmi_common_rda_hdcp_present, NULL);
 #endif
@@ -671,6 +718,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,
@@ -681,6 +729,8 @@
 	&dev_attr_edid_modes.attr,
 	&dev_attr_hdcp.attr,
 	&dev_attr_hpd.attr,
+	&dev_attr_pa.attr,
+	&dev_attr_scan_info.attr,
 	&dev_attr_3d_present.attr,
 	&dev_attr_hdcp_present.attr,
 #endif
@@ -693,6 +743,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 = {
@@ -907,11 +958,12 @@
 	 31500, 60000, 108108, 60000, TRUE},
 };
 
-static const uint8 *hdmi_edid_find_block(const uint8 *in_buf, uint8 type,
-	uint8 *len)
+static const uint8 *hdmi_edid_find_block(const uint8 *in_buf,
+		uint32 start_offset, uint8 type, uint8 *len)
 {
 	/* the start of data block collection, start of Video Data Block */
-	uint32 offset = 4;
+	uint32 offset = start_offset;
+	uint32 end_dbc_offset = in_buf[2];
 
 	*len = 0;
 
@@ -919,11 +971,11 @@
 	  present.
 	  edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block collection
 	  present and no DTD data present.*/
-	if ((in_buf[2] == 0) || (in_buf[2] == 4)) {
+	if ((end_dbc_offset == 0) || (end_dbc_offset == 4)) {
 		DEV_WARN("EDID: no DTD or non-DTD data present\n");
 		return NULL;
 	}
-	while (offset < 0x80) {
+	while (offset < end_dbc_offset) {
 		uint8 block_len = in_buf[offset] & 0x1F;
 		if ((in_buf[offset] >> 5) == type) {
 			*len = block_len;
@@ -951,20 +1003,24 @@
 static uint32 hdmi_edid_extract_ieee_reg_id(const uint8 *in_buf)
 {
 	uint8 len;
-	const uint8 *vsd = hdmi_edid_find_block(in_buf, 3, &len);
+	const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3,
+			&len);
 
 	if (vsd == NULL)
 		return 0;
 
 	DEV_DBG("EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n",
-		((uint32)vsd[6] << 8) + (uint32)vsd[5], (uint32)vsd[7] * 5);
+		((uint32)vsd[4] << 8) + (uint32)vsd[5], (uint32)vsd[7] * 5);
+	external_common_state->physical_address =
+		((uint16)vsd[4] << 8) + (uint16)vsd[5];
 	return ((uint32)vsd[3] << 16) + ((uint32)vsd[2] << 8) + (uint32)vsd[1];
 }
 
 static void hdmi_edid_extract_3d_present(const uint8 *in_buf)
 {
 	uint8 len, offset;
-	const uint8 *vsd = hdmi_edid_find_block(in_buf, 3, &len);
+	const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3,
+			&len);
 
 	external_common_state->present_3d = 0;
 	if (vsd == NULL || len < 9) {
@@ -984,7 +1040,8 @@
 static void hdmi_edid_extract_latency_fields(const uint8 *in_buf)
 {
 	uint8 len;
-	const uint8 *vsd = hdmi_edid_find_block(in_buf, 3, &len);
+	const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3,
+			&len);
 
 	if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
 		external_common_state->video_latency = (uint16)-1;
@@ -1002,7 +1059,8 @@
 static void hdmi_edid_extract_speaker_allocation_data(const uint8 *in_buf)
 {
 	uint8 len;
-	const uint8 *sad = hdmi_edid_find_block(in_buf, 4, &len);
+	const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4,
+			&len);
 
 	if (sad == NULL)
 		return;
@@ -1022,7 +1080,8 @@
 static void hdmi_edid_extract_audio_data_blocks(const uint8 *in_buf)
 {
 	uint8 len;
-	const uint8 *sad = hdmi_edid_find_block(in_buf, 1, &len);
+	const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1,
+			&len);
 	uint32 *adb = external_common_state->audio_data_blocks;
 
 	if (sad == NULL)
@@ -1041,6 +1100,63 @@
 	}
 }
 
+static void hdmi_edid_extract_extended_data_blocks(const uint8 *in_buf)
+{
+	uint8 len = 0;
+	uint8 const *prev_etag = in_buf;
+	uint32 start_offset = DBC_START_OFFSET;
+
+	/* A Tage code of 7 identifies extended data blocks */
+	uint8 const *etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+
+	while (etag != NULL) {
+		/* The extended data block should at least be 2 bytes long */
+		if (len < 2) {
+			DEV_DBG("EDID: Found an extended data block of length"
+				"less than 2 bytes. Ignoring ...\n");
+		} else {
+			/*
+			 * The second byte of the extended data block has the
+			 * extended tag code
+			 */
+			switch (etag[1]) {
+			case 0:
+				/* Video Capability Data Block */
+				DEV_DBG("EDID: VCDB=%02X %02X\n", etag[1],
+						etag[2]);
+
+				/*
+				 * Check if the sink specifies underscan
+				 * support for:
+				 * BIT 5: preferred video format
+				 * BIT 3: IT video format
+				 * BIT 1: CE video format
+				 */
+				external_common_state->pt_scan_info = (etag[2] &
+							(BIT(4) | BIT(5))) >> 4;
+				external_common_state->it_scan_info = (etag[2] &
+							(BIT(3) | BIT(2))) >> 2;
+				external_common_state->ce_scan_info = etag[2] &
+							(BIT(1) | BIT(0));
+				DEV_DBG("EDID: Scan Information (pt|it|ce): "
+					"(%d|%d|%d)",
+					external_common_state->pt_scan_info,
+					external_common_state->it_scan_info,
+					external_common_state->ce_scan_info);
+				break;
+			default:
+				DEV_DBG("EDID: Extend Tag Code %d not"
+						"supported\n", etag[1]);
+				break;
+			}
+		}
+
+		/* There could be more that one extended data block */
+		start_offset = etag - prev_etag + len + 1;
+		prev_etag = etag;
+		etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+	}
+}
 
 static void hdmi_edid_detail_desc(const uint8 *data_buf, uint32 *disp_mode)
 {
@@ -1185,7 +1301,8 @@
 	const uint8 *edid_blk0 = &data_buf[0x0];
 	const uint8 *edid_blk1 = &data_buf[0x80];
 	const uint8 *svd = num_og_cea_blocks ?
-		hdmi_edid_find_block(data_buf+0x80, 2, &len) : NULL;
+		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+				2, &len) : NULL;
 
 	disp_mode_list->num_of_elements = 0;
 	if (svd != NULL) {
@@ -1197,6 +1314,11 @@
 			video_format = (*svd & 0x7F) - 1;
 			add_supported_video_format(disp_mode_list,
 				video_format);
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				external_common_state->preferred_video_format =
+					video_format;
+			}
 			if (video_format == HDMI_VFRMT_640x480p60_4_3)
 				has480p = TRUE;
 		}
@@ -1219,6 +1341,11 @@
 				video_format);
 			if (video_format == HDMI_VFRMT_640x480p60_4_3)
 				has480p = TRUE;
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				external_common_state->preferred_video_format =
+					video_format;
+			}
 			desc_offset += 0x12;
 			++i;
 		}
@@ -1239,6 +1366,11 @@
 				video_format);
 			if (video_format == HDMI_VFRMT_640x480p60_4_3)
 				has480p = TRUE;
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				external_common_state->preferred_video_format =
+					video_format;
+			}
 			desc_offset += 0x12;
 			++i;
 		}
@@ -1262,6 +1394,11 @@
 				video_format);
 			if (video_format == HDMI_VFRMT_640x480p60_4_3)
 				has480p = TRUE;
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				external_common_state->preferred_video_format =
+					video_format;
+			}
 			desc_offset += 0x12;
 			++i;
 		}
@@ -1340,6 +1477,7 @@
 	/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
 	uint8 edid_buf[0x80 * 4];
 
+	external_common_state->preferred_video_format = 0;
 	external_common_state->present_3d = 0;
 	memset(&external_common_state->disp_mode_list, 0,
 		sizeof(external_common_state->disp_mode_list));
@@ -1391,6 +1529,7 @@
 				edid_buf+0x80);
 			hdmi_edid_extract_audio_data_blocks(edid_buf+0x80);
 			hdmi_edid_extract_3d_present(edid_buf+0x80);
+			hdmi_edid_extract_extended_data_blocks(edid_buf+0x80);
 		}
 		break;
 	case 2:
@@ -1567,11 +1706,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/external_common.h b/drivers/video/msm/external_common.h
index c9ab88e..b8d2e5f 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -216,6 +216,11 @@
 	uint8 speaker_allocation_block;
 	uint16 video_latency, audio_latency;
 	uint8 audio_data_block_cnt;
+	uint16 physical_address;
+	uint32 preferred_video_format;
+	uint8 pt_scan_info;
+	uint8 it_scan_info;
+	uint8 ce_scan_info;
 	boolean present_3d;
 	boolean present_hdcp;
 	uint32 audio_data_blocks[16];
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index a0665ac..d3bb4c7 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -132,12 +132,6 @@
 		| HDMI_MSM_CEC_REFTIMER_REFTIMER(27 * 50)
 		);
 
-	/* 0x02A4 CEC_TIME */
-	HDMI_OUTP(0x02A4,
-		HDMI_MSM_CEC_TIME_SIGNAL_FREE_TIME(350)
-		| HDMI_MSM_CEC_TIME_ENABLE
-		);
-
 	/*
 	 * 0x02A0 CEC_ADDR
 	 * Starting with a default address of 4
@@ -227,8 +221,13 @@
 
 	/* 0x0294 HDMI_MSM_CEC_RETRANSMIT */
 	HDMI_OUTP(0x0294,
+#ifdef DRVR_ONLY_CECT_NO_DAEMON
 		HDMI_MSM_CEC_RETRANSMIT_NUM(msg->retransmit)
 		| (msg->retransmit > 0) ? HDMI_MSM_CEC_RETRANSMIT_ENABLE : 0);
+#else
+		HDMI_MSM_CEC_RETRANSMIT_NUM(0) |
+			HDMI_MSM_CEC_RETRANSMIT_ENABLE);
+#endif
 
 	/* 0x028C CEC_CTRL */
 	HDMI_OUTP(0x028C, 0x1 | msg->frame_size << 4);
@@ -2218,6 +2217,9 @@
 {
 	int hdcp_link_status = HDMI_INP(0x011C);
 
+	/* Disable HDCP interrupts */
+	HDMI_OUTP(0x0118, 0x0);
+
 	external_common_state->hdcp_active = FALSE;
 	/* 0x0130 HDCP_RESET
 	  [0] LINK0_DEAUTHENTICATE */
@@ -2231,9 +2233,6 @@
 
 	if (hdcp_link_status & 0x00000004)
 		hdcp_auth_info((hdcp_link_status & 0x000000F0) >> 4);
-
-	/* Disable HDCP interrupts */
-	HDMI_OUTP(0x0118, 0x0);
 }
 
 static void check_and_clear_HDCP_DDC_Failure(void)
@@ -2472,15 +2471,10 @@
 				__func__, __LINE__,
 			(HDMI_INP_ND(0x011C) & BIT(8)) >> 8,
 			(HDMI_INP_ND(0x011C) & BIT(9)) >> 9);
+			mutex_unlock(&hdcp_auth_state_mutex);
 			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 */
@@ -3680,6 +3674,7 @@
 	uint32 regVal;
 	int i;
 	int mode = 0;
+	boolean use_ce_scan_info = TRUE;
 
 	switch (external_common_state->video_resolution) {
 	case HDMI_VFRMT_720x480p60_4_3:
@@ -3745,6 +3740,48 @@
 
 	/* Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0 */
 	aviInfoFrame[3]  = hdmi_msm_avi_iframe_lut[0][mode];
+
+	/*
+	 * If the sink specified support for both underscan/overscan
+	 * then, by default, set the underscan bit.
+	 * Only checking underscan support for preferred format and cea formats
+	 */
+	if ((external_common_state->video_resolution ==
+			external_common_state->preferred_video_format)) {
+		use_ce_scan_info = FALSE;
+		switch (external_common_state->pt_scan_info) {
+		case 0:
+			/*
+			 * Need to use the info specified for the corresponding
+			 * IT or CE format
+			 */
+			DEV_DBG("%s: No underscan information specified for the"
+				" preferred video format\n", __func__);
+			use_ce_scan_info = TRUE;
+			break;
+		case 3:
+			DEV_DBG("%s: Setting underscan bit for the preferred"
+				" video format\n", __func__);
+			aviInfoFrame[3] |= 0x02;
+			break;
+		default:
+			DEV_DBG("%s: Underscan information not set for the"
+				" preferred video format\n", __func__);
+			break;
+		}
+	}
+
+	if (use_ce_scan_info) {
+		if (3 == external_common_state->ce_scan_info) {
+			DEV_DBG("%s: Setting underscan bit for the CE video"
+					" format\n", __func__);
+			aviInfoFrame[3] |= 0x02;
+		} else {
+			DEV_DBG("%s: Not setting underscan bit for the CE video"
+				       " format\n", __func__);
+		}
+	}
+
 	/* Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0 */
 	aviInfoFrame[4]  = hdmi_msm_avi_iframe_lut[1][mode];
 	/* Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0 */
@@ -4062,6 +4099,11 @@
 
 static void hdmi_msm_hpd_off(void)
 {
+	if (!hdmi_msm_state->hpd_initialized) {
+		DEV_DBG("%s: HPD is already OFF, returning\n", __func__);
+		return;
+	}
+
 	DEV_DBG("%s: (timer, clk, 5V, core, IRQ off)\n", __func__);
 	del_timer(&hdmi_msm_state->hpd_state_timer);
 	disable_irq(hdmi_msm_state->irq);
@@ -4087,6 +4129,12 @@
 static int hdmi_msm_hpd_on(bool trigger_handler)
 {
 	static int phy_reset_done;
+	uint32 hpd_ctrl;
+
+	if (hdmi_msm_state->hpd_initialized) {
+		DEV_DBG("%s: HPD is already ON, returning\n", __func__);
+		return 0;
+	}
 
 	hdmi_msm_clk(1);
 	hdmi_msm_state->pd->core_power(1, 1);
@@ -4104,41 +4152,52 @@
 	HDMI_OUTP(0x0208, 0x0001001B);
 
 	/* Check HPD State */
-	if (!hdmi_msm_state->hpd_initialized) {
-		uint32 hpd_ctrl;
-		enable_irq(hdmi_msm_state->irq);
+	enable_irq(hdmi_msm_state->irq);
 
-		/* set timeout to 4.1ms (max) for hardware debounce */
-		hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
+	/* set timeout to 4.1ms (max) for hardware debounce */
+	hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
 
-		/* Toggle HPD circuit to trigger HPD sense */
-		HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
-		HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
+	/* Toggle HPD circuit to trigger HPD sense */
+	HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
+	HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
 
-		DEV_DBG("%s: (clk, 5V, core, IRQ on) <trigger:%s>\n", __func__,
-			trigger_handler ? "true" : "false");
+	DEV_DBG("%s: (clk, 5V, core, IRQ on) <trigger:%s>\n", __func__,
+		trigger_handler ? "true" : "false");
 
-		if (trigger_handler) {
-			/* Set HPD state machine: ensure at least 2 readouts */
-			mutex_lock(&hdmi_msm_state_mutex);
-			hdmi_msm_state->hpd_stable = 0;
-			hdmi_msm_state->hpd_prev_state = TRUE;
-			mutex_lock(&external_common_state_hpd_mutex);
-			external_common_state->hpd_state = FALSE;
-			mutex_unlock(&external_common_state_hpd_mutex);
-			hdmi_msm_state->hpd_cable_chg_detected = TRUE;
-			mutex_unlock(&hdmi_msm_state_mutex);
-			mod_timer(&hdmi_msm_state->hpd_state_timer,
-				jiffies + HZ/2);
-		}
-
-		hdmi_msm_state->hpd_initialized = TRUE;
+	if (trigger_handler) {
+		/* Set HPD state machine: ensure at least 2 readouts */
+		mutex_lock(&hdmi_msm_state_mutex);
+		hdmi_msm_state->hpd_stable = 0;
+		hdmi_msm_state->hpd_prev_state = TRUE;
+		mutex_lock(&external_common_state_hpd_mutex);
+		external_common_state->hpd_state = FALSE;
+		mutex_unlock(&external_common_state_hpd_mutex);
+		hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+		mutex_unlock(&hdmi_msm_state_mutex);
+		mod_timer(&hdmi_msm_state->hpd_state_timer,
+			jiffies + HZ/2);
 	}
+
+	hdmi_msm_state->hpd_initialized = TRUE;
+
 	hdmi_msm_set_mode(TRUE);
 
 	return 0;
 }
 
+static int hdmi_msm_power_ctrl(boolean enable)
+{
+	if (!external_common_state->hpd_feature_on)
+		return 0;
+
+	if (enable)
+		hdmi_msm_hpd_on(true);
+	else
+		hdmi_msm_hpd_off();
+
+	return 0;
+}
+
 static int hdmi_msm_power_on(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
@@ -4160,7 +4219,7 @@
 #endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 	changed = hdmi_common_get_video_format_from_drv_data(mfd);
-	if (!external_common_state->hpd_feature_on) {
+	if (!external_common_state->hpd_feature_on || mfd->ref_cnt) {
 		int rc = hdmi_msm_hpd_on(true);
 		DEV_INFO("HPD: panel power without 'hpd' feature on\n");
 		if (rc) {
@@ -4195,6 +4254,8 @@
  */
 static int hdmi_msm_power_off(struct platform_device *pdev)
 {
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
 	if (!hdmi_msm_state->hdmi_app_clk)
 		return -ENODEV;
 
@@ -4220,7 +4281,7 @@
 	hdmi_msm_hpd_on(true);
 
 	mutex_lock(&external_common_state_hpd_mutex);
-	if (!external_common_state->hpd_feature_on)
+	if (!external_common_state->hpd_feature_on || mfd->ref_cnt)
 		hdmi_msm_hpd_off();
 	mutex_unlock(&external_common_state_hpd_mutex);
 
@@ -4233,9 +4294,6 @@
 	int rc;
 	struct platform_device *fb_dev;
 
-	if (cpu_is_apq8064())
-		return -ENODEV;
-
 	if (!hdmi_msm_state) {
 		pr_err("%s: hdmi_msm_state is NULL\n", __func__);
 		return -ENOMEM;
@@ -4398,7 +4456,10 @@
 	queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_read_work);
 
 	/* Initialize hdmi node and register with switch driver */
-	external_common_state->sdev.name = "hdmi";
+	if (hdmi_prim_display)
+		external_common_state->sdev.name = "hdmi_as_primary";
+	else
+		external_common_state->sdev.name = "hdmi";
 	if (switch_dev_register(&external_common_state->sdev) < 0)
 		DEV_ERR("Hdmi switch registration failed\n");
 
@@ -4493,6 +4554,7 @@
 static struct msm_fb_panel_data hdmi_msm_panel_data = {
 	.on = hdmi_msm_power_on,
 	.off = hdmi_msm_power_off,
+	.power_ctrl = hdmi_msm_power_ctrl,
 };
 
 static struct platform_device this_device = {
@@ -4505,12 +4567,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/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h
index 9675fd5..5195f2c 100644
--- a/drivers/video/msm/hdmi_msm.h
+++ b/drivers/video/msm/hdmi_msm.h
@@ -98,7 +98,7 @@
 
 #define CEC_QUEUE_SIZE		16
 #define CEC_QUEUE_END	 (hdmi_msm_state->cec_queue_start + CEC_QUEUE_SIZE)
-#define RETRANSMIT_MAX_NUM	7
+#define RETRANSMIT_MAX_NUM	5
 #endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */
 
 	int irq;
diff --git a/drivers/video/msm/lcdc_truly_ips3p2335.c b/drivers/video/msm/lcdc_truly_ips3p2335.c
new file mode 100644
index 0000000..838c083
--- /dev/null
+++ b/drivers/video/msm/lcdc_truly_ips3p2335.c
@@ -0,0 +1,305 @@
+/* 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/delay.h>
+#include <linux/module.h>
+#include <mach/gpio.h>
+#include <mach/pmic.h>
+#include "msm_fb.h"
+
+static int prev_bl = 17;
+
+static int spi_cs;
+static int spi_sclk;
+static int spi_mosi;
+static int gpio_backlight_en;
+static int gpio_display_reset;
+
+struct truly_state_type {
+	boolean disp_initialized;
+	boolean display_on;
+	boolean disp_powered_up;
+};
+
+static struct truly_state_type truly_state = { 0 };
+static struct msm_panel_common_pdata *lcdc_truly_pdata;
+
+static char init_item_v1[] = { 0xff, 0x83, 0x57, };
+static char init_item_v2[] = { 0x03, };
+static char init_item_v3[] = { 0x00, 0x13, 0x1C, 0x1C, 0x83, 0x48, };
+static char init_item_v4[] = { 0x43, 0x06, 0x06, 0x06, };
+static char init_item_v5[] = { 0x53, };
+static char init_item_v6[] = { 0x02, 0x40, 0x00, 0x2a, 0x2a, 0x0d, 0x3f, };
+static char init_item_v7[] = { 0x70, 0x50, 0x01, 0x3c, 0xe8, 0x08, };
+static char init_item_v8[] = { 0x17, 0x0f, };
+static char init_item_v9[] = { 0x60};
+static char init_item_v10[] = { 0x00, 0x13, 0x1a, 0x29, 0x2d, 0x41, 0x49,
+				0x52, 0x48, 0x41, 0x3c, 0x33, 0x30, 0x1c,
+				0x19, 0x03, 0x00, 0x13, 0x1a, 0x29, 0x2d,
+				0x41, 0x49, 0x52, 0x48, 0x41, 0x3c, 0x33,
+				0x31, 0x1c, 0x19, 0x03, 0x00, 0x01,
+				};
+static char init_item_v11[] = { 0x40, };
+
+static inline void truly_spi_write_byte(char dc, uint8 data)
+{
+	uint32 bit;
+	int bnum;
+
+	gpio_set_value_cansleep(spi_sclk, 0); /* clk low */
+	/* dc: 0 for command, 1 for parameter */
+	gpio_set_value_cansleep(spi_mosi, dc);
+	udelay(1);	/* at least 20 ns */
+	gpio_set_value_cansleep(spi_sclk, 1); /* clk high */
+	udelay(1);	/* at least 20 ns */
+	bnum = 8;	/* 8 data bits */
+	bit = 0x80;
+	while (bnum) {
+		gpio_set_value_cansleep(spi_sclk, 0); /* clk low */
+		if (data & bit)
+			gpio_set_value_cansleep(spi_mosi, 1);
+		else
+			gpio_set_value_cansleep(spi_mosi, 0);
+		udelay(1);
+		gpio_set_value_cansleep(spi_sclk, 1); /* clk high */
+		udelay(1);
+		bit >>= 1;
+		bnum--;
+	}
+}
+
+static inline int truly_spi_write(char cmd, char *data, int num)
+{
+	int i;
+
+	gpio_set_value_cansleep(spi_cs, 0);	/* cs low */
+	/* command byte first */
+	truly_spi_write_byte(0, cmd);
+	/* followed by parameter bytes */
+	for (i = 0; i < num; i++) {
+		if (data)
+			truly_spi_write_byte(1, data[i]);
+	}
+	gpio_set_value_cansleep(spi_mosi, 1);	/* mosi high */
+	gpio_set_value_cansleep(spi_cs, 1);	/* cs high */
+	udelay(10);
+	return 0;
+}
+
+static void spi_pin_assign(void)
+{
+	/* Setting the Default GPIO's */
+	spi_mosi	= *(lcdc_truly_pdata->gpio_num);
+	spi_sclk	= *(lcdc_truly_pdata->gpio_num + 1);
+	spi_cs		= *(lcdc_truly_pdata->gpio_num + 2);
+	gpio_backlight_en = *(lcdc_truly_pdata->gpio_num + 3);
+	gpio_display_reset = *(lcdc_truly_pdata->gpio_num + 4);
+	pr_debug("spi_mosi:%d spi_sclk:%d spi_cs:%d backlight:%d reset:%d\n",
+		spi_mosi, spi_sclk, spi_cs, gpio_backlight_en,
+		gpio_display_reset);
+
+}
+
+static void truly_disp_powerup(void)
+{
+	/* Reset the hardware first */
+	/* Include DAC power up implementation here */
+	if (!truly_state.disp_powered_up && !truly_state.display_on)
+		truly_state.disp_powered_up = TRUE;
+}
+
+static void truly_disp_reginit(void)
+{
+	pr_debug("%s disp_powered_up:%d display_on:%d\n", __func__,
+			truly_state.disp_powered_up, truly_state.display_on);
+	if (truly_state.disp_powered_up && !truly_state.display_on) {
+		gpio_set_value_cansleep(spi_cs, 1);	/* cs high */
+
+		truly_spi_write(0xb9, init_item_v1, sizeof(init_item_v1));
+		msleep(20);
+		truly_spi_write(0xcc, init_item_v2, sizeof(init_item_v2));
+		truly_spi_write(0xb1, init_item_v3, sizeof(init_item_v3));
+		truly_spi_write(0xb3, init_item_v4, sizeof(init_item_v4));
+		truly_spi_write(0xb6, init_item_v5, sizeof(init_item_v5));
+		truly_spi_write(0xb4, init_item_v6, sizeof(init_item_v6));
+		truly_spi_write(0xc0, init_item_v7, sizeof(init_item_v7));
+		truly_spi_write(0xe3, init_item_v8, sizeof(init_item_v8));
+		truly_spi_write(0x3a, init_item_v9, sizeof(init_item_v9));
+		truly_spi_write(0xe0, init_item_v10, sizeof(init_item_v10));
+		truly_spi_write(0x36, init_item_v11, sizeof(init_item_v11));
+		truly_spi_write(0x11, NULL, 0);
+		msleep(150);
+		truly_spi_write(0x29, NULL, 0);
+		msleep(25);
+
+		truly_state.display_on = TRUE;
+	}
+}
+
+static int lcdc_truly_panel_on(struct platform_device *pdev)
+{
+	/* Configure reset GPIO that drives DAC */
+	if (lcdc_truly_pdata->panel_config_gpio)
+		lcdc_truly_pdata->panel_config_gpio(1);
+	gpio_set_value_cansleep(gpio_display_reset, 1);
+	truly_disp_powerup();
+	truly_disp_reginit();
+	truly_state.disp_initialized = TRUE;
+	return 0;
+}
+
+static int lcdc_truly_panel_off(struct platform_device *pdev)
+{
+	if (truly_state.disp_powered_up && truly_state.display_on) {
+		/* Main panel power off (Pull down reset) */
+		gpio_set_value_cansleep(gpio_display_reset, 0);
+		truly_state.display_on = FALSE;
+		truly_state.disp_initialized = FALSE;
+	}
+	return 0;
+}
+
+static void lcdc_truly_set_backlight(struct msm_fb_data_type *mfd)
+{
+	int step = 0, i = 0;
+	unsigned long flags;
+	int bl_level = mfd->bl_level;
+
+	/* real backlight level, 1 - max, 16 - min, 17 - off */
+	bl_level = 17 - bl_level;
+
+	if (bl_level > prev_bl) {
+		step = bl_level - prev_bl;
+		if (bl_level == 17)
+			step--;
+	} else if (bl_level < prev_bl) {
+		step = bl_level + 16 - prev_bl;
+	} else {
+		pr_info("%s: no change\n", __func__);
+		return;
+	}
+
+	if (bl_level == 17) {
+		/* turn off backlight */
+		gpio_set_value(gpio_backlight_en, 0);
+	} else {
+		local_irq_save(flags);
+
+		if (prev_bl == 17) {
+			/* turn on backlight */
+			gpio_set_value(gpio_backlight_en, 1);
+			udelay(30);
+		}
+
+		/* adjust backlight level */
+		for (i = 0; i < step; i++) {
+			gpio_set_value(gpio_backlight_en, 0);
+			udelay(1);
+			gpio_set_value(gpio_backlight_en, 1);
+			udelay(1);
+		}
+
+		local_irq_restore(flags);
+	}
+	msleep(20);
+	prev_bl = bl_level;
+
+	return;
+}
+
+static int __devinit truly_probe(struct platform_device *pdev)
+{
+
+	if (pdev->id == 0) {
+		lcdc_truly_pdata = pdev->dev.platform_data;
+
+		if (!lcdc_truly_pdata)
+			pr_err("%s pdata is null\n", __func__);
+
+		spi_pin_assign();
+		return 0;
+	}
+	msm_fb_add_device(pdev);
+
+	return 0;
+}
+
+static struct platform_driver this_driver = {
+	.probe  = truly_probe,
+	.driver = {
+		.name   = "lcdc_truly_hvga_ips3p2335_pt",
+	},
+};
+
+static struct msm_fb_panel_data truly_panel_data = {
+	.on = lcdc_truly_panel_on,
+	.off = lcdc_truly_panel_off,
+	.set_backlight = lcdc_truly_set_backlight,
+};
+
+static struct platform_device this_device = {
+	.name   = "lcdc_truly_hvga_ips3p2335_pt",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &truly_panel_data,
+	}
+};
+
+static int __init lcdc_truly_panel_init(void)
+{
+	int ret;
+	struct msm_panel_info *pinfo;
+
+	ret = msm_fb_detect_client("lcdc_truly_hvga_ips3p2335_pt");
+	if (ret)
+		return 0;
+
+	ret = platform_driver_register(&this_driver);
+	if (ret) {
+		pr_err("%s() driver registration failed", __func__);
+		return ret;
+	}
+
+	pinfo = &truly_panel_data.panel_info;
+	pinfo->xres = 320;
+	pinfo->yres = 480;
+	MSM_FB_SINGLE_MODE_PANEL(pinfo);
+	pinfo->type = LCDC_PANEL;
+	pinfo->pdest = DISPLAY_1;
+	pinfo->wait_cycle = 0;
+	pinfo->bpp = 18;
+	pinfo->fb_num = 2;
+	/* 10Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */
+	pinfo->clk_rate = 10240000;
+	pinfo->bl_max = 16;
+	pinfo->bl_min = 1;
+
+	pinfo->lcdc.h_back_porch = 16;		/* hsw = 8 + hbp=16 */
+	pinfo->lcdc.h_front_porch = 4;
+	pinfo->lcdc.h_pulse_width = 8;
+	pinfo->lcdc.v_back_porch = 7;		/* vsw=1 + vbp = 7 */
+	pinfo->lcdc.v_front_porch = 3;
+	pinfo->lcdc.v_pulse_width = 1;
+	pinfo->lcdc.border_clr = 0;		/* blk */
+	pinfo->lcdc.underflow_clr = 0xff;	/* blue */
+	pinfo->lcdc.hsync_skew = 0;
+
+	ret = platform_device_register(&this_device);
+	if (ret) {
+		pr_err("%s not able to register the device\n", __func__);
+		platform_driver_unregister(&this_driver);
+	}
+	return ret;
+}
+
+device_initcall(lcdc_truly_panel_init);
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index a69c64f..d9785d8 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -110,23 +110,43 @@
 	mb();
 
 	if (mfd->panel_info.bpp == 24) {
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
-		MDP_OUTP(MDP_BASE +  0xc2014, 0x03040508);
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
-		MDP_OUTP(MDP_BASE +  0xc2018, 0x00000102);
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
-		MDP_OUTP(MDP_BASE +  0xc201c, 0x0c0d1011);
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
-		MDP_OUTP(MDP_BASE +  0xc2020, 0x00090a0b);
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
-		MDP_OUTP(MDP_BASE +  0xc2024, 0x151a191a);
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
-		MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
-		MDP_OUTP(MDP_BASE +  0xc202c, 0x1706071b);
-		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
-		MDP_OUTP(MDP_BASE +  0xc2030, 0x000e0f16);
-
+		if (lvds_pdata &&
+		    lvds_pdata->lvds_pixel_remap &&
+		    lvds_pdata->lvds_pixel_remap()) {
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc2014, 0x05080001);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2018, 0x00020304);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc201c, 0x1011090a);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2020, 0x000b0c0d);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc2024, 0x191a1213);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2028, 0x00141518);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc202c, 0x171b0607);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2030, 0x000e0f16);
+		} else {
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc2014, 0x03040508);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2018, 0x00000102);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc201c, 0x0c0d1011);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2020, 0x00090a0b);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc2024, 0x151a191a);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
+			MDP_OUTP(MDP_BASE +  0xc202c, 0x1706071b);
+			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
+			MDP_OUTP(MDP_BASE +  0xc2030, 0x000e0f16);
+		}
 		if (mfd->panel_info.lvds.channel_mode ==
 			LVDS_DUAL_CHANNEL_MODE) {
 			lvds_intf = 0x0001ff80;
@@ -161,6 +181,8 @@
 			lvds_intf = 0x0001078c;
 			lvds_phy_cfg0 = BIT(6);
 		}
+	} else {
+		BUG();
 	}
 
 	/* MDP_LVDSPHY_CFG0 */
diff --git a/drivers/video/msm/mddi_orise.c b/drivers/video/msm/mddi_orise.c
index dc913e6..fa48c75 100644
--- a/drivers/video/msm/mddi_orise.c
+++ b/drivers/video/msm/mddi_orise.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
@@ -102,6 +102,7 @@
 		MSM_FB_SINGLE_MODE_PANEL(pinfo);
 		pinfo->type = MDDI_PANEL;
 		pinfo->pdest = DISPLAY_1;
+		pinfo->mddi.is_type1 = TRUE;
 		pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
 		pinfo->wait_cycle = 0;
 		pinfo->bpp = 18;
diff --git a/drivers/video/msm/mddi_prism.c b/drivers/video/msm/mddi_prism.c
index 5269b22..ec2bf57 100644
--- a/drivers/video/msm/mddi_prism.c
+++ b/drivers/video/msm/mddi_prism.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -87,6 +87,7 @@
 		pinfo->pdest = DISPLAY_1;
 		pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
 		pinfo->wait_cycle = 0;
+		pinfo->mddi.is_type1 = TRUE;
 		pinfo->bpp = 18;
 		pinfo->fb_num = 2;
 		pinfo->clk_rate = 153600000;
diff --git a/drivers/video/msm/mddi_quickvx.c b/drivers/video/msm/mddi_quickvx.c
index 330e679..95e7d41 100644
--- a/drivers/video/msm/mddi_quickvx.c
+++ b/drivers/video/msm/mddi_quickvx.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
@@ -695,6 +695,7 @@
 		pinfo->lcd.vsync_enable = TRUE;
 		pinfo->lcd.refx100 = (mddi_quickvx_rows_per_second \
 			* 100)/mddi_quickvx_rows_per_refresh;
+		pinfo->mddi.is_type1 = TRUE;
 		pinfo->lcd.v_back_porch = 4;
 		pinfo->lcd.v_front_porch = 2;
 		pinfo->lcd.v_pulse_width = 2;
diff --git a/drivers/video/msm/mddi_sharp.c b/drivers/video/msm/mddi_sharp.c
index b2a7188..6a9008f 100644
--- a/drivers/video/msm/mddi_sharp.c
+++ b/drivers/video/msm/mddi_sharp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -855,6 +855,7 @@
 		pinfo->clk_min = 120000000;
 		pinfo->clk_max = 125000000;
 		pinfo->lcd.vsync_enable = TRUE;
+		pinfo->mddi.is_type1 = TRUE;
 		pinfo->lcd.refx100 =
 			(mddi_sharp_rows_per_second * 100) /
 			mddi_sharp_rows_per_refresh;
diff --git a/drivers/video/msm/mddi_toshiba_vga.c b/drivers/video/msm/mddi_toshiba_vga.c
index 794edff..73749f9 100644
--- a/drivers/video/msm/mddi_toshiba_vga.c
+++ b/drivers/video/msm/mddi_toshiba_vga.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-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
@@ -90,6 +90,7 @@
 	pinfo.wait_cycle = 0;
 	pinfo.bpp = 18;
 	pinfo.lcd.vsync_enable = TRUE;
+	pinfo.mddi.is_type1 = TRUE;
 	pinfo.lcd.refx100 = 6118;
 	pinfo.lcd.v_back_porch = 6;
 	pinfo.lcd.v_front_porch = 0;
diff --git a/drivers/video/msm/mddi_toshiba_wvga.c b/drivers/video/msm/mddi_toshiba_wvga.c
index ad4ce46..c1925e1 100644
--- a/drivers/video/msm/mddi_toshiba_wvga.c
+++ b/drivers/video/msm/mddi_toshiba_wvga.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-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
@@ -34,6 +34,7 @@
 	pinfo.wait_cycle = 0;
 	pinfo.bpp = 18;
 	pinfo.lcd.vsync_enable = TRUE;
+	pinfo.mddi.is_type1 = TRUE;
 	pinfo.lcd.refx100 = 6118;
 	pinfo.lcd.v_back_porch = 6;
 	pinfo.lcd.v_front_porch = 0;
diff --git a/drivers/video/msm/mddi_toshiba_wvga_pt.c b/drivers/video/msm/mddi_toshiba_wvga_pt.c
index 7a9fb2d..8da1485 100644
--- a/drivers/video/msm/mddi_toshiba_wvga_pt.c
+++ b/drivers/video/msm/mddi_toshiba_wvga_pt.c
@@ -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
@@ -45,6 +45,7 @@
 	pinfo.bpp = 18;
 	pinfo.lcd.vsync_enable = TRUE;
 	pinfo.lcd.refx100 = 6102; /* adjust refx100 to prevent tearing */
+	pinfo.mddi.is_type1 = TRUE;
 	pinfo.lcd.v_back_porch = 8;     /* vsw=10 + vbp = 8 */
 	pinfo.lcd.v_front_porch = 2;
 	pinfo.lcd.v_pulse_width = 10;
diff --git a/drivers/video/msm/mddihosti.c b/drivers/video/msm/mddihosti.c
index 4989d35..1a5a3fd 100644
--- a/drivers/video/msm/mddihosti.c
+++ b/drivers/video/msm/mddihosti.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -1874,42 +1874,6 @@
 			MDDI_MSG_ERR("mddi_client_power return %d", ret);
 	}
 
-#if 0
-	switch (mddi_client_capability_pkt.Mfr_Name) {
-	case 0x4474:
-		if ((mddi_client_capability_pkt.Product_Code != 0x8960) &&
-		    (target == DISPLAY_1)) {
-			ret = PRISM_WVGA;
-		}
-		break;
-
-	case 0xD263:
-		if (target == DISPLAY_1)
-			ret = TOSHIBA_VGA_PRIM;
-		else if (target == DISPLAY_2)
-			ret = TOSHIBA_QCIF_SECD;
-		break;
-
-	case 0:
-		if (mddi_client_capability_pkt.Product_Code == 0x8835) {
-			if (target == DISPLAY_1)
-				ret = SHARP_QVGA_PRIM;
-			else if (target == DISPLAY_2)
-				ret = SHARP_128x128_SECD;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	if ((!client_detection_try) && (ret != TOSHIBA_VGA_PRIM)
-	    && (ret != TOSHIBA_QCIF_SECD)) {
-		/* Not a Toshiba display, so change drive_lo back to default value */
-		mddi_host_reg_out(DRIVE_LO, 0x0032);
-	}
-#endif
-
 #endif
 
 	return mddi_client_id;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index e43f729..79464bf 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -86,6 +86,9 @@
 struct workqueue_struct *mdp_dma_wq;	/*mdp dma wq */
 struct workqueue_struct *mdp_vsync_wq;	/*mdp vsync wq */
 
+struct workqueue_struct *mdp_hist_wq;	/*mdp histogram wq */
+struct work_struct mdp_histogram_worker;
+
 static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
 static struct delayed_work mdp_pipe_ctrl_worker;
 
@@ -142,6 +145,321 @@
 
 static uint32 mdp_prim_panel_type = NO_PANEL;
 #ifndef CONFIG_FB_MSM_MDP22
+
+struct list_head mdp_hist_lut_list;
+DEFINE_MUTEX(mdp_hist_lut_list_mutex);
+
+uint32_t mdp_block2base(uint32_t block)
+{
+	uint32_t base = 0x0;
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+		base = 0x90000;
+		break;
+	case MDP_BLOCK_DMA_S:
+		base = 0xA0000;
+		break;
+	case MDP_BLOCK_VG_1:
+		base = 0x20000;
+		break;
+	case MDP_BLOCK_VG_2:
+		base = 0x30000;
+		break;
+	case MDP_BLOCK_RGB_1:
+		base = 0x40000;
+		break;
+	case MDP_BLOCK_RGB_2:
+		base = 0x50000;
+		break;
+	case MDP_BLOCK_OVERLAY_0:
+		base = 0x10000;
+		break;
+	case MDP_BLOCK_OVERLAY_1:
+		base = 0x18000;
+		break;
+	default:
+		break;
+	}
+	return base;
+}
+
+static uint32_t mdp_pp_block2hist_lut(uint32_t block)
+{
+	uint32_t valid = 0;
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_DMA_S:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_VG_1:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_VG_2:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	default:
+		break;
+	}
+	return valid;
+}
+
+static void mdp_hist_lut_init_mgmt(struct mdp_hist_lut_mgmt *mgmt,
+		uint32_t block)
+{
+	mutex_init(&mgmt->lock);
+	mgmt->block = block;
+
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_add(&mgmt->list, &mdp_hist_lut_list);
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+}
+
+static int mdp_hist_lut_init(void)
+{
+	struct mdp_hist_lut_mgmt *temp;
+	struct list_head *pos, *q;
+	INIT_LIST_HEAD(&mdp_hist_lut_list);
+
+	if (mdp_rev >= MDP_REV_30) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_P);
+	}
+
+	if (mdp_rev >= MDP_REV_40) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_1);
+
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_2);
+	}
+
+	if (mdp_rev > MDP_REV_42) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_S);
+	}
+	return 0;
+
+exit_list:
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_for_each_safe(pos, q, &mdp_hist_lut_list) {
+		temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
+		list_del(pos);
+		kfree(temp);
+	}
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+exit:
+	pr_err("Failed initializing histogram LUT memory\n");
+	return -ENOMEM;
+}
+
+static int mdp_hist_lut_block2mgmt(uint32_t block,
+		struct mdp_hist_lut_mgmt **mgmt)
+{
+	struct mdp_hist_lut_mgmt *temp, *output;
+	int ret = 0;
+
+	output = NULL;
+
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_for_each_entry(temp, &mdp_hist_lut_list, list) {
+		if (temp->block == block)
+			output = temp;
+	}
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+
+	if (output == NULL)
+		ret = -EINVAL;
+	else
+		*mgmt = output;
+
+	return ret;
+}
+
+#define MDP_HIST_LUT_SIZE (256)
+static int mdp_hist_lut_write_off(struct mdp_hist_lut_data *data,
+		struct mdp_hist_lut_info *info, uint32_t offset)
+{
+	int i;
+	uint32_t element[MDP_HIST_LUT_SIZE];
+	uint32_t base = mdp_block2base(info->block);
+	uint32_t sel = info->bank_sel;
+
+
+	if (data->len != MDP_HIST_LUT_SIZE) {
+		pr_err("%s: data->len != %d", __func__, MDP_HIST_LUT_SIZE);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&element, data->data,
+				MDP_HIST_LUT_SIZE * sizeof(uint32_t))) {
+		pr_err("%s: Error copying histogram data", __func__);
+		return -ENOMEM;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < MDP_HIST_LUT_SIZE; i++)
+		MDP_OUTP(MDP_BASE + base + offset + (0x400*(sel)) + (4*i),
+				element[i]);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return 0;
+}
+
+static int mdp_hist_lut_write(struct mdp_hist_lut_data *data,
+						struct mdp_hist_lut_info *info)
+{
+	int ret = 0;
+
+	if (data->block != info->block) {
+		ret = -1;
+		pr_err("%s, data/info mdp_block mismatch! %d != %d\n",
+				__func__, data->block, info->block);
+		goto error;
+	}
+
+	switch (data->block) {
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+		ret = mdp_hist_lut_write_off(data, info, 0x3400);
+		break;
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		ret = mdp_hist_lut_write_off(data, info, 0x4800);
+		break;
+	default:
+		ret = -EINVAL;
+		goto error;
+	}
+
+error:
+	return ret;
+}
+
+#define MDP_HIST_LUT_VG_EN_MASK (0x20000)
+#define MDP_HIST_LUT_VG_EN_SHIFT (17)
+#define MDP_HIST_LUT_VG_EN_OFFSET (0x0058)
+#define MDP_HIST_LUT_VG_SEL_OFFSET (0x0064)
+static void mdp_hist_lut_commit_vg(struct mdp_hist_lut_info *info)
+{
+	uint32_t out_en, temp_en;
+	uint32_t base = mdp_block2base(info->block);
+	temp_en = (info->is_enabled) ? (1 << MDP_HIST_LUT_VG_EN_SHIFT) : 0x0;
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	out_en = inpdw(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET) &
+						~MDP_HIST_LUT_VG_EN_MASK;
+	MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET, out_en | temp_en);
+
+	if (info->has_sel_update)
+		MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_SEL_OFFSET,
+								info->bank_sel);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+#define MDP_HIST_LUT_DMA_EN_MASK (0x7)
+#define MDP_HIST_LUT_DMA_SEL_MASK (0x400)
+#define MDP_HIST_LUT_DMA_SEL_SHIFT (10)
+#define MDP_HIST_LUT_DMA_P_OFFSET (0x0070)
+#define MDP_HIST_LUT_DMA_S_OFFSET (0x0028)
+static void mdp_hist_lut_commit_dma(struct mdp_hist_lut_info *info)
+{
+	uint32_t out, temp, mask;
+	uint32_t base = mdp_block2base(info->block);
+	uint32_t offset = (info->block == MDP_BLOCK_DMA_P) ?
+		MDP_HIST_LUT_DMA_P_OFFSET : MDP_HIST_LUT_DMA_S_OFFSET;
+
+	mask = MDP_HIST_LUT_DMA_EN_MASK;
+	temp = (info->is_enabled) ? 0x7 : 0x0;
+
+	if (info->has_sel_update) {
+		mask |= MDP_HIST_LUT_DMA_SEL_MASK;
+		temp |=  ((info->bank_sel & 0x1) << MDP_HIST_LUT_DMA_SEL_SHIFT);
+	}
+
+	out = inpdw(MDP_BASE + base + offset) & ~mask;
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	MDP_OUTP(MDP_BASE + base + offset, out | temp);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+static void mdp_hist_lut_commit_info(struct mdp_hist_lut_info *info)
+{
+	switch (info->block) {
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+		mdp_hist_lut_commit_vg(info);
+		break;
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		mdp_hist_lut_commit_dma(info);
+		break;
+	default:
+		goto error;
+	}
+
+error:
+	return;
+}
+
+static void mdp_hist_lut_update_info(struct mdp_hist_lut_info *info, int ops)
+{
+	info->bank_sel = (ops & 0x8) >> 3;
+	info->is_enabled = (ops & 0x1) ? TRUE : FALSE;
+	info->has_sel_update = (ops & 0x10) ? TRUE : FALSE;
+}
+
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data)
+{
+	struct mdp_hist_lut_mgmt *mgmt = NULL;
+	struct mdp_hist_lut_info info;
+	int ret = 0;
+
+	if (!mdp_pp_block2hist_lut(data->block)) {
+		ret = -ENOTTY;
+		goto error;
+	}
+
+	ret = mdp_hist_lut_block2mgmt(data->block, &mgmt);
+	if (ret)
+		goto error;
+
+	mutex_lock(&mgmt->lock);
+
+	info.block = mgmt->block;
+
+	mdp_hist_lut_update_info(&info, data->ops);
+
+	switch ((data->ops & 0x6) >> 1) {
+	case 0x1:
+		pr_info("%s: histogram LUT read not supported\n", __func__);
+		break;
+	case 0x2:
+		ret = mdp_hist_lut_write(data, &info);
+		if (ret)
+			goto error_lock;
+		break;
+	default:
+		break;
+	}
+
+	mdp_hist_lut_commit_info(&info);
+
+error_lock:
+	mutex_unlock(&mgmt->lock);
+error:
+	return ret;
+}
+
+
 DEFINE_MUTEX(mdp_lut_push_sem);
 static int mdp_lut_i;
 static int mdp_lut_hw_update(struct fb_cmap *cmap)
@@ -211,8 +529,8 @@
 	}
 
 	/*mask off non LUT select bits*/
-	out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
-	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | out);
+	out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
+	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_lut_i = (mdp_lut_i + 1)%2;
 
@@ -225,9 +543,9 @@
 	if (mdp_lut_push) {
 		mutex_lock(&mdp_lut_push_sem);
 		mdp_lut_push = 0;
-		out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
+		out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
 		MDP_OUTP(MDP_BASE + 0x90070,
-				(mdp_lut_push_i << 10) | out);
+				(mdp_lut_push_i << 10) | 0x7 | out);
 		mutex_unlock(&mdp_lut_push_sem);
 	}
 }
@@ -237,20 +555,112 @@
 
 #ifdef CONFIG_FB_MSM_MDP40
 unsigned int mdp_hist_frame_cnt;
-struct completion mdp_hist_comp;
-boolean mdp_is_hist_start = FALSE;
 #else
 static unsigned int mdp_hist_frame_cnt;
-static struct completion mdp_hist_comp;
-static boolean mdp_is_hist_start = FALSE;
 #endif
+struct completion mdp_hist_comp;
 static DEFINE_MUTEX(mdp_hist_mutex);
 static boolean mdp_is_hist_data = FALSE;
+static boolean mdp_is_hist_start = FALSE;
+boolean mdp_is_hist_valid = FALSE;
+static boolean mdp_is_hist_init = FALSE;
+static uint32 mdp_hist_r[128];
+static uint32 mdp_hist_g[128];
+static uint32 mdp_hist_b[128];
+
+void __mdp_histogram_kickoff()
+{
+	char *mdp_hist_base;
+
+	if (mdp_rev >= MDP_REV_40)
+		mdp_hist_base = MDP_BASE + 0x95000;
+	else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
+		mdp_hist_base = MDP_BASE + 0x94000;
+	else {
+		pr_err("%s(): Unsupported MDP rev. %u\n", __func__, mdp_rev);
+		return ;
+	}
+
+	if (mdp_is_hist_data == TRUE) {
+		MDP_OUTP(mdp_hist_base + 0x004,	mdp_hist_frame_cnt);
+		MDP_OUTP(mdp_hist_base, 1);
+	}
+}
+
+void __mdp_histogram_reset()
+{
+	char *mdp_hist_base;
+
+	if (mdp_rev >= MDP_REV_40)
+		mdp_hist_base = MDP_BASE + 0x95000;
+	else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
+		mdp_hist_base = MDP_BASE + 0x94000;
+	else {
+		pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
+		return ;
+	}
+
+	MDP_OUTP(mdp_hist_base + 0x00C, 1);
+}
+
+static void mdp_hist_read_work(struct work_struct *data)
+{
+	char *mdp_hist_base;
+	uint32 r_data_offset = 0x100, g_data_offset = 0x200;
+	uint32 b_data_offset = 0x300;
+	int num_bins, i = 0;
+
+	if (mdp_rev >= MDP_REV_42) {
+		mdp_hist_base = MDP_BASE + 0x95000;
+		r_data_offset = 0x400;
+		g_data_offset = 0x800;
+		b_data_offset = 0xc00;
+		num_bins = 128;
+	} else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_41) {
+		mdp_hist_base = MDP_BASE + 0x95000;
+		num_bins = 32;
+	} else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31) {
+		mdp_hist_base = MDP_BASE + 0x94000;
+		num_bins = 32;
+	} else {
+		pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
+		return ;
+	}
+
+	mutex_lock(&mdp_hist_mutex);
+	if (mdp_is_hist_data == FALSE) {
+		pr_debug("%s, Histogram disabled before read.\n", __func__);
+		goto error;
+	}
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < num_bins; i++) {
+		mdp_hist_r[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
+		mdp_hist_g[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
+		mdp_hist_b[i] = inpdw(mdp_hist_base + b_data_offset + (4*i));
+	}
+
+	__mdp_histogram_kickoff();
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	/* if read was triggered by an underrun, don't wake up readers*/
+	if (mdp_is_hist_valid && mdp_is_hist_init) {
+		complete(&mdp_hist_comp);
+	} else {
+		if (mdp_is_hist_valid == FALSE)
+			mdp_is_hist_valid = TRUE;
+
+		if (mdp_is_hist_init == FALSE)
+			mdp_is_hist_init = TRUE;
+	}
+error:
+	mutex_unlock(&mdp_hist_mutex);
+}
 
 /*should hold mdp_hist_mutex before calling this function*/
 int _mdp_histogram_ctrl(boolean en)
 {
-	unsigned long flag;
 	unsigned long hist_base;
 	uint32_t status;
 
@@ -266,34 +676,40 @@
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		mdp_hist_frame_cnt = 1;
 		mdp_enable_irq(MDP_HISTOGRAM_TERM);
-		spin_lock_irqsave(&mdp_spin_lock, flag);
-		if (mdp_rev >= MDP_REV_40) {
-			MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
-			MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE);
-		}
-		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-		MDP_OUTP(MDP_BASE + hist_base + 0x4, mdp_hist_frame_cnt);
-		MDP_OUTP(MDP_BASE + hist_base, 1);
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		INIT_COMPLETION(mdp_hist_comp);
+
+		/*Clear the interrupts before enabling them*/
+		MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
+						INTR_HIST_RESET_SEQ_DONE);
+		MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
+		MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE |
+						INTR_HIST_RESET_SEQ_DONE);
+
 		mdp_is_hist_data = TRUE;
+		mdp_is_hist_valid = TRUE;
+		mdp_is_hist_init = FALSE;
+
+		__mdp_histogram_reset();
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
 	} else {
 		if (!mdp_is_hist_data)
 			return -EINVAL;
 
 		mdp_is_hist_data = FALSE;
+		mdp_is_hist_valid = FALSE;
+		mdp_is_hist_init = FALSE;
+
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		status = inpdw(MDP_BASE + hist_base + 0x1C);
+		status &= ~(INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+		MDP_OUTP(MDP_BASE + hist_base + 0x1C, status);
+		MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
+						INTR_HIST_RESET_SEQ_DONE);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
 		complete(&mdp_hist_comp);
 
-		if (mdp_rev >= MDP_REV_40) {
-			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-			status = inpdw(MDP_BASE + hist_base + 0x1C);
-			status &= ~INTR_HIST_DONE;
-			MDP_OUTP(MDP_BASE + hist_base + 0x1C, status);
-
-			MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE);
-			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
-									FALSE);
-		}
-
 		mdp_disable_irq(MDP_HISTOGRAM_TERM);
 	}
 
@@ -307,6 +723,10 @@
 	if (mdp_is_hist_start)
 		ret = _mdp_histogram_ctrl(en);
 	mutex_unlock(&mdp_hist_mutex);
+
+	if (en == false)
+		flush_workqueue(mdp_hist_wq);
+
 	return ret;
 }
 
@@ -361,6 +781,10 @@
 
 	ret = _mdp_histogram_ctrl(FALSE);
 
+	mutex_unlock(&mdp_hist_mutex);
+	flush_workqueue(mdp_hist_wq);
+	return ret;
+
 mdp_hist_stop_err:
 	mutex_unlock(&mdp_hist_mutex);
 	return ret;
@@ -369,55 +793,26 @@
 /*call from within mdp_hist_mutex*/
 static int _mdp_copy_hist_data(struct mdp_histogram *hist)
 {
-	char *mdp_hist_base;
-	uint32 r_data_offset = 0x100, g_data_offset = 0x200;
-	uint32 b_data_offset = 0x300;
 	int ret = 0;
 
-	if (mdp_rev >= MDP_REV_42) {
-		mdp_hist_base = MDP_BASE + 0x95000;
-		r_data_offset = 0x400;
-		g_data_offset = 0x800;
-		b_data_offset = 0xc00;
-	} else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_41) {
-		mdp_hist_base = MDP_BASE + 0x95000;
-	} else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31) {
-		mdp_hist_base = MDP_BASE + 0x94000;
-	} else {
-		pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
-		return -EPERM;
-	}
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	if (hist->r) {
-		ret = copy_to_user(hist->r, mdp_hist_base + r_data_offset,
-			hist->bin_cnt * 4);
+		ret = copy_to_user(hist->r, mdp_hist_r, hist->bin_cnt * 4);
 		if (ret)
 			goto hist_err;
 	}
 	if (hist->g) {
-		ret = copy_to_user(hist->g, mdp_hist_base + g_data_offset,
-			hist->bin_cnt * 4);
+		ret = copy_to_user(hist->g, mdp_hist_g, hist->bin_cnt * 4);
 		if (ret)
 			goto hist_err;
 	}
 	if (hist->b) {
-		ret = copy_to_user(hist->b, mdp_hist_base + b_data_offset,
-			hist->bin_cnt * 4);
+		ret = copy_to_user(hist->b, mdp_hist_b, hist->bin_cnt * 4);
 		if (ret)
 			goto hist_err;
 	}
-
-	if (mdp_is_hist_start == TRUE) {
-		MDP_OUTP(mdp_hist_base + 0x004,
-				mdp_hist_frame_cnt);
-		MDP_OUTP(mdp_hist_base, 1);
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	return 0;
-
 hist_err:
-	printk(KERN_ERR "%s: invalid hist buffer\n", __func__);
+	pr_err("%s: invalid hist buffer\n", __func__);
 	return ret;
 }
 
@@ -435,17 +830,17 @@
 
 	mutex_lock(&mdp_hist_mutex);
 	if (!mdp_is_hist_data) {
-		ret = -EINVAL;
-		goto error;
-	}
-
-	if (!mdp_is_hist_start) {
-		printk(KERN_ERR "%s histogram not started\n", __func__);
+		pr_err("%s - histogram not ready\n", __func__);
 		ret = -EPERM;
 		goto error;
 	}
 
-	INIT_COMPLETION(mdp_hist_comp);
+	if (!mdp_is_hist_start) {
+		pr_err("%s histogram not started\n", __func__);
+		ret = -EPERM;
+		goto error;
+	}
+
 	mdp_hist_frame_cnt = hist->frame_cnt;
 	mutex_unlock(&mdp_hist_mutex);
 
@@ -455,8 +850,9 @@
 	}
 
 	mutex_lock(&mdp_hist_mutex);
-	if (mdp_is_hist_data)
+	if (mdp_is_hist_data && mdp_is_hist_init)
 		ret =  _mdp_copy_hist_data(hist);
+
 error:
 	mutex_unlock(&mdp_hist_mutex);
 	return ret;
@@ -592,9 +988,6 @@
 		/* DMA update timestamp */
 		mdp_dma2_last_update_time = ktime_get_real();
 		/* let's turn on DMA2 block */
-#if 0
-		mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-#endif
 #ifdef CONFIG_FB_MSM_MDP22
 		outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0);/* start DMA */
 #else
@@ -645,6 +1038,7 @@
 	}
 #endif
 }
+
 static int mdp_clk_rate;
 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
 static int pdev_list_cnt;
@@ -818,7 +1212,7 @@
 #ifndef CONFIG_FB_MSM_MDP40
 irqreturn_t mdp_isr(int irq, void *ptr)
 {
-	uint32 mdp_interrupt = 0;
+	uint32 hist_interrupt, mdp_interrupt = 0;
 	struct mdp_dma_data *dma;
 	unsigned long flag;
 
@@ -853,24 +1247,34 @@
 	}
 #ifndef CONFIG_FB_MSM_MDP22
 	if (mdp_interrupt & MDP_HIST_DONE) {
+		hist_interrupt = inp32(MDP_DMA_P_HIST_INTR_STATUS);
 		outp32(MDP_BASE + 0x94018, 0x3);
 		outp32(MDP_INTR_CLEAR, MDP_HIST_DONE);
-		complete(&mdp_hist_comp);
+		if (hist_interrupt & INTR_HIST_RESET_SEQ_DONE)
+			__mdp_histogram_kickoff();
+
+		if (hist_interrupt & INTR_HIST_DONE) {
+			if (waitqueue_active(&mdp_hist_comp.wait)) {
+				if (!queue_work(mdp_hist_wq,
+						&mdp_histogram_worker)) {
+					pr_err("%s: can't queue hist_read\n",
+								__func__);
+				}
+			} else
+				__mdp_histogram_reset();
+		}
 	}
 
 	/* LCDC UnderFlow */
 	if (mdp_interrupt & LCDC_UNDERFLOW) {
 		mdp_lcdc_underflow_cnt++;
 		/*when underflow happens HW resets all the histogram
-		 registers that were set before so restore them back
-		 to normal.*/
+		  registers that were set before so restore them back
+		  to normal.*/
 		MDP_OUTP(MDP_BASE + 0x94010, 1);
-		MDP_OUTP(MDP_BASE + 0x9401c, 2);
-		if (mdp_is_hist_start == TRUE) {
-			MDP_OUTP(MDP_BASE + 0x94004,
-					 mdp_hist_frame_cnt);
-			MDP_OUTP(MDP_BASE + 0x94000, 1);
-		}
+		MDP_OUTP(MDP_BASE + 0x9401c, INTR_HIST_DONE);
+		mdp_is_hist_valid = FALSE;
+		__mdp_histogram_reset();
 	}
 
 	/* LCDC Frame Start */
@@ -969,6 +1373,8 @@
 	spin_lock_init(&mdp_spin_lock);
 	mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
 	mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
+	mdp_hist_wq = create_singlethread_workqueue("mdp_hist_wq");
+	INIT_WORK(&mdp_histogram_worker, mdp_hist_read_work);
 	mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
 	INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
 			  mdp_pipe_ctrl_workqueue_handler);
@@ -1009,8 +1415,6 @@
 	mutex_init(&dma_wb_data.ov_mutex);
 #endif
 
-
-
 #ifndef CONFIG_FB_MSM_MDP22
 	init_completion(&mdp_hist_comp);
 #endif
@@ -1101,12 +1505,16 @@
 static int mdp_off(struct platform_device *pdev)
 {
 	int ret = 0;
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
 
 	mdp_histogram_ctrl(FALSE);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	ret = panel_next_off(pdev);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
+		mdp_dsi_cmd_overlay_suspend();
 	return ret;
 }
 
@@ -1128,7 +1536,6 @@
 	}
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 #endif
-	mdp_histogram_ctrl(TRUE);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	ret = panel_next_on(pdev);
@@ -1141,6 +1548,7 @@
 		mdp4_mddi_overlay_restore();
 #endif
 
+	mdp_histogram_ctrl(TRUE);
 	return ret;
 }
 
@@ -1284,7 +1692,7 @@
 	return clk_rate;
 }
 
-static int mdp_irq_clk_setup(void)
+static int mdp_irq_clk_setup(char cont_splashScreen)
 {
 	int ret;
 
@@ -1337,12 +1745,18 @@
 	 * mdp_clk should greater than mdp_pclk always
 	 */
 	if (mdp_pdata && mdp_pdata->mdp_core_clk_rate) {
+		if (cont_splashScreen)
+			mdp_clk_rate = clk_get_rate(mdp_clk);
+		else
+			mdp_clk_rate = mdp_pdata->mdp_core_clk_rate;
+
 		mutex_lock(&mdp_clk_lock);
-		clk_set_rate(mdp_clk, mdp_pdata->mdp_core_clk_rate);
+		clk_set_rate(mdp_clk, mdp_clk_rate);
 		if (mdp_lut_clk != NULL)
-			clk_set_rate(mdp_lut_clk, mdp_pdata->mdp_core_clk_rate);
+			clk_set_rate(mdp_lut_clk, mdp_clk_rate);
 		mutex_unlock(&mdp_clk_lock);
 	}
+
 	MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk));
 #endif
 	return 0;
@@ -1362,6 +1776,7 @@
 #if defined(CONFIG_FB_MSM_MIPI_DSI) && defined(CONFIG_FB_MSM_MDP40)
 	struct mipi_panel_info *mipi;
 #endif
+	static int contSplash_update_done;
 
 	if ((pdev->id == 0) && (pdev->num_resources > 0)) {
 
@@ -1383,7 +1798,8 @@
 		}
 
 		mdp_rev = mdp_pdata->mdp_rev;
-		rc = mdp_irq_clk_setup();
+
+		rc = mdp_irq_clk_setup(mdp_pdata->cont_splash_enabled);
 
 		if (rc)
 			return rc;
@@ -1392,7 +1808,8 @@
 
 		/* initializing mdp hw */
 #ifdef CONFIG_FB_MSM_MDP40
-		mdp4_hw_init();
+		if (!(mdp_pdata->cont_splash_enabled))
+			mdp4_hw_init();
 #else
 		mdp_hw_init();
 #endif
@@ -1426,6 +1843,18 @@
 	mfd->pdev = msm_fb_dev;
 	mfd->mdp_rev = mdp_rev;
 
+	if (mdp_pdata) {
+		if (mdp_pdata->cont_splash_enabled) {
+			mfd->cont_splash_done = 0;
+			if (!contSplash_update_done) {
+				mdp_pipe_ctrl(MDP_CMD_BLOCK,
+					MDP_BLOCK_POWER_ON, FALSE);
+				contSplash_update_done = 1;
+			}
+		} else
+			mfd->cont_splash_done = 1;
+	}
+
 	mfd->ov0_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type));
 	mfd->ov1_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type));
 	memset((void *)mfd->ov0_wb_buf, 0, sizeof(struct mdp_buf_type));
@@ -1440,10 +1869,12 @@
 		mfd->ov1_wb_buf->size = 0;
 		mfd->mem_hid = 0;
 	}
-
 	mfd->ov0_blt_state  = 0;
 	mfd->use_ov0_blt = 0 ;
 
+    /* initialize Post Processing data*/
+	mdp_hist_lut_init();
+
 	/* add panel data */
 	if (platform_device_add_data
 	    (msm_fb_dev, pdev->dev.platform_data,
@@ -1598,6 +2029,8 @@
 			rc = -ENODEV;
 			goto mdp_probe_err;
 		}
+		INIT_WORK(&mfd->dma_update_worker,
+			mdp_lcd_update_workqueue_handler);
 #endif
 		mdp_config_vsync(mfd);
 		break;
@@ -1716,6 +2149,11 @@
 			return -ENOMEM;
 		}
 	}
+
+	/* req bus bandwidth immediately */
+	if (!(mfd->cont_splash_done))
+		mdp_bus_scale_update_request(5);
+
 #endif
 
 	/* set driver data */
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 35a1453..be57ee0 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,6 +44,10 @@
 extern int mdp_rev;
 extern struct mdp_csc_cfg mdp_csc_convert[4];
 
+extern struct workqueue_struct *mdp_hist_wq;
+extern struct work_struct mdp_histogram_worker;
+extern boolean mdp_is_hist_valid;
+
 #define MDP4_REVISION_V1		0
 #define MDP4_REVISION_V2		1
 #define MDP4_REVISION_V2_1	2
@@ -83,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
@@ -221,6 +226,20 @@
 	struct completion dmap_comp;
 };
 
+extern struct list_head mdp_hist_lut_list;
+extern struct mutex mdp_hist_lut_list_mutex;
+struct mdp_hist_lut_mgmt {
+	uint32_t block;
+	struct mutex lock;
+	struct list_head list;
+};
+
+struct mdp_hist_lut_info {
+	uint32_t block;
+	boolean is_enabled, has_sel_update;
+	int bank_sel;
+};
+
 #define MDP_CMD_DEBUG_ACCESS_BASE   (MDP_BASE+0x10000)
 
 #define MDP_DMA2_TERM 0x1
@@ -606,6 +625,10 @@
 #define MDP_EBI2_LCD0		(msm_mdp_base + 0x003c)
 #define MDP_EBI2_LCD1		(msm_mdp_base + 0x0040)
 #define MDP_EBI2_PORTMAP_MODE	(msm_mdp_base + 0x005c)
+
+#define MDP_DMA_P_HIST_INTR_STATUS	(msm_mdp_base + 0x94014)
+#define MDP_DMA_P_HIST_INTR_CLEAR	(msm_mdp_base + 0x94018)
+#define MDP_DMA_P_HIST_INTR_ENABLE	(msm_mdp_base + 0x9401C)
 #endif
 
 #define MDP_FULL_BYPASS_WORD43  (msm_mdp_base + 0x101ac)
@@ -694,6 +717,8 @@
 void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd);
 #endif
 
+void set_cont_splashScreen_status(int);
+
 int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor);
 #if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDP40)
 int mdp_hw_cursor_sync_update(struct fb_info *info, struct fb_cursor *cursor);
@@ -716,6 +741,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
@@ -733,6 +763,8 @@
 int mdp_start_histogram(struct fb_info *info);
 int mdp_stop_histogram(struct fb_info *info);
 int mdp_histogram_ctrl(boolean en);
+void __mdp_histogram_kickoff(void);
+void __mdp_histogram_reset(void);
 void mdp_footswitch_ctrl(boolean on);
 
 #ifdef CONFIG_FB_MSM_MDP303
@@ -755,4 +787,17 @@
 }
 #endif
 
+#ifndef CONFIG_FB_MSM_MDP40
+static inline void mdp_dsi_cmd_overlay_suspend(void)
+{
+	/* empty */
+}
+#endif
+
+int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
+int mdp_ppp_v4l2_overlay_clear(void);
+int mdp_ppp_v4l2_overlay_play(struct fb_info *info,
+	unsigned long srcp0_addr, unsigned long srcp0_size,
+	unsigned long srcp1_addr, unsigned long srcp1_size);
+
 #endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 155bc54..9c047e5 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -20,7 +20,6 @@
 extern struct mdp_dma_data dma_wb_data;
 extern unsigned int mdp_hist_frame_cnt;
 extern struct completion mdp_hist_comp;
-extern boolean mdp_is_hist_start;
 extern boolean mdp_is_in_isr;
 extern uint32 mdp_intr_mask;
 extern spinlock_t mdp_spin_lock;
@@ -247,6 +246,12 @@
 	int32_t dirty;
 };
 
+struct mdp4_iommu_pipe_info {
+	struct ion_handle *ihdl[MDP4_MAX_PLANE];
+	struct ion_handle *prev_ihdl[MDP4_MAX_PLANE];
+	u8 mark_unmap;
+};
+
 struct mdp4_overlay_pipe {
 	uint32 pipe_used;
 	uint32 pipe_type;		/* rgb, video/graphic */
@@ -410,6 +415,7 @@
 uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
 void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
 #ifdef CONFIG_FB_MSM_DTV
+void mdp4_overlay_dtv_start(void);
 void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe);
 void mdp4_overlay_dtv_wait_for_ov(struct msm_fb_data_type *mfd,
@@ -419,7 +425,12 @@
 int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe);
 void mdp4_dma_e_done_dtv(void);
+void mdp4_overlay_dtv_wait4vsync(void);
 #else
+static inline void mdp4_overlay_dtv_start(void)
+{
+	/* empty */
+}
 static inline void  mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe)
 {
@@ -440,21 +451,19 @@
 {
 	return 0;
 }
+
 static inline void mdp4_dma_e_done_dtv(void)
 {
-	return;
+    /* empty */
 }
-#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)
+static inline void mdp4_overlay_dtv_wait4vsync(void)
 {
     /* empty */
 }
 #endif
 
+void mdp4_dtv_set_black_screen(void);
+
 static inline int mdp4_overlay_borderfill_supported(void)
 {
 	unsigned int mdp_hw_version;
@@ -520,6 +529,7 @@
 void mdp4_primary_vsync_lcdc(void);
 void mdp4_external_vsync_dtv(void);
 void mdp4_overlay_lcdc_wait4vsync(struct msm_fb_data_type *mfd);
+void mdp4_overlay_lcdc_start(void);
 void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
 void mdp4_update_perf_level(u32 perf_level);
@@ -637,9 +647,11 @@
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd);
 void mdp4_dsi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
+void mdp4_overlay_dsi_video_start(void);
 void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
 void mdp4_dsi_cmd_overlay_restore(void);
+void mdp_dsi_cmd_overlay_suspend(void);
 #else
 static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
 {
@@ -649,6 +661,10 @@
 {
 	/* empty */
 }
+static inline void mdp4_overlay_dsi_video_start(void)
+{
+	/* empty */
+}
 static inline void mdp4_overlay_dsi_video_vsync_push(
 	struct msm_fb_data_type *mfd, struct mdp4_overlay_pipe *pipe)
 {
@@ -658,6 +674,12 @@
 {
 	/* empty */
 }
+#ifdef CONFIG_FB_MSM_MDP40
+static inline void mdp_dsi_cmd_overlay_suspend(void)
+{
+	/* empty */
+}
+#endif
 #endif /* MIPI_DSI */
 
 void mdp4_dsi_cmd_kickoff_ui(struct msm_fb_data_type *mfd,
@@ -708,14 +730,29 @@
 int mdp4_writeback_init(struct fb_info *info);
 int mdp4_writeback_terminate(struct fb_info *info);
 
+uint32_t mdp_block2base(uint32_t block);
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data);
+
 void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl);
 void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe);
 int mdp4_csc_config(struct mdp_csc_cfg_data *config);
 void mdp4_csc_write(struct mdp_csc_cfg *data, uint32_t base);
 int mdp4_csc_enable(struct mdp_csc_cfg_data *config);
+int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr);
+int mdp4_argc_cfg(struct mdp_pgc_lut_data *pgc_ptr);
 
 u32  mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
+void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe);
+void mdp4_iommu_attach(void);
+int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
+		struct mdp4_overlay_pipe **ppipe);
+void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe);
+int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
+	unsigned long srcp0_addr, unsigned long srcp1_addr,
+	unsigned long srcp2_addr);
+
 #endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index ba774b9..e3115a3 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -109,7 +109,6 @@
 		clk_disable(ebi1_clk);
 #endif
 	mdp4_extn_disp = 0;
-	mdp_footswitch_ctrl(FALSE);
 	return ret;
 }
 
@@ -127,7 +126,6 @@
 		pm_qos_rate = panel_pixclock_freq / 1000 ;
 	else
 		pm_qos_rate = 58000;
-	mdp_footswitch_ctrl(TRUE);
 	mdp4_extn_disp = 1;
 #ifdef CONFIG_MSM_BUS_SCALING
 	if (dtv_bus_scale_handle > 0)
@@ -225,11 +223,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 4f8be7e..b4a9512 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -21,6 +21,8 @@
 #include <linux/hrtimer.h>
 #include <linux/clk.h>
 #include <mach/hardware.h>
+#include <mach/iommu_domains.h>
+#include <mach/iommu.h>
 #include <linux/io.h>
 #include <linux/debugfs.h>
 #include <linux/fb.h>
@@ -96,6 +98,104 @@
 
 static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db;
 static int new_perf_level;
+static struct ion_client *display_iclient;
+static struct mdp4_iommu_pipe_info mdp_iommu[MDP4_MIXER_MAX][OVERLAY_PIPE_RGB3];
+
+int mdp4_overlay_iommu_map_buf(int mem_id,
+	struct mdp4_overlay_pipe *pipe, unsigned int plane,
+	unsigned long *start, unsigned long *len,
+	struct ion_handle **srcp_ihdl)
+{
+	struct mdp4_iommu_pipe_info *iom_pipe_info;
+
+	if (!display_iclient)
+		return -EINVAL;
+
+	*srcp_ihdl = ion_import_fd(display_iclient, mem_id);
+	if (IS_ERR_OR_NULL(*srcp_ihdl)) {
+		pr_err("ion_import_fd() failed\n");
+		return PTR_ERR(*srcp_ihdl);
+	}
+	pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *srcp_ihdl,
+		ion_share(display_iclient, *srcp_ihdl));
+	pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num,
+		pipe->pipe_ndx, plane);
+	if (ion_map_iommu(display_iclient, *srcp_ihdl,
+		DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, start,
+		len, 0, ION_IOMMU_UNMAP_DELAYED)) {
+		ion_free(display_iclient, *srcp_ihdl);
+		pr_err("ion_map_iommu() failed\n");
+		return -EINVAL;
+	}
+
+	iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1];
+	if (!iom_pipe_info->ihdl[plane]) {
+		iom_pipe_info->ihdl[plane] = *srcp_ihdl;
+	} else {
+		if (iom_pipe_info->prev_ihdl[plane]) {
+			ion_unmap_iommu(display_iclient,
+				iom_pipe_info->prev_ihdl[plane],
+				DISPLAY_DOMAIN, GEN_POOL);
+			ion_free(display_iclient,
+				iom_pipe_info->prev_ihdl[plane]);
+			pr_debug("Previous: mixer %u, pipe %u, plane %u, "
+				"prev_ihdl %p\n", pipe->mixer_num,
+				pipe->pipe_ndx, plane,
+				iom_pipe_info->prev_ihdl[plane]);
+		}
+
+		iom_pipe_info->prev_ihdl[plane] = iom_pipe_info->ihdl[plane];
+		iom_pipe_info->ihdl[plane] = *srcp_ihdl;
+	}
+	pr_debug("mem_id %d, start 0x%lx, len 0x%lx\n",
+		mem_id, *start, *len);
+	return 0;
+}
+
+void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe)
+{
+	struct mdp4_iommu_pipe_info *iom_pipe_info;
+	unsigned char i, j;
+
+	if (!display_iclient)
+		return;
+
+	for (j = 0; j < OVERLAY_PIPE_RGB3; j++) {
+		iom_pipe_info = &mdp_iommu[pipe->mixer_num][j];
+		for (i = 0; i < MDP4_MAX_PLANE; i++) {
+			if (iom_pipe_info->prev_ihdl[i]) {
+				pr_debug("%s(): mixer %u, pipe %u, plane %u, "
+					"prev_ihdl %p\n", __func__,
+					pipe->mixer_num, j + 1, i,
+					iom_pipe_info->prev_ihdl[i]);
+				ion_unmap_iommu(display_iclient,
+					iom_pipe_info->prev_ihdl[i],
+					DISPLAY_DOMAIN, GEN_POOL);
+				ion_free(display_iclient,
+					iom_pipe_info->prev_ihdl[i]);
+				iom_pipe_info->prev_ihdl[i] = NULL;
+			}
+
+			if (iom_pipe_info->mark_unmap) {
+				if (iom_pipe_info->ihdl[i]) {
+					if (pipe->mixer_num == MDP4_MIXER1)
+						mdp4_overlay_dtv_wait4vsync();
+					pr_debug("%s(): mixer %u, pipe %u, plane %u, "
+						"ihdl %p\n", __func__,
+						pipe->mixer_num, j + 1, i,
+						iom_pipe_info->ihdl[i]);
+					ion_unmap_iommu(display_iclient,
+						iom_pipe_info->ihdl[i],
+						DISPLAY_DOMAIN, GEN_POOL);
+					ion_free(display_iclient,
+						iom_pipe_info->ihdl[i]);
+					iom_pipe_info->ihdl[i] = NULL;
+				}
+			}
+		}
+		iom_pipe_info->mark_unmap = 0;
+	}
+}
 
 /* static array with index 0 for unset status and 1 for set status */
 static bool overlay_status[MDP4_OVERLAY_TYPE_MAX];
@@ -277,6 +377,7 @@
 void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc)
 {
 	uint32	dma2_cfg_reg;
+	uint32 mask, curr;
 
 	dma2_cfg_reg = DMA_DITHER_EN;
 #ifdef BLT_RGB565
@@ -309,6 +410,9 @@
 #endif
 
 	/* dma2 config register */
+	curr = inpdw(MDP_BASE + 0x90000);
+	mask = 0xBFFFFFFF;
+	dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
 	MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -398,7 +502,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;
@@ -420,7 +525,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;
@@ -442,6 +548,7 @@
 	char *rgb_base;
 	uint32 src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern;
+	uint32 curr, mask;
 	uint32 offset = 0;
 	int pnum;
 
@@ -473,6 +580,12 @@
 
 	mdp4_scale_setup(pipe);
 
+	/* Ensure proper covert matrix loaded when color space swaps */
+	curr = inpdw(rgb_base + 0x0058);
+	/* Don't touch bits you don't want to configure*/
+	mask = 0xFFFEFFFF;
+	pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	outpdw(rgb_base + 0x0000, src_size);	/* MDP_RGB_SRC_SIZE */
@@ -485,7 +598,13 @@
 
 	outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */
 	outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */
-	outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */
+	if (format & MDP4_FORMAT_SOLID_FILL) {
+		u32 op_mode = pipe->op_mode;
+		op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
+		op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
+		outpdw(rgb_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */
+	} else
+		outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */
 	outpdw(rgb_base + 0x005c, pipe->phasex_step);
 	outpdw(rgb_base + 0x0060, pipe->phasey_step);
 
@@ -558,7 +677,7 @@
 	char *vg_base;
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
-	uint32 mask, curr;
+	uint32 mask, curr, addr;
 	int pnum, ptype;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -625,13 +744,20 @@
 	/* Ensure proper covert matrix loaded when color space swaps */
 	curr = inpdw(vg_base + 0x0058);
 	mask = 0x600;
+
 	if ((curr & mask) != (pipe->op_mode & mask)) {
-		curr = ((uint32_t)vg_base) + 0x4000;
+		addr = ((uint32_t)vg_base) + 0x4000;
 		if (ptype != OVERLAY_TYPE_RGB)
-			mdp4_csc_write(&(mdp_csc_convert[1]), curr);
+			mdp4_csc_write(&(mdp_csc_convert[1]), addr);
 		else
-			mdp4_csc_write(&(mdp_csc_convert[0]), curr);
+			mdp4_csc_write(&(mdp_csc_convert[0]), addr);
+
+		mask = 0xFFFCFFFF;
+	} else {
+		/* Don't touch bits you don't want to configure*/
+		mask = 0xFFFCF1FF;
 	}
+	pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
 
 	/* luma component plane */
 	outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset);
@@ -650,7 +776,13 @@
 
 	outpdw(vg_base + 0x0050, format);	/* MDP_RGB_SRC_FORMAT */
 	outpdw(vg_base + 0x0054, pattern);	/* MDP_RGB_SRC_UNPACK_PATTERN */
-	outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */
+	if (format & MDP4_FORMAT_SOLID_FILL) {
+		u32 op_mode = pipe->op_mode;
+		op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
+		op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
+		outpdw(vg_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */
+	} else
+		outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */
 	outpdw(vg_base + 0x005c, pipe->phasex_step);
 	outpdw(vg_base + 0x0060, pipe->phasey_step);
 
@@ -1304,6 +1436,11 @@
 	u32 data = 0, stage, flush_bits = 0, pipe_cnt = 0, pull_mode = 0;
 	u32 cfg[MDP4_MIXER_MAX];
 
+	if (mixer == MDP4_MIXER0)
+		flush_bits |= 0x1;
+	else if (mixer == MDP4_MIXER1)
+		flush_bits |= 0x2;
+
 	for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++) {
 		cfg[i] = 0;
 		for (j = MDP4_MIXER_STAGE_BASE; j < MDP4_MIXER_STAGE_MAX; j++) {
@@ -1318,58 +1455,69 @@
 			pipe_cnt++;
 
 			mdp4_mixer_blend_setup(pipe);
-			if (i == mixer && pipe->pipe_num <= OVERLAY_PIPE_RGB2)
-				flush_bits |= (1 << (2 + pipe->pipe_num));
 		}
 	}
 
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	if (ctrl->mixer_cfg[mixer] != cfg[mixer]) {
-		if (mixer <= MDP4_MIXER1) {
+		if ((ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) ||
+		    (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1])) {
 			off = 0x10100;
 			if (ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) {
 				flush_bits |= 0x1;
 				ctrl->mixer_cfg[MDP4_MIXER0] = cfg[MDP4_MIXER0];
+
+				if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
+				    (ctrl->panel_mode & MDP4_PANEL_LCDC))
+					pull_mode = 1;
 			}
 			if (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1]) {
 				flush_bits |= 0x2;
 				ctrl->mixer_cfg[MDP4_MIXER1] = cfg[MDP4_MIXER1];
+
+				pull_mode = 1;
 			}
+
 			data = cfg[MDP4_MIXER0] | cfg[MDP4_MIXER1];
-		} else {
+
+			pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
+			       mixer, data, flush_bits);
+
+			outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
+			if (pull_mode)
+				outpdw(MDP_BASE + 0x18000, flush_bits);
+		}
+
+		if (ctrl->mixer_cfg[MDP4_MIXER2] != cfg[MDP4_MIXER2]) {
+			/* wait for vsync on both pull mode interfaces */
+			if (pull_mode)
+				msleep(20);
+
 			off = 0x100F0;
 			ctrl->mixer_cfg[MDP4_MIXER2] = cfg[MDP4_MIXER2];
 			data = cfg[MDP4_MIXER2];
+
+			pr_debug("%s: mixer=%d data=%x\n", __func__,
+			       mixer, data);
+
+			outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
 		}
-
-		pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
-		       mixer, data, flush_bits);
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		outpdw(MDP_BASE + off, data); /* MDP_LAYERMIXER_IN_CFG */
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-	}
-
-	if (mixer == MDP4_MIXER0) {
-		if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
-		    (ctrl->panel_mode & MDP4_PANEL_LCDC))
+	} else {
+		if (mixer == MDP4_MIXER0) {
+			if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
+			(ctrl->panel_mode & MDP4_PANEL_LCDC))
+				pull_mode = 1;
+		} else if (mixer == MDP4_MIXER1) {
 			pull_mode = 1;
-	} else if (mixer == MDP4_MIXER1) {
-		pull_mode = 1;
-	}
-
-	if (pull_mode) {
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		outpdw(MDP_BASE + 0x18000, flush_bits);
-		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 (pull_mode)
+			outpdw(MDP_BASE + 0x18000, flush_bits);
 	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	if (data && pipe_cnt == 1)
+		mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
 }
 
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
@@ -1475,11 +1623,21 @@
 	if (pipe->is_fg) {
 		if (pipe->alpha == 0xff &&
 			bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
+			u32 op_mode;
 			pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
 			rgb_base = MDP_BASE + MDP4_RGB_BASE;
 			rgb_base += MDP4_RGB_OFF * pnum;
 			rgb_src_format = inpdw(rgb_base + 0x50);
 			rgb_src_format |= MDP4_FORMAT_SOLID_FILL;
+			/*
+			 * If solid fill is enabled, flip and scale
+			 * have to be disabled. otherwise, h/w
+			 * underruns.
+			 */
+			op_mode = inpdw(rgb_base + 0x0058);
+			op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
+			op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
+			outpdw(rgb_base + 0x0058, op_mode);
 			outpdw(rgb_base + 0x50, rgb_src_format);
 			outpdw(rgb_base + 0x1008, constant_color);
 		}
@@ -1532,15 +1690,23 @@
 
 void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all)
 {
+	struct mdp4_overlay_pipe *bg_pipe;
 	uint32 bits = 0;
 
-	if (pipe->mixer_num == MDP4_MIXER1)
-		bits |= 0x02;
-	else
-		bits |= 0x01;
+	if (all) {
+		if (pipe->mixer_num == MDP4_MIXER1)
+			bits |= 0x02;
+		else
+			bits |= 0x01;
+	}
 
-	if (all && pipe->pipe_num <= OVERLAY_PIPE_RGB2)
+	if (pipe->pipe_num <= OVERLAY_PIPE_RGB2)
 		bits |= 1 << (2 + pipe->pipe_num);
+	if (pipe->is_fg && pipe->alpha == 0xFF) {
+		bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
+						  MDP4_MIXER_STAGE_BASE);
+		bits |= 1 << (2 + bg_pipe->pipe_num);
+	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	outpdw(MDP_BASE + 0x18000, bits);	/* MDP_OVERLAY_REG_FLUSH */
@@ -1597,6 +1763,7 @@
 void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe)
 {
 	uint32 ptype, num, ndx, mixer;
+	struct mdp4_iommu_pipe_info *iom_pipe_info;
 
 	pr_debug("%s: pipe=%x ndx=%d\n", __func__, (int)pipe, pipe->pipe_ndx);
 
@@ -1604,6 +1771,8 @@
 	num = pipe->pipe_num;
 	ndx = pipe->pipe_ndx;
 	mixer = pipe->mixer_num;
+	iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1];
+	iom_pipe_info->mark_unmap = 1;
 
 	memset(pipe, 0, sizeof(*pipe));
 
@@ -1691,6 +1860,7 @@
 			struct msm_fb_data_type *mfd)
 {
 	struct mdp4_overlay_pipe *pipe;
+	struct mdp4_iommu_pipe_info *iom_pipe_info;
 	int ret, ptype;
 
 	if (mfd == NULL) {
@@ -1804,6 +1974,15 @@
 		return -ENOMEM;
 	}
 
+	if (!display_iclient && !IS_ERR_OR_NULL(mfd->iclient)) {
+		display_iclient = mfd->iclient;
+		pr_debug("%s(): display_iclient %p\n", __func__,
+			display_iclient);
+	}
+
+	iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1];
+	iom_pipe_info->mark_unmap = 0;
+
 	pipe->src_format = req->src.format;
 	ret = mdp4_overlay_format2pipe(pipe);
 
@@ -1867,17 +2046,17 @@
 }
 
 static int get_img(struct msmfb_data *img, struct fb_info *info,
+	struct mdp4_overlay_pipe *pipe, unsigned int plane,
 	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;
-#endif
 	struct file *file;
 	int put_needed, ret = 0, fb_num;
 #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,
@@ -1891,10 +2070,13 @@
 
 		if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
 			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
-			if (get_fb_phys_info(start, len, fb_num))
+			if (get_fb_phys_info(start, len, fb_num,
+				DISPLAY_SUBSYSTEM_ID)) {
 				ret = -1;
-			else
+			} else {
 				*srcp_file = file;
+				*p_need = put_needed;
+			}
 		} else
 			ret = -1;
 		if (ret)
@@ -1903,13 +2085,8 @@
 	}
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	*srcp_ihdl = ion_import_fd(mfd->iclient, img->memory_id);
-	if (IS_ERR_OR_NULL(*srcp_ihdl))
-		return PTR_ERR(*srcp_ihdl);
-	if (!ion_phys(mfd->iclient, *srcp_ihdl, start, (size_t *) len))
-		return 0;
-	else
-		return -EINVAL;
+	return mdp4_overlay_iommu_map_buf(img->memory_id, pipe, plane,
+		start, len, srcp_ihdl);
 #endif
 #ifdef CONFIG_ANDROID_PMEM
 	if (!get_pmem_file(img->memory_id, start, &vstart,
@@ -2011,9 +2188,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)
 {
@@ -2032,9 +2207,10 @@
 	}
 }
 
-static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req)
+static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
+					  struct msm_fb_data_type *mfd)
 {
-	int is_fg;
+	int is_fg = 0, i, cnt;
 
 	if (req->is_fg && ((req->alpha & 0x0ff) == 0xff))
 		is_fg = 1;
@@ -2045,9 +2221,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))
@@ -2055,10 +2232,23 @@
 	else if (mdp4_overlay_is_rgb_type(req->src.format))
 		return OVERLAY_PERF_LEVEL1;
 
-	if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE)
-		return OVERLAY_PERF_LEVEL3;
-	else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE)
-		return OVERLAY_PERF_LEVEL2;
+	if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE) {
+		if (mfd->mdp_rev >= MDP_REV_42)
+			return OVERLAY_PERF_LEVEL4;
+		else
+			return OVERLAY_PERF_LEVEL3;
+
+	} else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) {
+		u32 max, min;
+		max = (req->dst_rect.h > req->dst_rect.w) ?
+			req->dst_rect.h : req->dst_rect.w;
+		min = (mfd->panel_info.yres > mfd->panel_info.xres) ?
+			mfd->panel_info.xres : mfd->panel_info.yres;
+		if (max > min)	/* landscape mode */
+			return OVERLAY_PERF_LEVEL3;
+		else		/* potrait mode */
+			return OVERLAY_PERF_LEVEL2;
+	}
 	else
 		return OVERLAY_PERF_LEVEL1;
 }
@@ -2081,6 +2271,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);
 	}
 }
 
@@ -2107,6 +2299,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)
 {
@@ -2117,7 +2324,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 ||
@@ -2136,7 +2344,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;
@@ -2153,8 +2362,9 @@
 		return -ENODEV;
 	}
 
-	if (!mfd->panel_power_on)	/* suspended */
-		return -EPERM;
+	if (info->node != 0 || mfd->cont_splash_done)	/* primary */
+		if (!mfd->panel_power_on)		/* suspended */
+			return -EPERM;
 
 	if (req->src.format == MDP_FB_FORMAT)
 		req->src.format = mfd->fb_imgType;
@@ -2164,8 +2374,6 @@
 		return -EINTR;
 	}
 
-	perf_level = mdp4_overlay_get_perf_level(req);
-
 	mixer = mfd->panel_info.pdest;	/* DISPLAY_1 or DISPLAY_2 */
 
 	ret = mdp4_overlay_req2pipe(req, mixer, &pipe, mfd);
@@ -2176,31 +2384,37 @@
 		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));
 		mfd->use_ov0_blt |= (use_blt << (pipe->pipe_ndx-1));
 	}
 
-	if (!IS_ERR_OR_NULL(mfd->iclient)) {
-		if (pipe->flags & MDP_SECURE_OVERLAY_SESSION)
-			mfd->mem_hid |= ION_SECURE;
-		else
-			mfd->mem_hid &= ~ION_SECURE;
-	}
-
 	/* return id back to user */
 	req->id = pipe->pipe_ndx;	/* pipe_ndx start from 1 */
 	pipe->req_data = *req;		/* keep original req */
 
 	pipe->flags = req->flags;
 
+	if (!IS_ERR_OR_NULL(mfd->iclient)) {
+		pr_debug("pipe->flags 0x%x\n", pipe->flags);
+		if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) {
+			mfd->mem_hid &= ~BIT(ION_IOMMU_HEAP_ID);
+			mfd->mem_hid |= ION_SECURE;
+		} else {
+			mfd->mem_hid |= BIT(ION_IOMMU_HEAP_ID);
+			mfd->mem_hid &= ~ION_SECURE;
+		}
+	}
+
 	if (pipe->flags & MDP_SHARPENING) {
 		bool test = ((pipe->req_data.dpp.sharp_strength > 0) &&
 			((req->src_rect.w > req->dst_rect.w) &&
 			 (req->src_rect.h > req->dst_rect.h)));
 		if (test) {
-			pr_warn("%s: No sharpening while downscaling.\n",
+			pr_debug("%s: No sharpening while downscaling.\n",
 								__func__);
 			pipe->flags &= ~MDP_SHARPENING;
 		}
@@ -2219,8 +2433,21 @@
 	}
 
 	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);
+
+		if (hdmi_prim_display) {
+			if (!mdp4_overlay_is_rgb_type(req->src.format) &&
+				pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
+				(req->src_rect.h > req->dst_rect.h ||
+				req->src_rect.w > req->dst_rect.w))
+				use_blt = 1;
+		}
+
 		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;
@@ -2243,19 +2470,14 @@
 				mdp4_set_perf_level();
 			}
 		} else {
-			if (ctrl->panel_mode & MDP4_PANEL_DTV)
+			if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+				mdp4_overlay_reg_flush(pipe, 0);
 				mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+			}
 		}
 	}
 	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;
 }
 
@@ -2300,8 +2522,8 @@
 #endif
 	}
 
-	if (mfd->mdp_rev >= MDP_REV_42 && !mfd->use_ov0_blt &&
-	    !(ctrl->panel_mode & (MDP4_PANEL_MDDI | MDP4_PANEL_DSI_CMD))) {
+	if (mfd->mdp_rev >= MDP_REV_41 && !mfd->use_ov0_blt &&
+		(pipe->mixer_num == MDP4_MIXER0)) {
 		ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
 	} else {
 		mdp4_mixer_stage_down(pipe);
@@ -2311,6 +2533,11 @@
 			if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
 				if (mfd->panel_power_on)
 					mdp4_dsi_cmd_overlay_restore();
+			} else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+				pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+				if (mfd->panel_power_on)
+					mdp4_overlay_dsi_video_vsync_push(mfd,
+									  pipe);
 			}
 #else
 			if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
@@ -2321,13 +2548,24 @@
 					mdp4_mddi_overlay_restore();
 			}
 #endif
+			else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+				pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+				if (mfd->panel_power_on)
+					mdp4_overlay_lcdc_vsync_push(mfd, pipe);
+			}
 			mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
 			mdp4_overlay_update_blt_mode(mfd);
 			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);
+			}
 		}
 	}
 
@@ -2344,8 +2582,6 @@
 
 	mdp4_overlay_pipe_free(pipe);
 
-	mdp4_set_perf_level();
-
 	mutex_unlock(&mfd->dma->ov_mutex);
 
 	return 0;
@@ -2406,7 +2642,11 @@
 
 	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);
+	mdp4_iommu_unmap(pipe);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
 	return 0;
@@ -2423,6 +2663,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;
 
@@ -2442,7 +2683,8 @@
 		return -EINTR;
 
 	img = &req->data;
-	get_img(img, info, &start, &len, &srcp0_file, &srcp0_ihdl);
+	get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
+		&ps0_need, &srcp0_ihdl);
 	if (len == 0) {
 		mutex_unlock(&mfd->dma->ov_mutex);
 		pr_err("%s: pmem Error\n", __func__);
@@ -2460,8 +2702,8 @@
 	if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) {
 		if (overlay_version > 0) {
 			img = &req->plane1_data;
-			get_img(img, info, &start, &len, &srcp1_file,
-				&srcp1_ihdl);
+			get_img(img, info, pipe, 1, &start, &len, &srcp1_file,
+				&p_need, &srcp1_ihdl);
 			if (len == 0) {
 				mutex_unlock(&mfd->dma->ov_mutex);
 				pr_err("%s: Error to get plane1\n", __func__);
@@ -2492,8 +2734,8 @@
 	} else if (pipe->fetch_plane == OVERLAY_PLANE_PLANAR) {
 		if (overlay_version > 0) {
 			img = &req->plane1_data;
-			get_img(img, info, &start, &len, &srcp1_file,
-				&srcp1_ihdl);
+			get_img(img, info, pipe, 1, &start, &len, &srcp1_file,
+				&p_need, &srcp1_ihdl);
 			if (len == 0) {
 				mutex_unlock(&mfd->dma->ov_mutex);
 				pr_err("%s: Error to get plane1\n", __func__);
@@ -2503,8 +2745,8 @@
 			pipe->srcp1_addr = start + img->offset;
 
 			img = &req->plane2_data;
-			get_img(img, info, &start, &len, &srcp2_file,
-				&srcp2_ihdl);
+			get_img(img, info, pipe, 2, &start, &len, &srcp2_file,
+				&p_need, &srcp2_ihdl);
 			if (len == 0) {
 				mutex_unlock(&mfd->dma->ov_mutex);
 				pr_err("%s: Error to get plane2\n", __func__);
@@ -2547,11 +2789,14 @@
 	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 {
 		if (pipe->flags & MDP_SHARPENING) {
-			pr_warn(
+			pr_debug(
 			"%s: Sharpening/Smoothing not supported on RGB pipe\n",
 								     __func__);
 			pipe->flags &= ~MDP_SHARPENING;
@@ -2572,21 +2817,30 @@
 	} 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_reg_flush(pipe, 0);
+			mdp4_overlay_dtv_start();
 			mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+			if (!mfd->use_ov1_blt)
+				mdp4_overlay1_update_blt_mode(mfd);
+		}
 	} else {
 
 		/* primary interface */
 		ctrl->mixer0_played++;
 		if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+			mdp4_overlay_reg_flush(pipe, 0);
 			if (!mfd->use_ov0_blt)
 				mdp4_overlay_update_blt_mode(mfd);
+			mdp4_overlay_lcdc_start();
 			mdp4_overlay_lcdc_vsync_push(mfd, pipe);
 		}
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+			mdp4_overlay_reg_flush(pipe, 0);
 			if (!mfd->use_ov0_blt)
 				mdp4_overlay_update_blt_mode(mfd);
+			mdp4_overlay_dsi_video_start();
 			mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
 		}
 #endif
@@ -2599,6 +2853,7 @@
 			}
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 			if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+				mdp4_iommu_attach();
 				mdp4_dsi_cmd_dma_busy_wait(mfd);
 				mdp4_dsi_cmd_kickoff_video(mfd, pipe);
 			}
@@ -2614,7 +2869,8 @@
 	/* write out DPP HSIC registers */
 	if (pipe->flags & MDP_DPP_HSIC)
 		mdp4_hsic_update(pipe);
-
+	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+		mdp4_iommu_unmap(pipe);
 	mdp4_stat.overlay_play[pipe->mixer_num]++;
 	mutex_unlock(&mfd->dma->ov_mutex);
 end:
@@ -2626,13 +2882,176 @@
 	if (srcp2_file)
 		put_pmem_file(srcp2_file);
 #endif
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	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))
-		ion_free(mfd->iclient, srcp2_ihdl);
-#endif
+	/* only source may use frame buffer */
+	if (img->flags & MDP_MEMORY_ID_TYPE_FB)
+		fput_light(srcp0_file, ps0_need);
 	return ret;
 }
+
+static struct {
+	char *name;
+	int  domain;
+} msm_iommu_ctx_names[] = {
+	/* Display */
+	{
+		.name = "mdp_vg1",
+		.domain = DISPLAY_DOMAIN,
+	},
+	/* Display */
+	{
+		.name = "mdp_vg2",
+		.domain = DISPLAY_DOMAIN,
+	},
+	/* Display */
+	{
+		.name = "mdp_rgb1",
+		.domain = DISPLAY_DOMAIN,
+	},
+	/* Display */
+	{
+		.name = "mdp_rgb2",
+		.domain = DISPLAY_DOMAIN,
+	},
+};
+
+void mdp4_iommu_attach(void)
+{
+	static int done;
+	struct iommu_domain *domain;
+	int i;
+
+	if (!done) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
+			int domain_idx;
+			struct device *ctx = msm_iommu_get_ctx(
+				msm_iommu_ctx_names[i].name);
+
+			if (!ctx)
+				continue;
+
+			domain_idx = msm_iommu_ctx_names[i].domain;
+
+			domain = msm_get_iommu_domain(domain_idx);
+			if (!domain)
+				continue;
+
+			if (iommu_attach_device(domain,	ctx)) {
+				WARN(1, "%s: could not attach domain %d to context %s."
+					" iommu programming will not occur.\n",
+					__func__, domain_idx,
+					msm_iommu_ctx_names[i].name);
+				continue;
+			}
+		}
+		done = 1;
+	}
+}
+
+int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
+	struct mdp4_overlay_pipe **ppipe)
+{
+	struct mdp4_overlay_pipe *pipe;
+	int err;
+	struct msm_fb_data_type *mfb = info->par;
+
+	req->z_order = 0;
+	req->id = MSMFB_NEW_REQUEST;
+	req->is_fg = false;
+	req->alpha = 0xff;
+	err = mdp4_overlay_req2pipe(req, MDP4_MIXER0, &pipe, mfb);
+	if (err < 0) {
+		pr_err("%s:Could not allocate MDP overlay pipe\n", __func__);
+		return err;
+	}
+
+	mdp4_mixer_blend_setup(pipe);
+	*ppipe = pipe;
+
+	return 0;
+}
+
+void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe)
+{
+	mdp4_mixer_stage_down(pipe);
+	mdp4_overlay_pipe_free(pipe);
+}
+
+int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
+	unsigned long srcp0_addr, unsigned long srcp1_addr,
+	unsigned long srcp2_addr)
+{
+	struct msm_fb_data_type *mfd = info->par;
+	int err;
+
+	if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
+		return -EINTR;
+
+	switch (pipe->src_format) {
+	case MDP_Y_CR_CB_H2V2:
+		/* YUV420 */
+		pipe->srcp0_addr = srcp0_addr;
+		pipe->srcp0_ystride = pipe->src_width;
+		/*
+		 * For YUV420, the luma plane is 1 byte per pixel times
+		 * num of pixels in the image Also, the planes are
+		 * switched in MDP, srcp2 is actually first chroma plane
+		 */
+		pipe->srcp2_addr = srcp1_addr ? srcp1_addr :
+		pipe->srcp0_addr + (pipe->src_width * pipe->src_height);
+		pipe->srcp2_ystride = pipe->src_width/2;
+		/*
+		 * The chroma planes are half the size of the luma
+		 * planes
+		 */
+		pipe->srcp1_addr = srcp2_addr ? srcp2_addr :
+		pipe->srcp2_addr +
+			(pipe->src_width * pipe->src_height / 4);
+		pipe->srcp1_ystride = pipe->src_width/2;
+		break;
+	case MDP_Y_CRCB_H2V2:
+		/* NV12 */
+		pipe->srcp0_addr = srcp0_addr;
+		pipe->srcp0_ystride = pipe->src_width;
+		pipe->srcp1_addr = srcp1_addr ? srcp1_addr :
+		pipe->srcp0_addr +
+			(pipe->src_width * pipe->src_height);
+		pipe->srcp1_ystride = pipe->src_width;
+		break;
+	default:
+		pr_err("%s: format (%u) is not supported\n", __func__,
+				pipe->src_format);
+		err = -EINVAL;
+		goto done;
+	}
+
+	pr_debug("%s: pipe ndx=%d stage=%d format=%x\n", __func__,
+		pipe->pipe_ndx, pipe->mixer_stage, pipe->src_format);
+
+	if (pipe->pipe_type == OVERLAY_TYPE_VIDEO)
+		mdp4_overlay_vg_setup(pipe);
+	else
+		mdp4_overlay_rgb_setup(pipe);
+
+	mdp4_mixer_stage_up(pipe);
+
+	if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+		mdp4_overlay_reg_flush(pipe, 1);
+		mdp4_overlay_lcdc_vsync_push(mfd, pipe);
+	} else {
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+		if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+			mdp4_dsi_cmd_dma_busy_wait(mfd);
+			mdp4_dsi_cmd_kickoff_video(mfd, pipe);
+		}
+#else
+		if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
+			mdp4_mddi_dma_busy_wait(mfd);
+			mdp4_mddi_kickoff_video(mfd, pipe);
+		}
+#endif
+	}
+done:
+	mutex_unlock(&mfd->dma->ov_mutex);
+	return err;
+}
+
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 0b707d7..dd827aa 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -37,17 +37,15 @@
 int mdp4_atv_on(struct platform_device *pdev)
 {
 	uint8 *buf;
+	unsigned int buf_offset;
 	int bpp, ptype;
-	int yres, remainder;
 	struct fb_info *fbi;
 	struct fb_var_screeninfo *var;
 	struct msm_fb_data_type *mfd;
 	struct mdp4_overlay_pipe *pipe;
-	struct msm_panel_info *panel_info;
 	int ret;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-	panel_info = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -58,28 +56,9 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf_offset = calc_fb_offset(mfd, fbi, bpp);
 
 	if (atv_pipe == NULL) {
 		ptype = mdp4_overlay_format2type(mfd->fb_imgType);
@@ -118,7 +97,15 @@
 	pipe->src_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
-	pipe->srcp0_addr = (uint32) buf;
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
+
 	pipe->srcp0_ystride = fbi->fix.line_length;
 
 	mdp4_overlay_dmae_xy(pipe);	/* dma_e */
@@ -130,6 +117,8 @@
 
 	mdp4_overlayproc_cfg(pipe);
 
+	mdp4_overlay_reg_flush(pipe, 1);
+
 	if (ret == 0)
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
@@ -151,8 +140,10 @@
 	msleep(100);
 
 	/* dis-engage rgb2 from mixer1 */
-	if (atv_pipe)
+	if (atv_pipe) {
 		mdp4_mixer_stage_down(atv_pipe);
+		mdp4_iommu_unmap(atv_pipe);
+	}
 
 	return ret;
 }
@@ -169,45 +160,33 @@
 {
 	struct fb_info *fbi = mfd->fbi;
 	uint8 *buf;
+	unsigned int buf_offset;
 	int bpp;
 	unsigned long flag;
-	int yres, remainder;
 	struct mdp4_overlay_pipe *pipe;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
 
 	if (!mfd->panel_power_on)
 		return;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	/* no need to power on cmd block since it's lcdc mode */
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf_offset = calc_fb_offset(mfd, fbi, bpp);
 
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = atv_pipe;
-	pipe->srcp0_addr = (uint32) buf;
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
 	mdp4_overlay_rgb_setup(pipe);
 	mdp4_mixer_stage_up(pipe);
+	mdp4_overlay_reg_flush(pipe, 0);
 
 	printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
 					(int)pipe, pipe->pipe_ndx);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index db07cb5..a5b4b3e 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -651,6 +651,15 @@
 	mdp4_stat.kickoff_ov0++;
 }
 
+void mdp_dsi_cmd_overlay_suspend(void)
+{
+	/* dis-engage rgb0 from mixer0 */
+	if (dsi_pipe) {
+		mdp4_mixer_stage_down(dsi_pipe);
+		mdp4_iommu_unmap(dsi_pipe);
+	}
+}
+
 void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd)
 {
 	mutex_lock(&mfd->dma->ov_mutex);
@@ -663,8 +672,9 @@
 
 		mdp4_overlay_update_dsi_cmd(mfd);
 
+		mdp4_iommu_attach();
 		mdp4_dsi_cmd_kickoff_ui(mfd, dsi_pipe);
-
+		mdp4_iommu_unmap(dsi_pipe);
 	/* signal if pan function is waiting for the update completion */
 		if (mfd->pan_waiting) {
 			mfd->pan_waiting = FALSE;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index a3be2af..f06f380 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -36,6 +36,7 @@
 
 static int first_pixel_start_x;
 static int first_pixel_start_y;
+static int dsi_video_enabled;
 
 static struct mdp4_overlay_pipe *dsi_pipe;
 static struct completion dsi_video_comp;
@@ -62,6 +63,9 @@
 	display_on = fxn;
 }
 
+static void mdp4_overlay_dsi_video_wait4event(struct msm_fb_data_type *mfd,
+						int intr_done);
+
 int mdp4_dsi_video_on(struct platform_device *pdev)
 {
 	int dsi_width;
@@ -95,17 +99,15 @@
 	int hsync_start_x;
 	int hsync_end_x;
 	uint8 *buf;
+	unsigned int buf_offset;
 	int bpp, ptype;
-	int yres, remainder;
 	struct fb_info *fbi;
 	struct fb_var_screeninfo *var;
 	struct msm_fb_data_type *mfd;
 	struct mdp4_overlay_pipe *pipe;
-	struct msm_panel_info *panel_info;
 	int ret;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-	panel_info = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -118,28 +120,9 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf_offset = calc_fb_offset(mfd, fbi, bpp);
 
 	if (dsi_pipe == NULL) {
 		ptype = mdp4_overlay_format2type(mfd->fb_imgType);
@@ -171,6 +154,17 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+	if (!(mfd->cont_splash_done)) {
+		mfd->cont_splash_done = 1;
+		mdp_pipe_ctrl(MDP_CMD_BLOCK,
+			      MDP_BLOCK_POWER_OFF, FALSE);
+		mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
+		/* disable timing generator */
+		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+		mipi_dsi_controller_cfg(0);
+	}
+
 	if (is_mdp4_hw_reset()) {
 		mdp4_hw_init();
 		outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
@@ -182,10 +176,18 @@
 	pipe->src_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
-	pipe->srcp0_addr = (uint32) buf;
 	pipe->srcp0_ystride = fbi->fix.line_length;
 	pipe->bpp = bpp;
 
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
+
 	pipe->dst_h = fbi->var.yres;
 	pipe->dst_w = fbi->var.xres;
 
@@ -271,14 +273,11 @@
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity);
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp_histogram_ctrl(TRUE);
 
 	ret = panel_next_on(pdev);
 	if (ret == 0) {
-		/* enable DSI block */
-		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1);
-		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-
 		if (display_on != NULL) {
 			msleep(50);
 			display_on(pdev);
@@ -297,6 +296,7 @@
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+	dsi_video_enabled = 0;
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -304,8 +304,10 @@
 	ret = panel_next_off(pdev);
 
 	/* dis-engage rgb0 from mixer0 */
-	if (dsi_pipe)
+	if (dsi_pipe) {
 		mdp4_mixer_stage_down(dsi_pipe);
+		mdp4_iommu_unmap(dsi_pipe);
+	}
 
 	return ret;
 }
@@ -316,9 +318,8 @@
 {
 	struct fb_info *fbi;
 	struct mdp4_overlay_pipe *pipe;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
+	unsigned int buf_offset;
 	int bpp;
-	int yres, remainder;
 	uint8 *buf = NULL;
 
 	if (dsi_pipe == NULL)
@@ -337,28 +338,9 @@
 
 	fbi = mfd->fbi;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf_offset = calc_fb_offset(mfd, fbi, bpp);
 
 	if (pipe->is_3d) {
 		pipe->src_height = pipe->src_height_3d;
@@ -384,7 +366,15 @@
 	pipe->src_x = 0;
 	pipe->dst_y = 0;
 	pipe->dst_x = 0;
-	pipe->srcp0_addr = (uint32)buf;
+
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
 
 	mdp4_overlay_rgb_setup(pipe);
 
@@ -502,6 +492,19 @@
 	pr_debug("%s: done pid=%d\n", __func__, current->pid);
 }
 
+void mdp4_overlay_dsi_video_start(void)
+{
+	if (!dsi_video_enabled) {
+		/* enable DSI block */
+		mdp4_iommu_attach();
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1);
+		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		dsi_video_enabled = 1;
+	}
+}
+
 void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe)
 {
@@ -688,44 +691,36 @@
 {
 	struct fb_info *fbi = mfd->fbi;
 	uint8 *buf;
+	unsigned int buf_offset;
 	int bpp;
-	int yres, remainder;
 	struct mdp4_overlay_pipe *pipe;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
 
 	if (!mfd->panel_power_on)
 		return;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	/* no need to power on cmd block since it's dsi video mode */
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf_offset = calc_fb_offset(mfd, fbi, bpp);
 
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = dsi_pipe;
-	pipe->srcp0_addr = (uint32) buf;
+
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
+
 	mdp4_overlay_rgb_setup(pipe);
 	mdp4_mixer_stage_up(pipe);
+	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_dsi_video_start();
 	mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
+	mdp4_iommu_unmap(pipe);
 	mutex_unlock(&mfd->dma->ov_mutex);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 590ad65..b94d1a4 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -51,8 +51,10 @@
 
 static int first_pixel_start_x;
 static int first_pixel_start_y;
+static int dtv_enabled;
 
 static struct mdp4_overlay_pipe *dtv_pipe;
+static DECLARE_COMPLETION(dtv_comp);
 
 static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
 {
@@ -102,12 +104,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);
 
 	/*
@@ -193,9 +195,6 @@
 	/* Test pattern 8 x 8 pixel */
 	/* MDP_OUTP(MDP_BASE + DTV_BASE + 0x4C, 0x80000808); */
 
-	/* enable DTV block */
-	MDP_OUTP(MDP_BASE + DTV_BASE, 1);
-	mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
@@ -210,6 +209,7 @@
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	MDP_OUTP(MDP_BASE + DTV_BASE, 0);
+	dtv_enabled = 0;
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -230,6 +230,7 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
+	mdp_footswitch_ctrl(TRUE);
 	mdp4_overlay_panel_mode(MDP4_MIXER1, MDP4_PANEL_DTV);
 
 	/* Allocate dtv_pipe at dtv_on*/
@@ -259,13 +260,21 @@
 
 	if (dtv_pipe != NULL) {
 		mdp4_mixer_stage_down(dtv_pipe);
+		/*
+		 * wait4vsync to make sure pipes are
+		 * dis-engaged from mixer1
+		 * before turn off timing generator
+		 */
+		mdp4_overlay_dtv_wait4vsync();
 		mdp4_dtv_stop(mfd);
 		mdp4_overlay_pipe_free(dtv_pipe);
+		mdp4_iommu_unmap(dtv_pipe);
 		dtv_pipe = NULL;
 	}
 	mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
 
 	ret = panel_next_off(pdev);
+	mdp_footswitch_ctrl(FALSE);
 
 	dev_info(&pdev->dev, "mdp4_overlay_dtv: off");
 	return ret;
@@ -301,7 +310,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 +321,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;
 		}
 	}
@@ -342,6 +350,7 @@
 	}
 
 	mdp4_mixer_stage_up(pipe);
+	mdp4_overlay_reg_flush(pipe, 1);
 
 	dtv_pipe = pipe; /* keep it */
 }
@@ -355,7 +364,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);
@@ -369,6 +378,13 @@
 {
 	int result = 0;
 
+	if (dtv_pipe == NULL)
+		return result;
+
+	pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+
 	if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE &&
 			pipe->pipe_type == OVERLAY_TYPE_RGB) {
 		result = mdp4_dtv_stop(mfd);
@@ -466,11 +482,23 @@
 	mdp_disable_irq(MDP_OVERLAY1_TERM);
 }
 
+void mdp4_overlay_dtv_start(void)
+{
+	if (!dtv_enabled) {
+		mdp4_iommu_attach();
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		/* enable DTV block */
+		MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		dtv_enabled = 1;
+	}
+}
+
 void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe)
 {
 	mdp4_overlay_dtv_ov_start(mfd);
-
 	if (pipe->flags & MDP_OV_PLAY_NOWAIT)
 		return;
 
@@ -494,7 +522,7 @@
 
 void mdp4_external_vsync_dtv()
 {
-	complete_all(&dtv_pipe->comp);
+	complete_all(&dtv_comp);
 }
 
 /*
@@ -509,7 +537,6 @@
 	complete_all(&dtv_pipe->comp);
 }
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 void mdp4_dtv_set_black_screen(void)
 {
 	char *rgb_base;
@@ -517,8 +544,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;
@@ -534,10 +562,28 @@
 	*/
 	temp_src_format = inpdw(rgb_base + 0x0050);
 	MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
-	mdp4_mixer_stage_up(dtv_pipe);
+	mdp4_overlay_reg_flush(dtv_pipe, 0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
-#endif
+
+void mdp4_overlay_dtv_wait4vsync(void)
+{
+	unsigned long flag;
+
+	if (!dtv_enabled)
+		return;
+
+	/* enable irq */
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	mdp_enable_irq(MDP_DMA_E_TERM);
+	INIT_COMPLETION(dtv_comp);
+	outp32(MDP_INTR_CLEAR, INTR_EXTERNAL_VSYNC);
+	mdp_intr_mask |= INTR_EXTERNAL_VSYNC;
+	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+	wait_for_completion_killable(&dtv_comp);
+	mdp_disable_irq(MDP_DMA_E_TERM);
+}
 
 static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
 {
@@ -593,20 +639,17 @@
 
 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);
 }
 
 void mdp4_dtv_overlay(struct msm_fb_data_type *mfd)
 {
 	struct mdp4_overlay_pipe *pipe;
-
 	if (!mfd->panel_power_on)
 		return;
 
@@ -617,6 +660,9 @@
 		mdp4_overlay_rgb_setup(pipe);
 	}
 	mdp4_mixer_stage_up(pipe);
+	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_dtv_start();
 	mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+	mdp4_iommu_unmap(pipe);
 	mutex_unlock(&mfd->dma->ov_mutex);
 }
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index ae498fc..ed4553d 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -41,6 +41,7 @@
 
 int first_pixel_start_x;
 int first_pixel_start_y;
+static int lcdc_enabled;
 
 static struct mdp4_overlay_pipe *lcdc_pipe;
 static struct completion lcdc_comp;
@@ -78,17 +79,15 @@
 	int hsync_start_x;
 	int hsync_end_x;
 	uint8 *buf;
+	unsigned int buf_offset;
 	int bpp, ptype;
 	struct fb_info *fbi;
 	struct fb_var_screeninfo *var;
 	struct msm_fb_data_type *mfd;
 	struct mdp4_overlay_pipe *pipe;
 	int ret;
-	int yres, remainder;
-	struct msm_panel_info *panel_info;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-	panel_info = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -101,17 +100,6 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	if (is_mdp4_hw_reset()) {
@@ -121,15 +109,7 @@
 
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf_offset = calc_fb_offset(mfd, fbi, bpp);
 
 	if (lcdc_pipe == NULL) {
 		ptype = mdp4_overlay_format2type(mfd->fb_imgType);
@@ -162,7 +142,15 @@
 	pipe->src_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
-	pipe->srcp0_addr = (uint32) buf;
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
+
 	pipe->srcp0_ystride = fbi->fix.line_length;
 	pipe->bpp = bpp;
 
@@ -254,17 +242,14 @@
 	MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start);
 	MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end);
 
+	mdp4_overlay_reg_flush(pipe, 1);
+
 #ifdef CONFIG_MSM_BUS_SCALING
 	mdp_bus_scale_update_request(2);
 #endif
 	mdp_histogram_ctrl(TRUE);
 
 	ret = panel_next_on(pdev);
-	if (ret == 0) {
-		/* enable LCDC block */
-		MDP_OUTP(MDP_BASE + LCDC_BASE, 1);
-		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	}
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
@@ -283,6 +268,7 @@
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
+	lcdc_enabled = 0;
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -296,8 +282,10 @@
 	msleep(16);
 
 	/* dis-engage rgb0 from mixer0 */
-	if (lcdc_pipe)
+	if (lcdc_pipe) {
 		mdp4_mixer_stage_down(lcdc_pipe);
+		mdp4_iommu_unmap(lcdc_pipe);
+	}
 
 #ifdef CONFIG_MSM_BUS_SCALING
 	mdp_bus_scale_update_request(0);
@@ -406,6 +394,19 @@
 	pr_debug("%s: done pid=%d\n", __func__, current->pid);
 }
 
+void mdp4_overlay_lcdc_start(void)
+{
+	if (!lcdc_enabled) {
+		/* enable LCDC block */
+		mdp4_iommu_attach();
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		MDP_OUTP(MDP_BASE + LCDC_BASE, 1);
+		mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		lcdc_enabled = 1;
+	}
+}
+
 void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe)
 {
@@ -572,44 +573,34 @@
 {
 	struct fb_info *fbi = mfd->fbi;
 	uint8 *buf;
+	unsigned int buf_offset;
 	int bpp;
-	int yres, remainder;
 	struct mdp4_overlay_pipe *pipe;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
 
 	if (!mfd->panel_power_on)
 		return;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	/* no need to power on cmd block since it's lcdc mode */
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf_offset = calc_fb_offset(mfd, fbi, bpp);
 
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = lcdc_pipe;
-	pipe->srcp0_addr = (uint32) buf;
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
 	mdp4_overlay_rgb_setup(pipe);
 	mdp4_mixer_stage_up(pipe);
+	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_lcdc_start();
 	mdp4_overlay_lcdc_vsync_push(mfd, pipe);
+	mdp4_iommu_unmap(pipe);
 	mutex_unlock(&mfd->dma->ov_mutex);
 }
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 7739837..f92fb43 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -141,6 +141,7 @@
 {
 	struct fb_info *fbi;
 	uint8 *buf;
+	unsigned int buf_offset;
 	struct mdp4_overlay_pipe *pipe;
 	int bpp;
 
@@ -156,7 +157,7 @@
 
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
-	buf += fbi->var.xoffset * bpp +
+	buf_offset = fbi->var.xoffset * bpp +
 		fbi->var.yoffset * fbi->fix.line_length;
 
 	/* MDP cmd block enable */
@@ -173,8 +174,15 @@
 	pipe->src_x = 0;
 	pipe->dst_y = 0;
 	pipe->dst_x = 0;
-	pipe->srcp0_addr = (uint32)buf;
 
+	if (mfd->map_buffer) {
+		pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \
+			buf_offset;
+		pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd->
+			map_buffer->iova[0], pipe->srcp0_addr);
+	} else {
+		pipe->srcp0_addr = (uint32)(buf + buf_offset);
+	}
 
 	mdp4_mixer_stage_up(pipe);
 
@@ -258,7 +266,9 @@
 	struct msmfb_writeback_data_list *node = NULL;
 	mutex_lock(&mfd->unregister_mutex);
 	mutex_lock(&mfd->writeback_mutex);
-	if (!list_empty(&mfd->writeback_free_queue)) {
+	if (!list_empty(&mfd->writeback_free_queue)
+		&& mfd->writeback_state != WB_STOPING
+		&& mfd->writeback_state != WB_STOP) {
 		node = list_first_entry(&mfd->writeback_free_queue,
 				struct msmfb_writeback_data_list, active_entry);
 	}
@@ -306,7 +316,9 @@
 
 	mutex_lock(&mfd->unregister_mutex);
 	mutex_lock(&mfd->writeback_mutex);
-	if (!list_empty(&mfd->writeback_free_queue)) {
+	if (!list_empty(&mfd->writeback_free_queue)
+		&& mfd->writeback_state != WB_STOPING
+		&& mfd->writeback_state != WB_STOP) {
 		node = list_first_entry(&mfd->writeback_free_queue,
 				struct msmfb_writeback_data_list, active_entry);
 	}
@@ -345,6 +357,7 @@
 		pr_debug("%s: in writeback pan display 0x%x\n", __func__,
 				(unsigned int)writeback_pipe->blt_addr);
 		mdp4_writeback_kickoff_ui(mfd, writeback_pipe);
+		mdp4_iommu_unmap(writeback_pipe);
 
 		/* signal if pan function is waiting for the
 		 * update completion */
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index d82672e..1f5904b 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -24,9 +24,11 @@
 #include <linux/debugfs.h>
 #include <linux/semaphore.h>
 #include <linux/uaccess.h>
+#include <linux/msm_mdp.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
+#include <mach/iommu_domains.h>
 #include "mdp.h"
 #include "msm_fb.h"
 #include "mdp4.h"
@@ -295,12 +297,6 @@
 	bits =  mdp_intr_mask;
 	outpdw(MDP_BASE + 0x0050, bits);/* enable specififed interrupts */
 
-	/* histogram */
-	MDP_OUTP(MDP_BASE + 0x95010, 1);	/* auto clear HIST */
-
-	/* enable histogram interrupts */
-	outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
-
 	/* For the max read pending cmd config below, if the MDP clock     */
 	/* is less than the AXI clock, then we must use 3 pending          */
 	/* pending requests.  Otherwise, we should use 8 pending requests. */
@@ -385,11 +381,8 @@
 		that histogram works.*/
 		MDP_OUTP(MDP_BASE + 0x95010, 1);
 		outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
-		if (mdp_is_hist_start == TRUE) {
-			MDP_OUTP(MDP_BASE + 0x95004,
-					mdp_hist_frame_cnt);
-			MDP_OUTP(MDP_BASE + 0x95000, 1);
-		}
+		mdp_is_hist_valid = FALSE;
+		__mdp_histogram_reset();
 	}
 
 	if (isr & INTR_EXTERNAL_INTF_UDERRUN)
@@ -568,16 +561,18 @@
 		outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr);
 		mb();
 		isr &= mask;
+		if (isr & INTR_HIST_RESET_SEQ_DONE)
+			__mdp_histogram_kickoff();
+
 		if (isr & INTR_HIST_DONE) {
-			if (waitqueue_active(&(mdp_hist_comp.wait))) {
-				complete(&mdp_hist_comp);
-			} else {
-				if (mdp_is_hist_start == TRUE) {
-					MDP_OUTP(MDP_BASE + 0x95004,
-							mdp_hist_frame_cnt);
-					MDP_OUTP(MDP_BASE + 0x95000, 1);
+			if (waitqueue_active(&mdp_hist_comp.wait)) {
+				if (!queue_work(mdp_hist_wq,
+						&mdp_histogram_worker)) {
+					pr_err("%s - can't queue hist_read\n",
+							__func__);
 				}
-			}
+			} else
+				__mdp_histogram_reset();
 		}
 	}
 
@@ -597,7 +592,7 @@
 };
 
 static uint32 vg_qseed_table1[] = {
-	0x76543210, 0xfedcba98
+	0x00000000, 0x20000000,
 };
 
 static uint32 vg_qseed_table2[] = {
@@ -2545,7 +2540,7 @@
 {
 	struct mdp_buf_type *buf;
 	ion_phys_addr_t	addr;
-	u32 len;
+	unsigned long len;
 
 	if (mix_num == MDP4_MIXER0)
 		buf = mfd->ov0_wb_buf;
@@ -2561,14 +2556,15 @@
 	}
 
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
-		pr_info("%s:%d ion based allocation\n", __func__, __LINE__);
-		buf->ihdl = ion_alloc(mfd->iclient, buf->size, 4,
-			(1 << mfd->mem_hid));
+		pr_info("%s:%d ion based allocation mfd->mem_hid 0x%x\n",
+			__func__, __LINE__, mfd->mem_hid);
+		buf->ihdl = ion_alloc(mfd->iclient, buf->size, SZ_4K,
+			mfd->mem_hid);
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
-			if (ion_phys(mfd->iclient, buf->ihdl,
-				&addr, &len)) {
-				pr_err("%s:%d: ion_phys map failed\n",
-					__func__, __LINE__);
+			if (ion_map_iommu(mfd->iclient, buf->ihdl,
+				DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, &addr,
+				&len, 0, 0)) {
+				pr_err("ion_map_iommu() failed\n");
 				return -ENOMEM;
 			}
 		} else {
@@ -2603,6 +2599,8 @@
 
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
+			ion_unmap_iommu(mfd->iclient, buf->ihdl,
+				DISPLAY_DOMAIN, GEN_POOL);
 			ion_free(mfd->iclient, buf->ihdl);
 			pr_debug("%s:%d free writeback imem\n", __func__,
 				__LINE__);
@@ -2617,3 +2615,573 @@
 	}
 	buf->phys_addr = 0;
 }
+
+static int mdp4_update_pcc_regs(uint32_t offset,
+				struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	int ret = -1;
+
+	if (offset && cfg_ptr) {
+
+		outpdw(offset, cfg_ptr->r.c);
+		outpdw(offset + 0x30, cfg_ptr->g.c);
+		outpdw(offset + 0x60, cfg_ptr->b.c);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.r);
+		outpdw(offset + 0x30, cfg_ptr->g.r);
+		outpdw(offset + 0x60, cfg_ptr->b.r);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.g);
+		outpdw(offset + 0x30, cfg_ptr->g.g);
+		outpdw(offset + 0x60, cfg_ptr->b.g);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.b);
+		outpdw(offset + 0x30, cfg_ptr->g.b);
+		outpdw(offset + 0x60, cfg_ptr->b.b);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.rr);
+		outpdw(offset + 0x30, cfg_ptr->g.rr);
+		outpdw(offset + 0x60, cfg_ptr->b.rr);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.gg);
+		outpdw(offset + 0x30, cfg_ptr->g.gg);
+		outpdw(offset + 0x60, cfg_ptr->b.gg);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.bb);
+		outpdw(offset + 0x30, cfg_ptr->g.bb);
+		outpdw(offset + 0x60, cfg_ptr->b.bb);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.rg);
+		outpdw(offset + 0x30, cfg_ptr->g.rg);
+		outpdw(offset + 0x60, cfg_ptr->b.rg);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.gb);
+		outpdw(offset + 0x30, cfg_ptr->g.gb);
+		outpdw(offset + 0x60, cfg_ptr->b.gb);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.rb);
+		outpdw(offset + 0x30, cfg_ptr->g.rb);
+		outpdw(offset + 0x60, cfg_ptr->b.rb);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.rgb_0);
+		outpdw(offset + 0x30, cfg_ptr->g.rgb_0);
+		outpdw(offset + 0x60, cfg_ptr->b.rgb_0);
+		offset += 4;
+
+		outpdw(offset, cfg_ptr->r.rgb_1);
+		outpdw(offset + 0x30, cfg_ptr->g.rgb_1);
+		outpdw(offset + 0x60, cfg_ptr->b.rgb_1);
+
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int mdp4_read_pcc_regs(uint32_t offset,
+				struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	int ret = -1;
+
+	if (offset && cfg_ptr) {
+		cfg_ptr->r.c = inpdw(offset);
+		cfg_ptr->g.c = inpdw(offset + 0x30);
+		cfg_ptr->b.c = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.r = inpdw(offset);
+		cfg_ptr->g.r = inpdw(offset + 0x30);
+		cfg_ptr->b.r = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.g = inpdw(offset);
+		cfg_ptr->g.g = inpdw(offset + 0x30);
+		cfg_ptr->b.g = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.b = inpdw(offset);
+		cfg_ptr->g.b = inpdw(offset + 0x30);
+		cfg_ptr->b.b = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.rr = inpdw(offset);
+		cfg_ptr->g.rr = inpdw(offset + 0x30);
+		cfg_ptr->b.rr = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.gg = inpdw(offset);
+		cfg_ptr->g.gg = inpdw(offset + 0x30);
+		cfg_ptr->b.gg = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.bb = inpdw(offset);
+		cfg_ptr->g.bb = inpdw(offset + 0x30);
+		cfg_ptr->b.bb = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.rg = inpdw(offset);
+		cfg_ptr->g.rg = inpdw(offset + 0x30);
+		cfg_ptr->b.rg = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.gb = inpdw(offset);
+		cfg_ptr->g.gb = inpdw(offset + 0x30);
+		cfg_ptr->b.gb = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.rb = inpdw(offset);
+		cfg_ptr->g.rb = inpdw(offset + 0x30);
+		cfg_ptr->b.rb = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.rgb_0 = inpdw(offset);
+		cfg_ptr->g.rgb_0 = inpdw(offset + 0x30);
+		cfg_ptr->b.rgb_0 = inpdw(offset + 0x60);
+		offset += 4;
+
+		cfg_ptr->r.rgb_1 = inpdw(offset);
+		cfg_ptr->g.rgb_1 = inpdw(offset + 0x30);
+		cfg_ptr->b.rgb_1 = inpdw(offset + 0x60);
+
+		ret = 0;
+	}
+
+	return ret;
+}
+
+
+#define MDP_PCC_OFFSET 0xA000
+#define MDP_DMA_GC_OFFSET 0x8800
+#define MDP_LM_0_GC_OFFSET 0x4800
+#define MDP_LM_1_GC_OFFSET 0x4880
+
+
+#define MDP_DMA_P_OP_MODE_OFFSET 0x70
+#define MDP_DMA_S_OP_MODE_OFFSET 0x28
+#define MDP_LM_OP_MODE_OFFSET 0x10
+
+#define DMA_PCC_R2_OFFSET 0x100
+
+#define MDP_GC_COLOR_OFFSET	0x100
+#define MDP_GC_PARMS_OFFSET	0x80
+
+#define MDP_AR_GC_MAX_STAGES	16
+
+static uint32_t mdp_pp_block2pcc(uint32_t block)
+{
+	uint32_t valid = 0;
+
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		valid = (mdp_rev >= MDP_REV_42) ? 1 : 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return valid;
+}
+
+int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	int ret = -1;
+	uint32_t pcc_offset = 0, mdp_cfg_offset = 0;
+	uint32_t mdp_dma_op_mode = 0;
+	uint32_t blockbase;
+
+	if (!mdp_pp_block2pcc(cfg_ptr->block))
+		return ret;
+
+	blockbase = mdp_block2base(cfg_ptr->block);
+	if (!blockbase)
+		return ret;
+
+	blockbase += (uint32_t) MDP_BASE;
+
+	switch (cfg_ptr->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		pcc_offset = blockbase + MDP_PCC_OFFSET;
+		mdp_cfg_offset = blockbase;
+		mdp_dma_op_mode = blockbase +
+			(MDP_BLOCK_DMA_P == cfg_ptr->block ?
+			 MDP_DMA_P_OP_MODE_OFFSET
+			 : MDP_DMA_S_OP_MODE_OFFSET);
+		break;
+
+	default:
+		break;
+	}
+
+	if (0x8 & cfg_ptr->ops)
+		pcc_offset += DMA_PCC_R2_OFFSET;
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+	switch ((0x6 & cfg_ptr->ops)>>1) {
+	case 0x1:
+		ret = mdp4_read_pcc_regs(pcc_offset, cfg_ptr);
+		break;
+
+	case 0x2:
+		ret = mdp4_update_pcc_regs(pcc_offset, cfg_ptr);
+		break;
+
+	default:
+		break;
+	}
+
+	if (0x8 & cfg_ptr->ops)
+		outpdw(mdp_dma_op_mode,
+			(inpdw(mdp_dma_op_mode)|((0x8&cfg_ptr->ops)<<10)));
+
+	outpdw(mdp_cfg_offset,
+			(inpdw(mdp_cfg_offset)|((cfg_ptr->ops&0x1)<<29)));
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return ret;
+}
+
+static uint32_t mdp_pp_block2argc(uint32_t block)
+{
+	uint32_t valid = 0;
+
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+	case MDP_BLOCK_OVERLAY_0:
+	case MDP_BLOCK_OVERLAY_1:
+		valid = (mdp_rev >= MDP_REV_42) ? 1 : 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return valid;
+}
+
+static int update_ar_gc_lut(uint32_t *offset, struct mdp_pgc_lut_data *lut_data)
+{
+	int count = 0;
+
+	uint32_t *c0_offset = offset;
+	uint32_t *c0_params_offset = (uint32_t *)((uint32_t)c0_offset
+							+ MDP_GC_PARMS_OFFSET);
+
+	uint32_t *c1_offset = (uint32_t *)((uint32_t)offset
+							+ MDP_GC_COLOR_OFFSET);
+
+	uint32_t *c1_params_offset = (uint32_t *)((uint32_t)c1_offset
+							+ MDP_GC_PARMS_OFFSET);
+
+	uint32_t *c2_offset = (uint32_t *)((uint32_t)offset
+						+ 2*MDP_GC_COLOR_OFFSET);
+
+	uint32_t *c2_params_offset = (uint32_t *)((uint32_t)c2_offset
+						+MDP_GC_PARMS_OFFSET);
+
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (count = 0; count < MDP_AR_GC_MAX_STAGES; count++) {
+		if (count < lut_data->num_r_stages) {
+			outpdw(c0_offset+count,
+				((0xfff & lut_data->r_data[count].x_start)
+					| 0x10000));
+
+			outpdw(c0_params_offset+count,
+				((0x7fff & lut_data->r_data[count].slope)
+					| ((0xffff
+					& lut_data->r_data[count].offset)
+						<< 16)));
+		} else
+			outpdw(c0_offset+count, 0);
+
+		if (count < lut_data->num_b_stages) {
+			outpdw(c1_offset+count,
+				((0xfff & lut_data->b_data[count].x_start)
+					| 0x10000));
+
+			outpdw(c1_params_offset+count,
+				((0x7fff & lut_data->b_data[count].slope)
+					| ((0xffff
+					& lut_data->b_data[count].offset)
+						<< 16)));
+		} else
+			outpdw(c1_offset+count, 0);
+
+		if (count < lut_data->num_g_stages) {
+			outpdw(c2_offset+count,
+				((0xfff & lut_data->g_data[count].x_start)
+					| 0x10000));
+
+			outpdw(c2_params_offset+count,
+				((0x7fff & lut_data->g_data[count].slope)
+				| ((0xffff
+				& lut_data->g_data[count].offset)
+					<< 16)));
+		} else
+			outpdw(c2_offset+count, 0);
+	}
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return 0;
+}
+
+static int mdp4_argc_process_write_req(uint32_t *offset,
+		struct mdp_pgc_lut_data *pgc_ptr)
+{
+	int ret = -1;
+	struct mdp_ar_gc_lut_data r[MDP_AR_GC_MAX_STAGES];
+	struct mdp_ar_gc_lut_data g[MDP_AR_GC_MAX_STAGES];
+	struct mdp_ar_gc_lut_data b[MDP_AR_GC_MAX_STAGES];
+
+	ret = copy_from_user(&r[0], pgc_ptr->r_data,
+		pgc_ptr->num_r_stages * sizeof(struct mdp_ar_gc_lut_data));
+
+	if (!ret) {
+		ret = copy_from_user(&g[0],
+				pgc_ptr->g_data,
+				pgc_ptr->num_g_stages
+				* sizeof(struct mdp_ar_gc_lut_data));
+		if (!ret)
+			ret = copy_from_user(&b[0],
+					pgc_ptr->b_data,
+					pgc_ptr->num_b_stages
+					* sizeof(struct mdp_ar_gc_lut_data));
+	}
+
+	if (ret)
+		return ret;
+
+	pgc_ptr->r_data = &r[0];
+	pgc_ptr->g_data = &g[0];
+	pgc_ptr->b_data = &b[0];
+
+	ret = update_ar_gc_lut(offset, pgc_ptr);
+	return ret;
+}
+
+int mdp4_argc_cfg(struct mdp_pgc_lut_data *pgc_ptr)
+{
+	int ret = -1;
+	uint32_t *offset = 0, *pgc_enable_offset = 0, lshift_bits = 0;
+	uint32_t blockbase;
+
+	if (!mdp_pp_block2argc(pgc_ptr->block))
+		return ret;
+
+	blockbase = mdp_block2base(pgc_ptr->block);
+	if (!blockbase)
+		return ret;
+
+	blockbase += (uint32_t) MDP_BASE;
+	ret = 0;
+
+	switch (pgc_ptr->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		offset = (uint32_t *)(blockbase + MDP_DMA_GC_OFFSET);
+		pgc_enable_offset = (uint32_t *) blockbase;
+		lshift_bits = 28;
+		break;
+
+	case MDP_BLOCK_OVERLAY_0:
+	case MDP_BLOCK_OVERLAY_1:
+		offset = (uint32_t *)(blockbase +
+				(MDP_BLOCK_OVERLAY_0 == pgc_ptr->block ?
+				 MDP_LM_0_GC_OFFSET
+				 : MDP_LM_1_GC_OFFSET));
+
+		pgc_enable_offset = (uint32_t *)(blockbase
+				+ MDP_LM_OP_MODE_OFFSET);
+		lshift_bits = 2;
+		break;
+
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (!ret) {
+
+		switch ((0x6 & pgc_ptr->flags)>>1) {
+		case 0x1:
+			ret = -ENOTTY;
+			break;
+
+		case 0x2:
+			ret = mdp4_argc_process_write_req(offset, pgc_ptr);
+			break;
+
+		default:
+			break;
+		}
+
+		if (!ret) {
+			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+			outpdw(pgc_enable_offset, (inpdw(pgc_enable_offset) |
+				((0x1 & pgc_ptr->flags) << lshift_bits)));
+			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
+									FALSE);
+		}
+	}
+
+	return ret;
+}
+
+static uint32_t mdp4_pp_block2igc(uint32_t block)
+{
+	uint32_t valid = 0;
+	switch (block) {
+	case MDP_BLOCK_VG_1:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_VG_2:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_RGB_1:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_RGB_2:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_DMA_P:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_DMA_S:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	default:
+		break;
+	}
+	return valid;
+}
+
+static int mdp4_igc_lut_write(struct mdp_igc_lut_data *cfg, uint32_t en_off,
+		uint32_t lut_off)
+{
+	int i;
+	uint32_t base, *off_low, *off_high;
+	uint32_t low[cfg->len];
+	uint32_t high[cfg->len];
+
+	base = mdp_block2base(cfg->block);
+
+	if (cfg->len != 256)
+		return -EINVAL;
+
+	off_low = (uint32_t *)(MDP_BASE + base + lut_off);
+	off_high = (uint32_t *)(MDP_BASE + base + lut_off + 0x800);
+	if (copy_from_user(&low, cfg->c0_c1_data, cfg->len * sizeof(uint32_t)))
+		return -EFAULT;
+	if (copy_from_user(&high, cfg->c2_data, cfg->len * sizeof(uint32_t)))
+		return -EFAULT;
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < cfg->len; i++) {
+		MDP_OUTP(off_low++, low[i]);
+		/*low address write should occur before high address write*/
+		wmb();
+		MDP_OUTP(off_high++, high[i]);
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	return 0;
+}
+
+static int mdp4_igc_lut_ctrl(struct mdp_igc_lut_data *cfg)
+{
+	uint32_t mask, out;
+	uint32_t base = mdp_block2base(cfg->block);
+	int8_t shift = 0;
+
+	switch (cfg->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		base = base;
+		shift = 30;
+		break;
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+	case MDP_BLOCK_RGB_1:
+	case MDP_BLOCK_RGB_2:
+		base += 0x58;
+		shift = 16;
+		break;
+	default:
+		return -EINVAL;
+
+	}
+	out = 1<<shift;
+	mask = ~out;
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	out = inpdw(MDP_BASE + base) & mask;
+	MDP_OUTP(MDP_BASE + base, out | ((cfg->ops & 0x1)<<shift));
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return 0;
+}
+
+static int mdp4_igc_lut_write_cfg(struct mdp_igc_lut_data *cfg)
+{
+	int ret = 0;
+
+	switch (cfg->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		ret = mdp4_igc_lut_write(cfg, 0x00, 0x9000);
+		break;
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+	case MDP_BLOCK_RGB_1:
+	case MDP_BLOCK_RGB_2:
+		ret = mdp4_igc_lut_write(cfg, 0x58, 0x5000);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg)
+{
+	int ret = 0;
+
+	if (!mdp4_pp_block2igc(cfg->block)) {
+		ret = -ENOTTY;
+		goto error;
+	}
+
+	switch ((cfg->ops & 0x6) >> 1) {
+	case 0x1:
+		pr_info("%s: IGC LUT read not supported\n", __func__);
+		break;
+	case 0x2:
+		ret = mdp4_igc_lut_write_cfg(cfg);
+		if (ret)
+			goto error;
+		break;
+	default:
+		break;
+	}
+
+	ret = mdp4_igc_lut_ctrl(cfg);
+
+error:
+	return ret;
+}
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index e8b288f..32856ef 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -523,36 +523,18 @@
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct fb_info *fbi = mfd->fbi;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
 	MDPIBUF *iBuf;
 	int bpp = info->var.bits_per_pixel / 8;
-	int yres, remainder;
-
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
 
 	down(&mfd->sem);
 
 	iBuf = &mfd->ibuf;
-	iBuf->buf = (uint8 *) info->fix.smem_start;
+	if (mfd->map_buffer)
+		iBuf->buf = (uint8 *)mfd->map_buffer->iova[0];
+	else
+		iBuf->buf = (uint8 *) info->fix.smem_start;
 
-	if (fbi->var.yoffset < yres) {
-		iBuf->buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		iBuf->buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		iBuf->buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	iBuf->buf += calc_fb_offset(mfd, fbi, bpp);
 
 	iBuf->ibuf_width = info->var.xres_virtual;
 	iBuf->bpp = bpp;
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 0e76a07..e1d7acc 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -67,17 +67,15 @@
 	int hsync_end_x;
 	uint8 *buf;
 	uint32 dma2_cfg_reg;
-	int yres, remainder;
 
 	int bpp;
 	struct fb_info *fbi;
 	struct fb_var_screeninfo *var;
 	struct msm_fb_data_type *mfd;
-	struct msm_panel_info *panel_info;
 	int ret;
+	uint32 mask, curr;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-	panel_info = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -88,29 +86,10 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf += calc_fb_offset(mfd, fbi, bpp);
 
 	dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_OUT_SEL_DSI_VIDEO;
 
@@ -163,6 +142,9 @@
 	MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x10, 0);
 
 	/* dma config */
+	curr = inpdw(MDP_BASE + 0x90000);
+	mask = 0xBFFFFFFF;
+	dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
 	MDP_OUTP(MDP_BASE + DMA_P_BASE, dma2_cfg_reg);
 
 	/*
@@ -261,38 +243,18 @@
 	uint8 *buf;
 	int bpp;
 	unsigned long flag;
-	int yres, remainder;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
 	int irq_block = MDP_DMA2_TERM;
 
 	if (!mfd->panel_power_on)
 		return;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	down(&mfd->dma->mutex);
 
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf += calc_fb_offset(mfd, fbi, bpp);
+
 	/* no need to power on cmd block since it's dsi mode */
 	/* starting address */
 	MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x8, (uint32) buf);
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index 5dada35..7350d91 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -89,15 +89,12 @@
 	struct fb_info *fbi;
 	struct fb_var_screeninfo *var;
 	struct msm_fb_data_type *mfd;
-	struct msm_panel_info *panel_info;
 	uint32 dma_base;
 	uint32 timer_base = LCDC_BASE;
 	uint32 block = MDP_DMA2_BLOCK;
 	int ret;
-	int yres, remainder;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-	panel_info = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -108,32 +105,13 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf += calc_fb_offset(mfd, fbi, bpp);
 
 	dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_OUT_SEL_LCDC;
 
@@ -342,28 +320,15 @@
 void mdp_lcdc_update(struct msm_fb_data_type *mfd)
 {
 	struct fb_info *fbi = mfd->fbi;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
 	uint8 *buf;
 	int bpp;
 	unsigned long flag;
 	uint32 dma_base;
-	int yres, remainder;
 	int irq_block = MDP_DMA2_TERM;
 #ifdef CONFIG_FB_MSM_MDP40
 	int intr = INTR_DMA_P_DONE;
 #endif
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	if (!mfd->panel_power_on)
 		return;
 
@@ -372,15 +337,7 @@
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf += calc_fb_offset(mfd, fbi, bpp);
 
 	dma_base = DMA_P_BASE;
 
diff --git a/drivers/video/msm/mdp_dma_tv.c b/drivers/video/msm/mdp_dma_tv.c
index 1305e03..b578ba2 100644
--- a/drivers/video/msm/mdp_dma_tv.c
+++ b/drivers/video/msm/mdp_dma_tv.c
@@ -39,15 +39,12 @@
 int mdp_dma3_on(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
-	struct msm_panel_info *panel_info;
 	struct fb_info *fbi;
 	uint8 *buf;
 	int bpp;
 	int ret = 0;
-	int yres, remainder;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-	panel_info = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -57,32 +54,13 @@
 
 	fbi = mfd->fbi;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf += calc_fb_offset(mfd, fbi, bpp);
 
 	/* starting address[31..8] of Video frame buffer is CS0 */
 	MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
@@ -135,36 +113,15 @@
 	uint8 *buf;
 	int bpp;
 	unsigned long flag;
-	int yres, remainder;
-	struct msm_panel_info *panel_info = &mfd->panel_info;
 
 	if (!mfd->panel_power_on)
 		return;
 
-	if (panel_info->mode2_yres != 0) {
-		yres = panel_info->mode2_yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	} else {
-		yres = panel_info->yres;
-		remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
-	}
-
-	if (!remainder)
-		remainder = PAGE_SIZE;
-
 	/* no need to power on cmd block since dma3 is running */
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
-	if (fbi->var.yoffset < yres) {
-		buf += fbi->var.xoffset * bpp;
-	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
-		buf += fbi->var.xoffset * bpp + yres *
-		fbi->fix.line_length + PAGE_SIZE - remainder;
-	} else {
-		buf += fbi->var.xoffset * bpp + 2 * yres *
-		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
-	}
+	buf += calc_fb_offset(mfd, fbi, bpp);
 
 	MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
 
diff --git a/drivers/video/msm/mdp_hw_init.c b/drivers/video/msm/mdp_hw_init.c
index 8f8b4d3..ff3ad41 100644
--- a/drivers/video/msm/mdp_hw_init.c
+++ b/drivers/video/msm/mdp_hw_init.c
@@ -635,8 +635,6 @@
 	MDP_OUTP(MDP_BASE + 0xE0000, 0);
 	MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
 	MDP_OUTP(MDP_BASE + 0x90070, 0);
-	MDP_OUTP(MDP_BASE + 0x94010, 1);
-	MDP_OUTP(MDP_BASE + 0x9401c, 2);
 #endif
 
 	/*
diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c
index 199e472..4009ffc 100644
--- a/drivers/video/msm/mdp_ppp.c
+++ b/drivers/video/msm/mdp_ppp.c
@@ -1314,39 +1314,21 @@
 }
 
 
-int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req)
+static int mdp_ppp_blit_addr(struct fb_info *info, struct mdp_blit_req *req,
+	unsigned long srcp0_start, unsigned long srcp0_len,
+	unsigned long srcp1_start, unsigned long srcp1_len,
+	unsigned long dst_start, unsigned long dst_len,
+	struct file *p_src_file, struct file *p_dst_file)
 {
-	unsigned long src_start, dst_start;
-	unsigned long src_len = 0;
-	unsigned long dst_len = 0;
 	MDPIBUF iBuf;
 	u32 dst_width, dst_height;
-	struct file *p_src_file = 0 , *p_dst_file = 0;
-	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct msm_fb_data_type *mfd = info->par;
 
 	if (req->dst.format == MDP_FB_FORMAT)
 		req->dst.format =  mfd->fb_imgType;
 	if (req->src.format == MDP_FB_FORMAT)
 		req->src.format = mfd->fb_imgType;
-	if (req->flags & MDP_BLIT_SRC_GEM)
-		get_gem_img(&req->src, &src_start, &src_len);
-	else
-		get_img(&req->src, info, &src_start, &src_len, &p_src_file);
-	if (src_len == 0) {
-		printk(KERN_ERR "mdp_ppp: could not retrieve image from "
-		       "memory\n");
-		return -1;
-	}
-	if (req->flags & MDP_BLIT_DST_GEM)
-		get_gem_img(&req->dst, &dst_start, &dst_len);
-	else
-		get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file);
-	if (dst_len == 0) {
-		put_img(p_src_file);
-		printk(KERN_ERR "mdp_ppp: could not retrieve image from "
-		       "memory\n");
-		return -1;
-	}
+
 	if (mdp_ppp_verify_req(req)) {
 		printk(KERN_ERR "mdp_ppp: invalid image!\n");
 		put_img(p_src_file);
@@ -1375,17 +1357,17 @@
 	iBuf.mdpImg.width = req->src.width;
 	iBuf.mdpImg.imgType = req->src.format;
 
-	iBuf.mdpImg.bmy_addr = (uint32 *) (src_start + req->src.offset);
 
+	iBuf.mdpImg.bmy_addr = (uint32 *) (srcp0_start + req->src.offset);
 	if (iBuf.mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO)
 		iBuf.mdpImg.cbcr_addr =
 			(uint32 *) ((uint32) iBuf.mdpImg.bmy_addr +
 				ALIGN((ALIGN(req->src.width, 32) *
 				ALIGN(req->src.height, 32)), 4096));
 	else
-		iBuf.mdpImg.cbcr_addr =
+		iBuf.mdpImg.cbcr_addr = srcp1_start ? (uint32 *)srcp1_start :
 			(uint32 *) ((uint32) iBuf.mdpImg.bmy_addr +
-				req->src.width * req->src.height);
+			req->src.width * req->src.height);
 
 	iBuf.mdpImg.mdpOp = MDPOP_NOP;
 
@@ -1417,7 +1399,7 @@
 		iBuf.mdpImg.mdpOp |= MDPOP_DITHER;
 
 	if (req->flags & MDP_BLEND_FG_PREMULT) {
-#ifdef CONFIG_FB_MSM_MDP31
+#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP303)
 		iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA;
 #else
 		put_img(p_src_file);
@@ -1589,3 +1571,116 @@
 	put_img(p_dst_file);
 	return 0;
 }
+
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req)
+{
+	unsigned long src_start, dst_start;
+	unsigned long src_len = 0;
+	unsigned long dst_len = 0;
+	struct file *p_src_file = 0 , *p_dst_file = 0;
+
+	if (req->flags & MDP_BLIT_SRC_GEM)
+		get_gem_img(&req->src, &src_start, &src_len);
+	else
+		get_img(&req->src, info, &src_start, &src_len, &p_src_file);
+	if (src_len == 0) {
+		printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+		       "memory\n");
+		return -EINVAL;
+	}
+	if (req->flags & MDP_BLIT_DST_GEM)
+		get_gem_img(&req->dst, &dst_start, &dst_len);
+	else
+		get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file);
+	if (dst_len == 0) {
+		put_img(p_src_file);
+		printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+		       "memory\n");
+		return -EINVAL;
+	}
+
+	return mdp_ppp_blit_addr(info, req, src_start, src_len, 0, 0, dst_start,
+		dst_len, p_src_file, p_dst_file);
+}
+
+static struct mdp_blit_req overlay_req;
+static bool mdp_overlay_req_set;
+
+int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req)
+{
+	memset(&overlay_req, 0, sizeof(struct mdp_blit_req));
+
+	overlay_req.src.width  = req->src.width;
+	overlay_req.src.height = req->src.height;
+	overlay_req.src.format = req->src.format;
+
+
+	overlay_req.dst.width  = req->dst_rect.w;
+	overlay_req.dst.height = req->dst_rect.h;
+	overlay_req.dst.format = MDP_FB_FORMAT;
+	overlay_req.transp_mask = req->transp_mask;
+	overlay_req.flags = req->flags;
+	overlay_req.alpha = req->alpha;
+
+	overlay_req.src_rect.x = req->src_rect.x;
+	overlay_req.src_rect.y = req->src_rect.y;
+	overlay_req.src_rect.w = req->src_rect.w;
+	overlay_req.src_rect.h = req->src_rect.h;
+	overlay_req.dst_rect.x = req->dst_rect.x;
+	overlay_req.dst_rect.y = req->dst_rect.y;
+	overlay_req.dst_rect.w = req->dst_rect.w;
+	overlay_req.dst_rect.h = req->dst_rect.h;
+	mdp_overlay_req_set = true;
+
+	pr_debug("%s: Overlay parameters:", __func__);
+	pr_debug("Src_Image (%u %u)\n", overlay_req.src.width,
+	overlay_req.src.height);
+
+	if (overlay_req.src.format == MDP_Y_CRCB_H2V2)
+		pr_debug("Overlay format MDP_Y_CRCB_H2V2\n");
+	else if (overlay_req.src.format == MDP_RGB_565)
+		pr_debug("Overlay format MDP_RGB_565\n");
+	else
+		pr_debug("Overlay format(%u) unknown\n",
+		overlay_req.src.format);
+
+	pr_debug("Dst_Image (%u %u)\n", overlay_req.dst.width,
+		overlay_req.dst.height);
+	pr_debug("Src rect: (%u,%u,%u,%u), Dst rect: (%u,%u,%u,%u)\n",
+		overlay_req.src_rect.x, overlay_req.src_rect.y,
+		overlay_req.src_rect.w, overlay_req.src_rect.h,
+		overlay_req.dst_rect.x, overlay_req.dst_rect.y,
+		overlay_req.dst_rect.w, overlay_req.dst_rect.h);
+	return 0;
+}
+
+int mdp_ppp_v4l2_overlay_clear(void)
+{
+	memset(&overlay_req, 0, sizeof(struct mdp_overlay));
+	mdp_overlay_req_set = false;
+	return 0;
+}
+
+int mdp_ppp_v4l2_overlay_play(struct fb_info *info,
+	unsigned long srcp0_addr, unsigned long srcp0_size,
+	unsigned long srcp1_addr, unsigned long srcp1_size)
+{
+	int ret;
+
+	if (!mdp_overlay_req_set) {
+		pr_err("mdp_ppp:v4l2:No overlay set, ignore play req\n");
+		return -EINVAL;
+	}
+
+	overlay_req.dst.width = info->var.xres;
+	overlay_req.dst.height = info->var.yres;
+
+	ret = mdp_ppp_blit_addr(info, &overlay_req,
+		srcp0_addr, srcp0_size, srcp1_addr, srcp1_size,
+		info->fix.smem_start, info->fix.smem_len, NULL, NULL);
+
+	if (ret)
+		pr_err("%s:Blitting overlay failed(%d)\n", __func__, ret);
+
+	return ret;
+}
diff --git a/drivers/video/msm/mdp_ppp_v20.c b/drivers/video/msm/mdp_ppp_v20.c
index e2a6564..fe237ee 100644
--- a/drivers/video/msm/mdp_ppp_v20.c
+++ b/drivers/video/msm/mdp_ppp_v20.c
@@ -2177,26 +2177,8 @@
 			*pppop_reg_ptr |=
 			    (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
 
-		/* let's use SHIM logic to calculate the partial ROI scaling */
-#if 0
-			phasex_step =
-			    (uint32) mdp_do_div(0x20000000 * iBuf->roi.width,
-						dst_roi_width_scale);
-			phasey_step =
-			    (uint32) mdp_do_div(0x20000000 * iBuf->roi.height,
-						dst_roi_height_scale);
-
-/*
-    phasex_step= ((long long) iBuf->roi.width * 0x20000000)/dst_roi_width_scale;
-    phasey_step= ((long long)iBuf->roi.height * 0x20000000)/dst_roi_height_scale;
-*/
-
-			phasex_init =
-			    (((long long)phasex_step - 0x20000000) >> 1);
-			phasey_init =
-			    (((long long)phasey_step - 0x20000000) >> 1);
-
-#else
+			/* let's use SHIM logic to calculate the
+			   partial ROI scaling */
 			mdp_calc_scale_params(iBuf->roi.x, iBuf->roi.width,
 					      dst_roi_width_scale, 1,
 					      &phasex_init, &phasex_step,
@@ -2205,7 +2187,6 @@
 					      dst_roi_height_scale, 0,
 					      &phasey_init, &phasey_step,
 					      &dummy, &dummy);
-#endif
 			MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c,
 				 phasex_init);
 			MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140,
@@ -2448,37 +2429,102 @@
 			uint32 *tpVal,
 			uint32 perPixelAlpha, uint32 *pppop_reg_ptr)
 {
-	if (perPixelAlpha) {
-		*pppop_reg_ptr |= PPP_OP_ROT_ON |
-		    PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
+	if (mdp_rev == MDP_REV_303) {
+		int bg_alpha;
+
+		*alpha = iBuf->mdpImg.alpha;
+		*tpVal = iBuf->mdpImg.tpVal;
+
+		if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) {
+			if (perPixelAlpha) {
+				*pppop_reg_ptr |= PPP_OP_ROT_ON |
+						  PPP_OP_BLEND_ON |
+						  PPP_OP_BLEND_CONSTANT_ALPHA;
+			} else {
+				if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+					&& (iBuf->mdpImg.alpha == 0xff)) {
+					iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
+				}
+
+				if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+				   || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+
+					*pppop_reg_ptr |= PPP_OP_ROT_ON |
+						PPP_OP_BLEND_ON |
+						PPP_OP_BLEND_CONSTANT_ALPHA |
+						PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+				}
+			}
+
+			bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
+				PPP_BLEND_BG_ALPHA_REVERSE;
+
+			if (perPixelAlpha) {
+				bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
+			} else {
+				bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
+				bg_alpha |= iBuf->mdpImg.alpha << 24;
+			}
+			outpdw(MDP_BASE + 0x70010, bg_alpha);
+
+			if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
+				*pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
+		} else if (perPixelAlpha) {
+				*pppop_reg_ptr |= PPP_OP_ROT_ON |
+						  PPP_OP_BLEND_ON |
+						  PPP_OP_BLEND_SRCPIXEL_ALPHA;
+			} else {
+				if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+					&& (iBuf->mdpImg.alpha == 0xff)) {
+						iBuf->mdpImg.mdpOp &=
+							~(MDPOP_ALPHAB);
+				}
+
+				if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+				   || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+					*pppop_reg_ptr |= PPP_OP_ROT_ON |
+						PPP_OP_BLEND_ON |
+						PPP_OP_BLEND_CONSTANT_ALPHA |
+						PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+				}
+
+				if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
+					*pppop_reg_ptr |=
+						PPP_BLEND_CALPHA_TRNASP;
+			}
 	} else {
-		if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
-		    && (iBuf->mdpImg.alpha == 0xff)) {
-			iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
-		}
-
-		if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
-		    && (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
-			*pppop_reg_ptr |=
-			    PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
-			    PPP_OP_BLEND_CONSTANT_ALPHA |
-			    PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
-			    PPP_BLEND_CALPHA_TRNASP;
-
-			*alpha = iBuf->mdpImg.alpha;
-			*tpVal = iBuf->mdpImg.tpVal;
+		if (perPixelAlpha) {
+			*pppop_reg_ptr |= PPP_OP_ROT_ON |
+			    PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
 		} else {
-			if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) {
-				*pppop_reg_ptr |= PPP_OP_ROT_ON |
-				    PPP_OP_BLEND_ON |
-				    PPP_OP_BLEND_SRCPIXEL_TRANSP;
-				*tpVal = iBuf->mdpImg.tpVal;
-			} else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) {
-				*pppop_reg_ptr |= PPP_OP_ROT_ON |
-				    PPP_OP_BLEND_ON |
+			if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+			    && (iBuf->mdpImg.alpha == 0xff)) {
+				iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
+			}
+
+			if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+			    && (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+				*pppop_reg_ptr |=
+				    PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
+				    PPP_OP_BLEND_CONSTANT_ALPHA |
 				    PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
-				    PPP_OP_BLEND_CONSTANT_ALPHA;
+				    PPP_BLEND_CALPHA_TRNASP;
+
 				*alpha = iBuf->mdpImg.alpha;
+				*tpVal = iBuf->mdpImg.tpVal;
+			} else {
+				if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) {
+					*pppop_reg_ptr |= PPP_OP_ROT_ON |
+					    PPP_OP_BLEND_ON |
+					    PPP_OP_BLEND_SRCPIXEL_TRANSP;
+					*tpVal = iBuf->mdpImg.tpVal;
+				} else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) {
+					*pppop_reg_ptr |= PPP_OP_ROT_ON |
+					    PPP_OP_BLEND_ON |
+					    PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
+					    PPP_OP_BLEND_CONSTANT_ALPHA;
+					*alpha = iBuf->mdpImg.alpha;
+				}
 			}
 		}
 	}
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 930b4e9..c6f531e 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -18,6 +18,7 @@
 static struct msm_panel_common_pdata *mipi_nt35510_pdata;
 static struct dsi_buf nt35510_tx_buf;
 static struct dsi_buf nt35510_rx_buf;
+spinlock_t bl_spinlock;
 
 #define NT35510_SLEEP_OFF_DELAY 150
 #define NT35510_DISPLAY_ON_DELAY 150
@@ -506,6 +507,8 @@
 
 	if (pdev->id == 0) {
 		mipi_nt35510_pdata = pdev->dev.platform_data;
+		if (mipi_nt35510_pdata->bl_lock)
+			spin_lock_init(&bl_spinlock);
 		return 0;
 	}
 
@@ -523,8 +526,16 @@
 
 static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd)
 {
-	/* Add backlight changes later*/
-	return;
+	int bl_level;
+	unsigned long flags;
+	bl_level = mfd->bl_level;
+
+	if (mipi_nt35510_pdata->bl_lock) {
+		spin_lock_irqsave(&bl_spinlock, flags);
+		mipi_nt35510_pdata->pmic_backlight(bl_level);
+		spin_unlock_irqrestore(&bl_spinlock, flags);
+	} else
+		mipi_nt35510_pdata->pmic_backlight(bl_level);
 }
 
 static struct msm_fb_panel_data nt35510_panel_data = {
@@ -564,7 +575,6 @@
 		return -ENOMEM;
 
 	nt35510_panel_data.panel_info = *pinfo;
-
 	ret = platform_device_add_data(pdev, &nt35510_panel_data,
 				sizeof(nt35510_panel_data));
 	if (ret) {
diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
index 2c4ee3e..f052e93 100644
--- a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
@@ -56,7 +56,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 100;
+	pinfo.bl_max = 31;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
index 82e03b2..4e97d99 100644
--- a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
@@ -59,7 +59,7 @@
 	delayed from VSYNC active edge */
 	pinfo.lcdc.hsync_skew = 0;
 	pinfo.clk_rate = 499000000;
-	pinfo.bl_max = 100; /*16; CHECK THIS!!!*/
+	pinfo.bl_max = 31;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_chimei_wuxga.c b/drivers/video/msm/mipi_chimei_wuxga.c
index c63df46..7abb0d4 100644
--- a/drivers/video/msm/mipi_chimei_wuxga.c
+++ b/drivers/video/msm/mipi_chimei_wuxga.c
@@ -55,12 +55,12 @@
 	/* DSIPHY_TIMING_CTRL */
 	.timing = { 0xC9, 0x92, 0x29, /* panel specific */
 	0, /* DSIPHY_TIMING_CTRL_3 = 0 */
-	0x2E, 0x9B, 0x2C, 0x94, 0x2E, 0x03, 0x04},  /* panel specific */
+	0x2D, 0x9B, 0x2B, 0x94, 0x2D, 0x03, 0x04},  /* panel specific */
 
 	/* DSIPHY_PLL_CTRL */
 	.pll = { 0x00, /* common 8960 */
 	/* VCO */
-	0x32, (0x01 | 0x30) , (0x19 | 0xC0), /* panel specific */
+	0x30, (0x01 | 0x30) , (0x19 | 0xC0), /* panel specific */
 	0x00, 0x50, 0x48, 0x63,
 	0x77, 0x88, 0x99, /* Auto update by dsi-mipi driver */
 	0x00, 0x14, 0x03, 0x00, 0x02, /* common 8960 */
@@ -104,19 +104,19 @@
 	 * LVDS-CLK = DSI-CLK/4 , 320 MHZ/4= 80 MHZ.
 	 */
 
-	pinfo->clk_rate = 640 * MHZ ; /* bitclk Calculated */
+	pinfo->clk_rate = 635 * MHZ ; /* bitclk Calculated */
 
 	/*
 	 * this panel is operated by DE,
 	 * vsycn and hsync are ignored
 	 */
 
-	pinfo->lcdc.h_front_porch = 16;	/* thfp */
-	pinfo->lcdc.h_back_porch = 160;	/* thb */
+	pinfo->lcdc.h_front_porch = 160-48-32;	/* thfp */
+	pinfo->lcdc.h_back_porch = 48;	/* thb */
 	pinfo->lcdc.h_pulse_width = 32;	/* thpw */
 
-	pinfo->lcdc.v_front_porch = 0;	/* tvfp */
-	pinfo->lcdc.v_back_porch = 26;	/* tvb */
+	pinfo->lcdc.v_front_porch = 26-3-6;	/* tvfp */
+	pinfo->lcdc.v_back_porch = 3;	/* tvb */
 	pinfo->lcdc.v_pulse_width = 6;	/* tvpw */
 
 	pinfo->lcdc.border_clr = 0;		/* black */
@@ -138,7 +138,7 @@
 	pinfo->mipi.dsi_phy_db = &dsi_video_mode_phy_db;
 
 	/* Four lanes are recomended for 1920x1200 at 60 frames per second */
-	pinfo->mipi.frame_rate = 45; /* 45 frames per second */
+	pinfo->mipi.frame_rate = 60;
 	pinfo->mipi.data_lane0 = true;
 	pinfo->mipi.data_lane1 = true;
 	pinfo->mipi.data_lane2 = true;
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index f319072..a9f5078 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -91,6 +91,9 @@
 		} else {
 			mdp3_dsi_cmd_dma_busy_wait(mfd);
 		}
+	} else {
+		/* video mode, wait until fifo cleaned */
+		mipi_dsi_controller_cfg(0);
 	}
 
 	/*
@@ -164,6 +167,7 @@
 	if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
 		mipi_dsi_pdata->dsi_power_save(1);
 
+	cont_splash_clk_ctrl();
 	local_bh_disable();
 	mipi_dsi_ahb_ctrl(1);
 	local_bh_enable();
@@ -427,7 +431,7 @@
 		return 0;
 	}
 
-	mipi_dsi_clk_init(&pdev->dev);
+	mipi_dsi_clk_init(pdev);
 
 	if (!mipi_dsi_resource_initialized)
 		return -EPERM;
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 4fbb044..79eb8b8 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,
@@ -298,9 +299,10 @@
 	int target_type);
 int mipi_dsi_clk_div_config(uint8 bpp, uint8 lanes,
 			    uint32 *expected_dsi_pclk);
-void mipi_dsi_clk_init(struct device *dev);
+void mipi_dsi_clk_init(struct platform_device *pdev);
 void mipi_dsi_clk_deinit(struct device *dev);
 void mipi_dsi_ahb_ctrl(u32 enable);
+void cont_splash_clk_ctrl(void);
 void mipi_dsi_turn_on_clks(void);
 void mipi_dsi_turn_off_clks(void);
 
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 0a80363..dbf45b0 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -1,5 +1,5 @@
 
-/* 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
@@ -39,7 +39,6 @@
 #include "mdp.h"
 #include "mdp4.h"
 
-int mipi_dsi_clk_on;
 static struct completion dsi_dma_comp;
 static struct completion dsi_mdp_comp;
 static struct dsi_buf dsi_tx_buf;
@@ -147,11 +146,6 @@
 
 void mipi_dsi_turn_on_clks(void)
 {
-	if (mipi_dsi_clk_on) {
-		pr_err("%s: mipi_dsi_clks already ON\n", __func__);
-		return;
-	}
-	mipi_dsi_clk_on = 1;
 	local_bh_disable();
 	mipi_dsi_ahb_ctrl(1);
 	mipi_dsi_clk_enable();
@@ -160,11 +154,6 @@
 
 void mipi_dsi_turn_off_clks(void)
 {
-	if (mipi_dsi_clk_on == 0) {
-		pr_err("%s: mipi_dsi_clks already OFF\n", __func__);
-		return;
-	}
-	mipi_dsi_clk_on = 0;
 	local_bh_disable();
 	mipi_dsi_clk_disable();
 	mipi_dsi_ahb_ctrl(0);
@@ -1493,9 +1482,9 @@
 		mipi_dsi_mdp_stat_inc(STAT_DSI_MDP);
 		spin_lock(&dsi_mdp_lock);
 		dsi_mdp_busy = FALSE;
+		mipi_dsi_disable_irq_nosync();
 		spin_unlock(&dsi_mdp_lock);
 		complete(&dsi_mdp_comp);
-		mipi_dsi_disable_irq_nosync();
 		mipi_dsi_post_kickoff_action();
 	}
 
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index ed0dee4..0070757 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -14,6 +14,7 @@
 #ifdef CONFIG_SPI_QUP
 #include <linux/spi/spi.h>
 #endif
+#include <linux/leds.h>
 #include "msm_fb.h"
 #include "mipi_dsi.h"
 #include "mipi_novatek.h"
@@ -26,6 +27,8 @@
 static struct dsi_buf novatek_rx_buf;
 static int mipi_novatek_lcd_init(void);
 
+static int wled_trigger_initialized;
+
 #define MIPI_DSI_NOVATEK_SPI_DEVICE_NAME	"dsi_novatek_3d_panel_spi"
 #define HPCI_FPGA_READ_CMD	0x84
 #define HPCI_FPGA_WRITE_CMD	0x04
@@ -427,12 +430,17 @@
 	return 0;
 }
 
-
+DEFINE_LED_TRIGGER(bkl_led_trigger);
 
 static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
 {
 	struct mipi_panel_info *mipi;
 
+	if ((mipi_novatek_pdata->enable_wled_bl_ctrl)
+	    && (wled_trigger_initialized)) {
+		led_trigger_event(bkl_led_trigger, mfd->bl_level);
+		return;
+	}
 	mipi  = &mfd->panel_info.mipi;
 
 	mutex_lock(&mfd->dma->ov_mutex);
@@ -639,6 +647,10 @@
 		pr_info("%s: SUCCESS (SPI)\n", __func__);
 #endif
 
+	led_trigger_register_simple("bkl_trigger", &bkl_led_trigger);
+	pr_info("%s: SUCCESS (WLED TRIGGER)\n", __func__);
+	wled_trigger_initialized = 1;
+
 	mipi_dsi_buf_alloc(&novatek_tx_buf, DSI_BUF_SIZE);
 	mipi_dsi_buf_alloc(&novatek_rx_buf, DSI_BUF_SIZE);
 
diff --git a/drivers/video/msm/mipi_orise.c b/drivers/video/msm/mipi_orise.c
new file mode 100644
index 0000000..2afbb9b
--- /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/mipi_toshiba.c b/drivers/video/msm/mipi_toshiba.c
index 2db8bcf..aeaa5aa 100644
--- a/drivers/video/msm/mipi_toshiba.c
+++ b/drivers/video/msm/mipi_toshiba.c
@@ -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
@@ -224,11 +224,21 @@
 	return 0;
 }
 
+void mipi_bklight_pwm_cfg(void)
+{
+	if (mipi_toshiba_pdata && mipi_toshiba_pdata->dsi_pwm_cfg)
+		mipi_toshiba_pdata->dsi_pwm_cfg();
+}
+
 static void mipi_toshiba_set_backlight(struct msm_fb_data_type *mfd)
 {
 	int ret;
+	static int bklight_pwm_cfg;
 
-	pr_debug("%s: back light level %d\n", __func__, mfd->bl_level);
+	if (bklight_pwm_cfg == 0) {
+		mipi_bklight_pwm_cfg();
+		bklight_pwm_cfg++;
+	}
 
 	if (bl_lpm) {
 		ret = pwm_config(bl_lpm, MIPI_TOSHIBA_PWM_DUTY_LEVEL *
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
new file mode 100644
index 0000000..30e255e
--- /dev/null
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -0,0 +1,806 @@
+/* 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_truly_tft540960_1_e.h"
+
+static struct msm_panel_common_pdata *mipi_truly_pdata;
+static struct dsi_buf truly_tx_buf;
+static struct dsi_buf truly_rx_buf;
+
+#define TRULY_CMD_DELAY 0
+#define MIPI_SETTING_DELAY 10
+#define TRULY_SLEEP_OFF_DELAY 150
+#define TRULY_DISPLAY_ON_DELAY 150
+
+/* common setting */
+static char exit_sleep[2] = {0x11, 0x00};
+static char display_on[2] = {0x29, 0x00};
+static char display_off[2] = {0x28, 0x00};
+static char enter_sleep[2] = {0x10, 0x00};
+static char write_ram[2] = {0x2c, 0x00}; /* write ram */
+
+static struct dsi_cmd_desc truly_display_off_cmds[] = {
+	{DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(display_off), display_off},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(enter_sleep), enter_sleep}
+};
+
+
+/* TFT540960_1_E CMD mode */
+static char cmd0[5] = {
+	0xFF, 0xAA, 0x55, 0x25,
+	0x01,
+};
+
+static char cmd2[5] = {
+	0xF3, 0x02, 0x03, 0x07,
+	0x45,
+};
+
+static char cmd3[6] = {
+	0xF0, 0x55, 0xAA, 0x52,
+	0x08, 0x00,
+};
+
+static char cmd4[2] = {
+	0xB1, 0xeC,
+};
+
+/* add 0X BD command */
+static char cmd26_2[6] = {
+	0xBD, 0x01, 0x48, 0x10, 0x38, 0x01 /* 59 HZ */
+};
+
+static char cmd5[5] = {
+	0xB8, 0x01, 0x02, 0x02,
+	0x02,
+};
+
+static char cmd6[4] = {
+	0xBC, 0x05, 0x05, 0x05,
+};
+
+static char cmd7[2] = {
+	0x4C, 0x11,
+};
+
+static char cmd8[6] = {
+	0xF0, 0x55, 0xAA, 0x52,
+	0x08, 0x01,
+};
+
+static char cmd9[4] = {
+	0xB0, 0x05, 0x05, 0x05,
+};
+
+static char cmd10[4] = {
+	0xB6, 0x44, 0x44, 0x44,
+};
+static char cmd11[4] = {
+	0xB1, 0x05, 0x05, 0x05,
+};
+
+static char cmd12[4] = {
+	0xB7, 0x34, 0x34, 0x34,
+};
+
+static char cmd13[4] = {
+	0xB3, 0x10, 0x10, 0x10,
+};
+
+static char cmd14[4] = {
+	0xB9, 0x34, 0x34, 0x34,
+};
+
+static char cmd15[4] = {
+	0xB4, 0x0A, 0x0A, 0x0A,
+};
+
+static char cmd16[4] = {
+	0xBA, 0x14, 0x14, 0x14,
+};
+static char cmd17[4] = {
+	0xBC, 0x00, 0xA0, 0x00,
+};
+
+static char cmd18[4] = {
+	0xBD, 0x00, 0xA0, 0x00,
+};
+
+static char cmd19[2] = {
+	0xBE, 0x45,
+};
+
+static char cmd20[17] = {
+	0xD1, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char cmd21[17] = {
+	0xD2, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char cmd22[17] = {
+	0xD3, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char cmd23[5] = {
+	0xD4, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char cmd24[17] = {
+	0xD5, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+static char cmd25[17] = {
+	0xD6, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char cmd26[17] = {
+	0xD7, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+static char cmd27[5] = {
+	0xD8, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+
+static char cmd28[17] = {
+	0xD9, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char cmd29[17] = {
+	0xDD, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+static char cmd30[17] = {
+	0xDE, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char cmd31[5] = {
+	0xDF, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char cmd32[17] = {
+	0xE0, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char cmd33[17] = {
+	0xE1, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char cmd34[17] = {
+	0xE2, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char cmd35[5] = {
+	0xE3, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char cmd36[17] = {
+	0xE4, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+static char cmd37[17] = {
+	0xE5, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char cmd38[17] = {
+	0xE6, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char cmd39[5] = {
+	0xE7, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char cmd40[17] = {
+	0xE8, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char cmd41[17] = {
+	0xE9, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char cmd42[17] = {
+	0xEA, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char cmd43[5] = {
+	0xEB, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char cmd44[2] = {
+	0x3A, 0x07,
+};
+
+static char cmd45[2] = {
+	0x35, 0x00,
+};
+
+
+static struct dsi_cmd_desc truly_cmd_display_on_cmds[] = {
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd0), cmd0},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd2), cmd2},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd3), cmd3},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd4), cmd4},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd26_2), cmd26_2},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd5), cmd5},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd6), cmd6},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd7), cmd7},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd8), cmd8},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd9), cmd9},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd10), cmd10},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd11), cmd11},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd12), cmd12},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd13), cmd13},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd14), cmd14},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd15), cmd15},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd16), cmd16},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd17), cmd17},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd18), cmd18},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd19), cmd19},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd20), cmd20},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd21), cmd21},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd22), cmd22},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd23), cmd23},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd24), cmd24},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd25), cmd25},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd26), cmd26},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd27), cmd27},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd28), cmd28},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd29), cmd29},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd30), cmd30},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd31), cmd31},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd32), cmd32},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd33), cmd33},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd34), cmd34},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd35), cmd35},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd36), cmd36},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd37), cmd37},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd38), cmd38},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd39), cmd39},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd40), cmd40},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd41), cmd41},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd42), cmd42},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd43), cmd43},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd44), cmd44},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd45), cmd45},
+	{DTYPE_DCS_WRITE, 1, 0, 0, TRULY_SLEEP_OFF_DELAY, sizeof(exit_sleep),
+								exit_sleep},
+	{DTYPE_DCS_WRITE, 1, 0, 0, TRULY_CMD_DELAY, sizeof(display_on),
+							display_on},
+	{DTYPE_DCS_WRITE, 1, 0, 0, TRULY_CMD_DELAY, sizeof(write_ram),
+							write_ram},
+
+};
+
+/* TFT540960_1_E VIDEO mode */
+static char video0[5] = {
+	0xFF, 0xAA, 0x55, 0x25,
+	0x01,
+};
+
+static char video2[5] = {
+	0xF3, 0x02, 0x03, 0x07,
+	0x15,
+};
+
+static char video3[6] = {
+	0xF0, 0x55, 0xAA, 0x52,
+	0x08, 0x00,
+};
+
+static char video4[2] = {
+	0xB1, 0xFC,
+};
+
+static char video5[5] = {
+	0xB8, 0x01, 0x02, 0x02,
+	0x02,
+};
+
+static char video6[4] = {
+	0xBC, 0x05, 0x05, 0x05,
+};
+
+static char video7[2] = {
+	0x4C, 0x11,
+};
+
+static char video8[6] = {
+	0xF0, 0x55, 0xAA, 0x52,
+	0x08, 0x01,
+};
+
+static char video9[4] = {
+	0xB0, 0x05, 0x05, 0x05,
+};
+
+static char video10[4] = {
+	0xB6, 0x44, 0x44, 0x44,
+};
+
+static char video11[4] = {
+	0xB1, 0x05, 0x05, 0x05,
+};
+
+static char video12[4] = {
+	0xB7, 0x34, 0x34, 0x34,
+};
+
+static char video13[4] = {
+	0xB3, 0x10, 0x10, 0x10,
+};
+
+static char video14[4] = {
+	0xB9, 0x34, 0x34, 0x34,
+};
+
+static char video15[4] = {
+	0xB4, 0x0A, 0x0A, 0x0A,
+};
+
+static char video16[4] = {
+	0xBA, 0x14, 0x14, 0x14,
+};
+
+static char video17[4] = {
+	0xBC, 0x00, 0xA0, 0x00,
+};
+
+static char video18[4] = {
+	0xBD, 0x00, 0xA0, 0x00,
+};
+
+static char video19[2] = {
+	0xBE, 0x45,
+};
+
+static char video20[17] = {
+	0xD1, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char video21[17] = {
+	0xD2, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char video22[17] = {
+	0xD3, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char video23[5] = {
+	0xD4, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char video24[17] = {
+	0xD5, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char video25[17] = {
+	0xD6, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char video26[17] = {
+	0xD7, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char video27[5] = {
+	0xD8, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char video28[17] = {
+	0xD9, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char video29[17] = {
+	0xDD, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char video30[17] = {
+	0xDE, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char video31[5] = {
+	0xDF, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char video32[17] = {
+	0xE0, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char video33[17] = {
+	0xE1, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char video34[17] = {
+	0xE2, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char video35[5] = {
+	0xE3, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char video36[17] = {
+	0xE4, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char video37[17] = {
+	0xE5, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char video38[17] = {
+	0xE6, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char video39[5] = {
+	0xE7, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char video40[17] = {
+	0xE8, 0x00, 0x32, 0x00,
+	0x41, 0x00, 0x54, 0x00,
+	0x67, 0x00, 0x7A, 0x00,
+	0x98, 0x00, 0xB0, 0x00,
+	0xDB,
+};
+
+static char video41[17] = {
+	0xE9, 0x01, 0x01, 0x01,
+	0x3F, 0x01, 0x70, 0x01,
+	0xB4, 0x01, 0xEC, 0x01,
+	0xED, 0x02, 0x1E, 0x02,
+	0x51,
+};
+
+static char video42[17] = {
+	0xEA, 0x02, 0x6C, 0x02,
+	0x8D, 0x02, 0xA5, 0x02,
+	0xC9, 0x02, 0xEA, 0x03,
+	0x19, 0x03, 0x45, 0x03,
+	0x7A,
+};
+
+static char video43[5] = {
+	0xEB, 0x03, 0xB0, 0x03,
+	0xF4,
+};
+
+static char video44[2] = {
+	0x3A, 0x07,
+};
+
+static char video45[2] = {
+	0x35, 0x00,
+};
+
+static struct dsi_cmd_desc truly_video_display_on_cmds[] = {
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video0), video0},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video2), video2},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video3), video3},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video4), video4},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video5), video5},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video6), video6},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video7), video7},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video8), video8},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video9), video9},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video10), video10},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video11), video11},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video12), video12},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video13), video13},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video14), video14},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video15), video15},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video16), video16},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video17), video17},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video18), video18},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video19), video19},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video20), video20},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video21), video21},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video22), video22},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video23), video23},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video24), video24},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video25), video25},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video26), video26},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video27), video27},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video28), video28},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video29), video29},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video30), video30},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video31), video31},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video32), video32},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video33), video33},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video34), video34},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video35), video35},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video36), video36},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video37), video37},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video38), video38},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video39), video39},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video40), video40},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video41), video41},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video42), video42},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video43), video43},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video44), video44},
+	{DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video45), video45},
+
+	{DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(exit_sleep), exit_sleep},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_on), display_on},
+};
+
+static int mipi_truly_lcd_on(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+	struct mipi_panel_info *mipi;
+
+	mfd = platform_get_drvdata(pdev);
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	mipi  = &mfd->panel_info.mipi;
+	pr_info("%s: mode = %d\n", __func__, mipi->mode);
+	msleep(120);
+
+	if (mipi->mode == DSI_VIDEO_MODE) {
+		mipi_dsi_cmds_tx(mfd, &truly_tx_buf,
+			truly_video_display_on_cmds,
+			ARRAY_SIZE(truly_video_display_on_cmds));
+	} else if (mipi->mode == DSI_CMD_MODE) {
+		mipi_dsi_cmds_tx(mfd, &truly_tx_buf,
+			truly_cmd_display_on_cmds,
+			ARRAY_SIZE(truly_cmd_display_on_cmds));
+	}
+
+	return 0;
+}
+
+static int mipi_truly_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, &truly_tx_buf, truly_display_off_cmds,
+			ARRAY_SIZE(truly_display_off_cmds));
+
+	return 0;
+}
+
+static int __devinit mipi_truly_lcd_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	if (pdev->id == 0) {
+		mipi_truly_pdata = pdev->dev.platform_data;
+		return rc;
+	}
+
+	msm_fb_add_device(pdev);
+
+	return rc;
+}
+
+static struct platform_driver this_driver = {
+	.probe  = mipi_truly_lcd_probe,
+	.driver = {
+		.name   = "mipi_truly_tft540960_1_e",
+	},
+};
+
+static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd)
+{
+	return;
+}
+
+static struct msm_fb_panel_data truly_panel_data = {
+	.on	= mipi_truly_lcd_on,
+	.off = mipi_truly_lcd_off,
+	.set_backlight = mipi_truly_set_backlight,
+};
+
+static int ch_used[3];
+
+static int mipi_truly_tft540960_1_e_lcd_init(void)
+{
+	mipi_dsi_buf_alloc(&truly_tx_buf, DSI_BUF_SIZE);
+	mipi_dsi_buf_alloc(&truly_rx_buf, DSI_BUF_SIZE);
+
+	return platform_driver_register(&this_driver);
+}
+int mipi_truly_tft540960_1_e_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;
+
+	ret = mipi_truly_tft540960_1_e_lcd_init();
+	if (ret) {
+		pr_err("%s: platform_device_register failed!\n", __func__);
+		return ret;
+	}
+
+	pdev = platform_device_alloc("mipi_truly_tft540960_1_e",
+						(panel << 8)|channel);
+	if (!pdev)
+		return -ENOMEM;
+
+	truly_panel_data.panel_info = *pinfo;
+
+	ret = platform_device_add_data(pdev, &truly_panel_data,
+		sizeof(truly_panel_data));
+	if (ret) {
+		pr_err("%s: platform_device_add_data failed!\n", __func__);
+		goto err_device_put;
+	}
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		pr_err("%s: platform_device_register failed!\n", __func__);
+		goto err_device_put;
+	}
+
+	return 0;
+
+err_device_put:
+	platform_device_put(pdev);
+	return ret;
+}
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.h b/drivers/video/msm/mipi_truly_tft540960_1_e.h
new file mode 100644
index 0000000..8cbfb80
--- /dev/null
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.h
@@ -0,0 +1,20 @@
+/* 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_TRULY_H
+#define MIPI_TRULY_H
+
+int mipi_truly_tft540960_1_e_device_register(struct msm_panel_info *pinfo,
+					u32 channel, u32 panel);
+
+#endif  /* MIPI_TRULY_H */
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
new file mode 100644
index 0000000..b3805c5
--- /dev/null
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
@@ -0,0 +1,98 @@
+/* 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_truly_tft540960_1_e.h"
+
+static struct msm_panel_info pinfo;
+
+static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = {
+	/* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */
+	/* regulator */
+	{0x03, 0x01, 0x01, 0x00},
+	/* timing   */
+	{0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90,
+	0x18, 0x03, 0x04},
+	/* phy ctrl */
+	{0x7f, 0x00, 0x00, 0x00},
+	/* strength */
+	{0xbb, 0x02, 0x06, 0x00},
+	/* pll control */
+	{0x01, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62,
+	0x01, 0x0f, 0x07,
+	0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0},
+};
+
+static int mipi_cmd_truly_qhd_pt_init(void)
+{
+	int ret;
+	if (msm_fb_detect_client("mipi_cmd_truly_qhd"))
+		return 0;
+
+	pinfo.xres = 540;
+	pinfo.yres = 960;
+	pinfo.type = MIPI_CMD_PANEL;
+	pinfo.pdest = DISPLAY_1;
+	pinfo.wait_cycle = 0;
+	pinfo.bpp = 24;
+	pinfo.lcdc.h_back_porch = 100;
+	pinfo.lcdc.h_front_porch = 100;
+	pinfo.lcdc.h_pulse_width = 8;
+	pinfo.lcdc.v_back_porch = 20;
+	pinfo.lcdc.v_front_porch = 20;
+	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 = 16;
+	pinfo.bl_min = 1;
+	pinfo.fb_num = 2;
+
+	pinfo.clk_rate = 499000000;
+
+	pinfo.lcd.vsync_enable = TRUE;
+	pinfo.lcd.hw_vsync_mode = TRUE;
+	pinfo.lcd.refx100 = 6100; /* adjust refx100 to prevent tearing */
+
+	pinfo.mipi.mode = DSI_CMD_MODE;
+	pinfo.mipi.dst_format = DSI_CMD_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.t_clk_post = 0x20;
+	pinfo.mipi.t_clk_pre = 0x2F;
+	pinfo.mipi.stream = 0; /* dma_p */
+	pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW_TE;
+	pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
+	pinfo.mipi.te_sel = 1; /* TE from vsync 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;
+	pinfo.mipi.tx_eot_append = 0x01;
+	pinfo.mipi.rx_eot_ignore = 0x0;
+	pinfo.mipi.dlane_swap = 0x01;
+
+	ret = mipi_truly_tft540960_1_e_device_register(&pinfo, MIPI_DSI_PRIM,
+						MIPI_DSI_PANEL_WVGA_PT);
+	if (ret)
+		pr_err("%s: failed to register device!\n", __func__);
+
+	return ret;
+}
+
+module_init(mipi_cmd_truly_qhd_pt_init);
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
new file mode 100644
index 0000000..0e12813
--- /dev/null
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
@@ -0,0 +1,107 @@
+/* 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_truly_tft540960_1_e.h"
+
+static struct msm_panel_info pinfo;
+
+static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = {
+	/* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */
+	/* regulator */
+	{0x03, 0x01, 0x01, 0x00},
+	/* timing   */
+	{0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90,
+	0x18, 0x03, 0x04},
+	/* phy ctrl */
+	{0x7f, 0x00, 0x00, 0x00},
+	/* strength */
+	{0xbb, 0x02, 0x06, 0x00},
+	/* pll control */
+	{0x00, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62,
+	0x01, 0x0f, 0x07,
+	0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0},
+};
+
+static int mipi_video_truly_qhd_pt_init(void)
+{
+	int ret;
+	if (msm_fb_detect_client("mipi_video_truly_qhd"))
+		return 0;
+
+	pinfo.xres = 540;
+	pinfo.yres = 960;
+	pinfo.type = MIPI_VIDEO_PANEL;
+	pinfo.pdest = DISPLAY_1;
+	pinfo.wait_cycle = 0;
+	pinfo.bpp = 24;
+	pinfo.lcdc.h_back_porch = 100;
+	pinfo.lcdc.h_front_porch = 100;
+	pinfo.lcdc.h_pulse_width = 8;
+	pinfo.lcdc.v_back_porch = 20;
+	pinfo.lcdc.v_front_porch = 20;
+	pinfo.lcdc.v_pulse_width = 1;
+	pinfo.lcdc.border_clr = 0;	/* blk */
+	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
+	/* number of dot_clk cycles HSYNC active edge
+	   is delayed from VSYNC active edge */
+	pinfo.lcdc.hsync_skew = 0;
+	pinfo.clk_rate = 699000000;
+	pinfo.lcd.refx100 = 6000; /* FB driver calc FPS based on this value */
+	pinfo.bl_max = 16;
+	pinfo.bl_min = 1;
+	pinfo.fb_num = 2;
+
+	pinfo.mipi.mode = DSI_VIDEO_MODE;
+	/* send HSA and HE following VS/VE packet */
+	pinfo.mipi.pulse_mode_hsa_he = TRUE;
+	pinfo.mipi.hfp_power_stop = TRUE; /* LP-11 during the HFP period */
+	pinfo.mipi.hbp_power_stop = TRUE; /* LP-11 during the HBP period */
+	pinfo.mipi.hsa_power_stop = TRUE; /* LP-11 during the HSA period */
+	/* LP-11 or let Command Mode Engine send packets in
+	HS or LP mode for the BLLP of the last line of a frame */
+	pinfo.mipi.eof_bllp_power_stop = TRUE;
+	/* LP-11 or let Command Mode Engine send packets in
+	HS or LP mode for packets sent during BLLP period */
+	pinfo.mipi.bllp_power_stop = TRUE;
+
+	pinfo.mipi.traffic_mode = DSI_BURST_MODE;
+	pinfo.mipi.dst_format =  DSI_VIDEO_DST_FORMAT_RGB888;
+	pinfo.mipi.vc = 0;
+	pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; /* RGB */
+	pinfo.mipi.data_lane0 = TRUE;
+	pinfo.mipi.data_lane1 = TRUE;
+
+	pinfo.mipi.t_clk_post = 0x20;
+	pinfo.mipi.t_clk_pre = 0x2f;
+
+	pinfo.mipi.stream = 0; /* dma_p */
+	pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE;
+	pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
+	pinfo.mipi.frame_rate = 60;
+
+	pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db;
+	pinfo.mipi.dlane_swap = 0x01;
+	/* append EOT at the end of data burst */
+	pinfo.mipi.tx_eot_append = 0x01;
+
+	ret = mipi_truly_tft540960_1_e_device_register(&pinfo, MIPI_DSI_PRIM,
+						MIPI_DSI_PANEL_WVGA_PT);
+	if (ret)
+		pr_err("%s: failed to register device!\n", __func__);
+
+	return ret;
+}
+
+module_init(mipi_video_truly_qhd_pt_init);
diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c
index 032c9cd..193b89c 100644
--- a/drivers/video/msm/msm_dss_io_7x27a.c
+++ b/drivers/video/msm/msm_dss_io_7x27a.c
@@ -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
@@ -30,8 +30,9 @@
 static struct clk *ahb_m_clk;
 static struct clk *ahb_s_clk;
 static struct clk *ebi1_dsi_clk;
+int mipi_dsi_clk_on;
 
-void mipi_dsi_clk_init(struct device *dev)
+void mipi_dsi_clk_init(struct platform_device *pdev)
 {
 	dsi_esc_clk = clk_get(NULL, "dsi_esc_clk");
 	if (IS_ERR(dsi_esc_clk)) {
@@ -294,16 +295,31 @@
 	wmb();
 }
 
+void cont_splash_clk_ctrl(void)
+{
+}
+
 void mipi_dsi_ahb_ctrl(u32 enable)
 {
+	static int ahb_ctrl_done;
 	if (enable) {
+		if (ahb_ctrl_done) {
+			pr_info("%s: ahb clks already ON\n", __func__);
+			return;
+		}
 		clk_enable(dsi_ref_clk);
 		clk_enable(ahb_m_clk);
 		clk_enable(ahb_s_clk);
+		ahb_ctrl_done = 1;
 	} else {
+		if (ahb_ctrl_done == 0) {
+			pr_info("%s: ahb clks already OFF\n", __func__);
+			return;
+		}
 		clk_disable(ahb_m_clk);
 		clk_disable(ahb_s_clk);
 		clk_disable(dsi_ref_clk);
+		ahb_ctrl_done = 0;
 	}
 }
 
@@ -312,6 +328,10 @@
 	unsigned data = 0;
 	uint32 pll_ctrl;
 
+	if (mipi_dsi_clk_on) {
+		pr_info("%s: mipi_dsi_clks already ON\n", __func__);
+		return;
+	}
 	if (clk_set_rate(ebi1_dsi_clk, 65000000)) /* 65 MHz */
 		pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__);
 	clk_enable(ebi1_dsi_clk);
@@ -327,10 +347,15 @@
 	clk_enable(dsi_esc_clk);
 	mipi_dsi_pclk_ctrl(&dsi_pclk, 1);
 	mipi_dsi_clk_ctrl(&dsicore_clk, 1);
+	mipi_dsi_clk_on = 1;
 }
 
 void mipi_dsi_clk_disable(void)
 {
+	if (mipi_dsi_clk_on == 0) {
+		pr_info("%s: mipi_dsi_clks already OFF\n", __func__);
+		return;
+	}
 	mipi_dsi_pclk_ctrl(&dsi_pclk, 0);
 	mipi_dsi_clk_ctrl(&dsicore_clk, 0);
 	clk_disable(dsi_esc_clk);
@@ -341,6 +366,7 @@
 	if (clk_set_rate(ebi1_dsi_clk, 0))
 		pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__);
 	clk_disable(ebi1_dsi_clk);
+	mipi_dsi_clk_on = 0;
 }
 
 void mipi_dsi_phy_ctrl(int on)
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 3b000ec..a6f1d36 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"
@@ -61,9 +62,17 @@
 static struct clk *dsi_s_pclk;
 
 static struct clk *amp_pclk;
+int mipi_dsi_clk_on;
 
-void mipi_dsi_clk_init(struct device *dev)
+static int cont_splash_clks_enabled;
+
+void mipi_dsi_clk_init(struct platform_device *pdev)
 {
+	struct msm_fb_data_type *mfd;
+	struct device *dev = &pdev->dev;
+
+	mfd = platform_get_drvdata(pdev);
+
 	amp_pclk = clk_get(NULL, "amp_pclk");
 	if (IS_ERR(amp_pclk)) {
 		pr_err("can't find amp_pclk\n");
@@ -94,6 +103,12 @@
 		goto mipi_dsi_clk_err;
 	}
 
+	if (!(mfd->cont_splash_done)) {
+		clk_enable(dsi_byte_div_clk);
+		clk_enable(dsi_esc_clk);
+		cont_splash_clks_enabled = 1;
+	}
+
 	return;
 
 mipi_dsi_clk_err:
@@ -328,7 +343,7 @@
 	} else if (rate < 250) {
 		vco = rate * 4;
 		div_ratio = 4;
-	} else if (rate < 500) {
+	} else if (rate < 600) {
 		vco = rate * 2;
 		div_ratio = 2;
 	} else {
@@ -526,24 +541,48 @@
 		mipi_dsi_configure_serdes();
 }
 
+void cont_splash_clk_ctrl(void)
+{
+	if (cont_splash_clks_enabled) {
+		clk_disable(dsi_byte_div_clk);
+		clk_disable(dsi_esc_clk);
+		cont_splash_clks_enabled = 0;
+	}
+}
+
 void mipi_dsi_ahb_ctrl(u32 enable)
 {
+	static int ahb_ctrl_done;
 	if (enable) {
+		if (ahb_ctrl_done) {
+			pr_info("%s: ahb clks already ON\n", __func__);
+			return;
+		}
 		clk_enable(amp_pclk); /* clock for AHB-master to AXI */
 		clk_enable(dsi_m_pclk);
 		clk_enable(dsi_s_pclk);
 		mipi_dsi_ahb_en();
 		mipi_dsi_sfpb_cfg();
+		ahb_ctrl_done = 1;
 	} else {
+		if (ahb_ctrl_done == 0) {
+			pr_info("%s: ahb clks already OFF\n", __func__);
+			return;
+		}
 		clk_disable(dsi_m_pclk);
 		clk_disable(dsi_s_pclk);
 		clk_disable(amp_pclk); /* clock for AHB-master to AXI */
+		ahb_ctrl_done = 0;
 	}
 }
 
 void mipi_dsi_clk_enable(void)
 {
 	u32 pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200);
+	if (mipi_dsi_clk_on) {
+		pr_info("%s: mipi_dsi_clks already ON\n", __func__);
+		return;
+	}
 	MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01);
 	mipi_dsi_phy_rdy_poll();
 
@@ -557,17 +596,23 @@
 	mipi_dsi_clk_ctrl(&dsicore_clk, 1);
 	clk_enable(dsi_byte_div_clk);
 	clk_enable(dsi_esc_clk);
+	mipi_dsi_clk_on = 1;
 	mdp4_stat.dsi_clk_on++;
 }
 
 void mipi_dsi_clk_disable(void)
 {
+	if (mipi_dsi_clk_on == 0) {
+		pr_info("%s: mipi_dsi_clks already OFF\n", __func__);
+		return;
+	}
 	clk_disable(dsi_esc_clk);
 	clk_disable(dsi_byte_div_clk);
 	mipi_dsi_pclk_ctrl(&dsi_pclk, 0);
 	mipi_dsi_clk_ctrl(&dsicore_clk, 0);
 	/* DSIPHY_PLL_CTRL_0, disable dsi pll */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x0);
+	mipi_dsi_clk_on = 0;
 	mdp4_stat.dsi_clk_off++;
 }
 
@@ -634,6 +679,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_dss_io_8x60.c b/drivers/video/msm/msm_dss_io_8x60.c
index 0daf727..2231bce 100644
--- a/drivers/video/msm/msm_dss_io_8x60.c
+++ b/drivers/video/msm/msm_dss_io_8x60.c
@@ -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
@@ -32,8 +32,9 @@
 static struct clk *dsi_s_pclk;
 
 static struct clk *amp_pclk;
+int mipi_dsi_clk_on;
 
-void mipi_dsi_clk_init(struct device *dev)
+void mipi_dsi_clk_init(struct platform_device *pdev)
 {
 	amp_pclk = clk_get(NULL, "amp_pclk");
 	if (IS_ERR(amp_pclk)) {
@@ -390,24 +391,43 @@
 	wmb();
 }
 
+void cont_splash_clk_ctrl(void)
+{
+}
+
 void mipi_dsi_ahb_ctrl(u32 enable)
 {
+	static int ahb_ctrl_done;
 	if (enable) {
+		if (ahb_ctrl_done) {
+			pr_info("%s: ahb clks already ON\n", __func__);
+			return;
+		}
 		clk_enable(amp_pclk); /* clock for AHB-master to AXI */
 		clk_enable(dsi_m_pclk);
 		clk_enable(dsi_s_pclk);
 		mipi_dsi_ahb_en();
 		mipi_dsi_sfpb_cfg();
+		ahb_ctrl_done = 1;
 	} else {
+		if (ahb_ctrl_done == 0) {
+			pr_info("%s: ahb clks already OFF\n", __func__);
+			return;
+		}
 		clk_disable(dsi_m_pclk);
 		clk_disable(dsi_s_pclk);
 		clk_disable(amp_pclk); /* clock for AHB-master to AXI */
+		ahb_ctrl_done = 0;
 	}
 }
 
 void mipi_dsi_clk_enable(void)
 {
 	u32 pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200);
+	if (mipi_dsi_clk_on) {
+		pr_info("%s: mipi_dsi_clks already ON\n", __func__);
+		return;
+	}
 	MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01);
 	mb();
 
@@ -417,10 +437,15 @@
 	mipi_dsi_clk_ctrl(&dsicore_clk, 1);
 	clk_enable(dsi_byte_div_clk);
 	clk_enable(dsi_esc_clk);
+	mipi_dsi_clk_on = 1;
 }
 
 void mipi_dsi_clk_disable(void)
 {
+	if (mipi_dsi_clk_on == 0) {
+		pr_info("%s: mipi_dsi_clks already OFF\n", __func__);
+		return;
+	}
 	clk_disable(dsi_esc_clk);
 	clk_disable(dsi_byte_div_clk);
 
@@ -428,6 +453,7 @@
 	mipi_dsi_clk_ctrl(&dsicore_clk, 0);
 	/* DSIPHY_PLL_CTRL_0, disable dsi pll */
 	MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x40);
+	mipi_dsi_clk_on = 0;
 }
 
 void mipi_dsi_phy_ctrl(int on)
@@ -579,6 +605,14 @@
 
 void hdmi_msm_powerdown_phy(void)
 {
+	/* Assert RESET PHY from controller */
+	HDMI_OUTP_ND(0x02D4, 0x4);
+	udelay(10);
+	/* De-assert RESET PHY from controller */
+	HDMI_OUTP_ND(0x02D4, 0x0);
+	/* Turn off Driver */
+	HDMI_OUTP_ND(0x0308, 0x1F);
+	udelay(10);
 	/* Disable PLL */
 	HDMI_OUTP_ND(0x030C, 0x00);
 	/* Power down PHY */
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 019acce..74f7ead 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -82,6 +82,8 @@
 	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
 };
 
+static struct ion_client *iclient;
+
 u32 msm_fb_debug_enabled;
 /* Setting msm_fb_msg_level to 8 prints out ALL messages */
 u32 msm_fb_msg_level = 7;
@@ -188,12 +190,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 +200,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;
@@ -338,6 +345,13 @@
 		MSM_FB_DEBUG("msm_fb_probe:  phy_Addr = 0x%x virt = 0x%x\n",
 			     (int)fbram_phys, (int)fbram);
 
+		iclient = msm_ion_client_create(-1, pdev->name);
+		if (IS_ERR_OR_NULL(iclient)) {
+			pr_err("msm_ion_client_create() return"
+				" error, val %p\n", iclient);
+			iclient = NULL;
+		}
+
 		msm_fb_resource_initialized = 1;
 		return 0;
 	}
@@ -537,10 +551,13 @@
 static int msm_fb_resume_sub(struct msm_fb_data_type *mfd)
 {
 	int ret = 0;
+	struct msm_fb_panel_data *pdata = NULL;
 
 	if ((!mfd) || (mfd->key != MFD_KEY))
 		return 0;
 
+	pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+
 	/* attach display channel irq if there's any */
 	if (mfd->channel_irq != 0)
 		enable_irq(mfd->channel_irq);
@@ -555,6 +572,9 @@
 				      mfd->op_enable);
 		if (ret)
 			MSM_FB_INFO("msm_fb_resume: can't turn on display!\n");
+	} else {
+		if (pdata->power_ctrl)
+			pdata->power_ctrl(TRUE);
 	}
 
 	return ret;
@@ -790,6 +810,9 @@
 				mfd->panel_power_on = curr_pwr_state;
 
 			mfd->op_enable = TRUE;
+		} else {
+			if (pdata->power_ctrl)
+				pdata->power_ctrl(FALSE);
 		}
 		break;
 	}
@@ -797,6 +820,36 @@
 	return ret;
 }
 
+int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp)
+{
+	struct msm_panel_info *panel_info = &mfd->panel_info;
+	int remainder, yres, offset;
+
+	if (panel_info->mode2_yres != 0) {
+		yres = panel_info->mode2_yres;
+		remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1);
+	} else {
+		yres = panel_info->yres;
+		remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1);
+	}
+
+	if (!remainder)
+		remainder = PAGE_SIZE;
+
+	if (fbi->var.yoffset < yres) {
+		offset = (fbi->var.xoffset * bpp);
+				/* iBuf->buf +=	fbi->var.xoffset * bpp + 0 *
+				yres * fbi->fix.line_length; */
+	} else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
+		offset = (fbi->var.xoffset * bpp + yres *
+		fbi->fix.line_length + PAGE_SIZE - remainder);
+	} else {
+		offset = (fbi->var.xoffset * bpp + 2 * yres *
+		fbi->fix.line_length + 2 * (PAGE_SIZE - remainder));
+	}
+	return offset;
+}
+
 static void msm_fb_fillrect(struct fb_info *info,
 			    const struct fb_fillrect *rect)
 {
@@ -974,6 +1027,9 @@
 	int *id;
 	int fbram_offset;
 	int remainder, remainder_mode2;
+	static int subsys_id[2] = {MSM_SUBSYSTEM_DISPLAY,
+		MSM_SUBSYSTEM_ROTATOR};
+	unsigned int flags = MSM_SUBSYSTEM_MAP_IOVA;
 
 	/*
 	 * fb info initialization
@@ -1114,11 +1170,12 @@
 	/* Make sure all buffers can be addressed on a page boundary by an x
 	 * and y offset */
 
-	remainder = (fix->line_length * panel_info->yres) % PAGE_SIZE;
+	remainder = (fix->line_length * panel_info->yres) & (PAGE_SIZE - 1);
+					/* PAGE_SIZE is a power of 2 */
 	if (!remainder)
 		remainder = PAGE_SIZE;
 	remainder_mode2 = (fix->line_length *
-				panel_info->mode2_yres) % PAGE_SIZE;
+				panel_info->mode2_yres) & (PAGE_SIZE - 1);
 	if (!remainder_mode2)
 		remainder_mode2 = PAGE_SIZE;
 
@@ -1144,10 +1201,14 @@
 	var->xres = panel_info->xres;
 	var->yres = panel_info->yres;
 	var->xres_virtual = panel_info->xres;
-	var->yres_virtual = panel_info->yres * mfd->fb_page;
+	var->yres_virtual = panel_info->yres * mfd->fb_page +
+		((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page;
 	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
 	if (mfd->dest == DISPLAY_LCD) {
-		var->reserved[4] = panel_info->lcd.refx100 / 100;
+		if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
+			var->reserved[4] = panel_info->lcd.refx100 / (100 * 2);
+		else
+			var->reserved[4] = panel_info->lcd.refx100 / 100;
 	} else {
 		if (panel_info->type == MIPI_VIDEO_PANEL) {
 			var->reserved[4] = panel_info->mipi.frame_rate;
@@ -1178,6 +1239,8 @@
 	snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
 #elif defined(CONFIG_FB_MSM_MDP40)
 	snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
+#elif defined(CONFIG_FB_MSM_MDP_NONE)
+	snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id);
 #else
 	error CONFIG_FB_MSM_MDP undefined !
 #endif
@@ -1215,6 +1278,16 @@
 	fbi->screen_base = fbram;
 	fbi->fix.smem_start = (unsigned long)fbram_phys;
 
+	mfd->map_buffer = msm_subsystem_map_buffer(
+		fbi->fix.smem_start, fbi->fix.smem_len,
+		flags, subsys_id, 2);
+	if (mfd->map_buffer) {
+		pr_debug("%s(): buf 0x%lx, mfd->map_buffer->iova[0] 0x%lx\n"
+			"mfd->map_buffer->iova[1] 0x%lx", __func__,
+			fbi->fix.smem_start, mfd->map_buffer->iova[0],
+			mfd->map_buffer->iova[1]);
+	}
+
 	memset(fbi->screen_base, 0x0, fix->smem_len);
 
 	mfd->op_enable = TRUE;
@@ -1414,6 +1487,10 @@
 		printk(KERN_ERR "pm_runtime: fail to wake up\n");
 	}
 
+	if (info->node == 0 && !(mfd->cont_splash_done)) {	/* primary */
+			mfd->ref_cnt++;
+			return 0;
+	}
 
 	if (!mfd->ref_cnt) {
 		mdp_set_dma_pan_info(info, NULL, TRUE);
@@ -1464,8 +1541,9 @@
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct msm_fb_panel_data *pdata;
 
-	if ((!mfd->op_enable) || (!mfd->panel_power_on))
-		return -EPERM;
+	if (info->node != 0 || mfd->cont_splash_done)	/* primary */
+		if ((!mfd->op_enable) || (!mfd->panel_power_on))
+			return -EPERM;
 
 	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
 		return -EINVAL;
@@ -1524,6 +1602,15 @@
 	mutex_unlock(&msm_fb_notify_update_sem);
 
 	down(&msm_fb_pan_sem);
+
+	if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
+		mdp_set_dma_pan_info(info, NULL, TRUE);
+		if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
+			pr_err("%s: can't turn on display!\n", __func__);
+			return -EINVAL;
+		}
+	}
+
 	mdp_set_dma_pan_info(info, dirtyPtr,
 			     (var->activate == FB_ACTIVATE_VBL));
 	mdp_dma_pan_update(info);
@@ -2102,6 +2189,8 @@
 
 		/* blit first region */
 		if (((splitreq.flags & 0x07) == 0x07) ||
+			((splitreq.flags & 0x07) == 0x05) ||
+			((splitreq.flags & 0x07) == 0x02) ||
 			((splitreq.flags & 0x07) == 0x0)) {
 
 			if (splitreq.flags & MDP_ROT_90) {
@@ -2182,6 +2271,8 @@
 
 		/* blit second region */
 		if (((splitreq.flags & 0x07) == 0x07) ||
+			((splitreq.flags & 0x07) == 0x05) ||
+			((splitreq.flags & 0x07) == 0x02) ||
 			((splitreq.flags & 0x07) == 0x0)) {
 			splitreq.src_rect.h = s_h_1;
 			splitreq.src_rect.y = s_y_1;
@@ -2631,6 +2722,14 @@
 	add_timer(&mfd->msmfb_no_update_notify_timer);
 	mutex_unlock(&msm_fb_notify_update_sem);
 
+	if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
+		mdp_set_dma_pan_info(info, NULL, TRUE);
+		if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
+			pr_err("%s: can't turn on display!\n", __func__);
+			return -EINVAL;
+		}
+	}
+
 	ret = mdp4_overlay_play(info, &req);
 
 	if (unset_bl_level && !bl_updated) {
@@ -2932,6 +3031,56 @@
 	return 0;
 }
 
+static int msmfb_handle_pp_ioctl(struct msmfb_mdp_pp *pp_ptr)
+{
+	int ret = -1;
+
+	if (!pp_ptr)
+		return ret;
+
+	switch (pp_ptr->op) {
+#ifdef CONFIG_FB_MSM_MDP40
+	case mdp_op_csc_cfg:
+		ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data));
+		break;
+
+	case mdp_op_pcc_cfg:
+		ret = mdp4_pcc_cfg(&(pp_ptr->data.pcc_cfg_data));
+		break;
+
+	case mdp_op_lut_cfg:
+		switch (pp_ptr->data.lut_cfg_data.lut_type) {
+		case mdp_lut_igc:
+			ret = mdp4_igc_lut_config(
+					(struct mdp_igc_lut_data *)
+					&pp_ptr->data.lut_cfg_data.data);
+			break;
+
+		case mdp_lut_pgc:
+			ret = mdp4_argc_cfg(
+				&pp_ptr->data.lut_cfg_data.data.pgc_lut_data);
+			break;
+
+		case mdp_lut_hist:
+			ret = mdp_hist_lut_config(
+					(struct mdp_hist_lut_data *)
+					&pp_ptr->data.lut_cfg_data.data);
+			break;
+
+		default:
+			break;
+		}
+		break;
+#endif
+	default:
+		pr_warn("Unsupported request to MDP_PP IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
@@ -3225,28 +3374,15 @@
 		ret = -EINVAL;
 #endif
 		break;
+
 	case MSMFB_MDP_PP:
 		ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
 		if (ret)
 			return ret;
 
-		switch (mdp_pp.op) { /*Add PCC and LUT op handling here*/
-#ifdef CONFIG_FB_MSM_MDP40
-		case mdp_op_csc_cfg:
-			ret = mdp4_csc_config((struct mdp_csc_cfg_data *)
-					&(mdp_pp.data));
-			break;
-		case mdp_op_pcc_cfg:
-		case mdp_op_lut_cfg:
-#endif
-		default:
-			pr_warn("%s: Only CSC supported by MDP_PP IOCTL.\n",
-					__func__);
-			ret = -EINVAL;
-			break;
-		}
-
+		ret = msmfb_handle_pp_ioctl(&mdp_pp);
 		break;
+
 	default:
 		MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
 		ret = -EINVAL;
@@ -3338,11 +3474,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;
@@ -3388,11 +3523,7 @@
 	mfd->fb_page = fb_num;
 	mfd->index = fbi_list_index;
 	mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	mfd->iclient = msm_ion_client_create(-1, pdev->name);
-#else
-	mfd->iclient = NULL;
-#endif
+	mfd->iclient = iclient;
 	/* link to the latest pdev */
 	mfd->pdev = this_dev;
 
@@ -3415,19 +3546,32 @@
 }
 EXPORT_SYMBOL(msm_fb_add_device);
 
-int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num)
+int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num,
+	int subsys_id)
 {
 	struct fb_info *info;
+	struct msm_fb_data_type *mfd;
 
-	if (fb_num > MAX_FBI_LIST)
+	if (fb_num > MAX_FBI_LIST ||
+		(subsys_id != DISPLAY_SUBSYSTEM_ID &&
+		 subsys_id != ROTATOR_SUBSYSTEM_ID)) {
+		pr_err("%s(): Invalid parameters\n", __func__);
 		return -1;
+	}
 
 	info = fbi_list[fb_num];
-	if (!info)
+	if (!info) {
+		pr_err("%s(): info is NULL\n", __func__);
 		return -1;
+	}
 
-	*start = info->fix.smem_start;
+	mfd = (struct msm_fb_data_type *)info->par;
+	if (mfd->map_buffer)
+		*start = mfd->map_buffer->iova[subsys_id];
+	else
+		*start = info->fix.smem_start;
 	*len = info->fix.smem_len;
+
 	return 0;
 }
 EXPORT_SYMBOL(get_fb_phys_info);
@@ -3459,4 +3603,58 @@
 	return 0;
 }
 
+/* Called by v4l2 driver to enable/disable overlay pipe */
+int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par)
+{
+	int err = 0;
+#ifdef CONFIG_FB_MSM_MDP40
+	struct mdp4_overlay_pipe *pipe;
+	if (enable) {
+
+		err = mdp4_v4l2_overlay_set(fbi_list[0], req, &pipe);
+
+		*(struct mdp4_overlay_pipe **)par = pipe;
+
+	} else {
+		pipe = *(struct mdp4_overlay_pipe **)par;
+		mdp4_v4l2_overlay_clear(pipe);
+	}
+#else
+#ifdef CONFIG_FB_MSM_MDP30
+	if (enable)
+		err = mdp_ppp_v4l2_overlay_set(fbi_list[0], req);
+	else
+		err = mdp_ppp_v4l2_overlay_clear();
+#else
+	err = -EINVAL;
+#endif
+#endif
+
+	return err;
+}
+EXPORT_SYMBOL(msm_fb_v4l2_enable);
+
+/* Called by v4l2 driver to provide a frame for display */
+int msm_fb_v4l2_update(void *par,
+	unsigned long srcp0_addr, unsigned long srcp0_size,
+	unsigned long srcp1_addr, unsigned long srcp1_size,
+	unsigned long srcp2_addr, unsigned long srcp2_size)
+{
+#ifdef CONFIG_FB_MSM_MDP40
+	struct mdp4_overlay_pipe *pipe = (struct mdp4_overlay_pipe *)par;
+	return mdp4_v4l2_overlay_play(fbi_list[0], pipe,
+		srcp0_addr, srcp1_addr,
+		srcp2_addr);
+#else
+#ifdef CONFIG_FB_MSM_MDP30
+	return mdp_ppp_v4l2_overlay_play(fbi_list[0],
+		srcp0_addr, srcp0_size,
+		srcp1_addr, srcp1_size);
+#else
+	return -EINVAL;
+#endif
+#endif
+}
+EXPORT_SYMBOL(msm_fb_v4l2_update);
+
 module_init(msm_fb_init);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 9837f07..44d5018 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -23,6 +23,7 @@
 #include "linux/proc_fs.h"
 
 #include <mach/hardware.h>
+#include <mach/msm_subsystem_map.h>
 #include <linux/io.h>
 #include <mach/board.h>
 
@@ -171,13 +172,16 @@
 	struct list_head writeback_register_queue;
 	wait_queue_head_t wait_q;
 	struct ion_client *iclient;
+	struct msm_mapped_buffer *map_buffer;
 	struct mdp_buf_type *ov0_wb_buf;
 	struct mdp_buf_type *ov1_wb_buf;
 	u32 ov_start;
 	u32 mem_hid;
 	u32 mdp_rev;
 	u32 use_ov0_blt, ov0_blt_state;
+	u32 use_ov1_blt, ov1_blt_state;
 	u32 writeback_state;
+	int cont_splash_done;
 };
 
 struct dentry *msm_fb_get_debugfs_root(void);
@@ -196,6 +200,7 @@
 int msm_fb_writeback_stop(struct fb_info *info);
 int msm_fb_writeback_terminate(struct fb_info *info);
 int msm_fb_detect_client(const char *name);
+int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp);
 
 #ifdef CONFIG_FB_BACKLIGHT
 void msm_fb_config_backlight(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 903c865..7744e7a 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -86,6 +86,7 @@
 
 struct mddi_panel_info {
 	__u32 vdopkt;
+	boolean is_type1;
 };
 
 struct mipi_panel_info {
@@ -188,6 +189,7 @@
 	/* function entry chain */
 	int (*on) (struct platform_device *pdev);
 	int (*off) (struct platform_device *pdev);
+	int (*power_ctrl) (boolean enable);
 	struct platform_device *next;
 	int (*clk_func) (int enable);
 };
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 1e02a2c..6ebc955 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.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
@@ -88,7 +88,7 @@
 			ddl_context->dram_base_a.align_virtual_addr;
 	}
 	if (!status) {
-		ddl_context->metadata_shared_input.mem_type = DDL_MM_MEM;
+		ddl_context->metadata_shared_input.mem_type = DDL_FW_MEM;
 		ptr = ddl_pmem_alloc(&ddl_context->metadata_shared_input,
 			DDL_METADATA_TOTAL_INPUTBUFSIZE,
 			DDL_LINEAR_BUFFER_ALIGN_BYTES);
@@ -164,14 +164,20 @@
 		DDL_MSG_ERROR("ddl_open:Client_trasac_failed");
 		return status;
 	}
-	ddl->shared_mem[0].mem_type = DDL_CMD_MEM;
+	if (res_trk_check_for_sec_session())
+		ddl->shared_mem[0].mem_type = DDL_CMD_MEM;
+	else
+		ddl->shared_mem[0].mem_type = DDL_FW_MEM;
 	ptr = ddl_pmem_alloc(&ddl->shared_mem[0],
 			DDL_FW_AUX_HOST_CMD_SPACE_SIZE, 0);
 	if (!ptr)
 		status = VCD_ERR_ALLOC_FAIL;
 	if (!status && ddl_context->frame_channel_depth
 		== VCD_DUAL_FRAME_COMMAND_CHANNEL) {
-		ddl->shared_mem[1].mem_type = DDL_CMD_MEM;
+		if (res_trk_check_for_sec_session())
+			ddl->shared_mem[1].mem_type = DDL_CMD_MEM;
+		else
+			ddl->shared_mem[1].mem_type = DDL_FW_MEM;
 		ptr = ddl_pmem_alloc(&ddl->shared_mem[1],
 				DDL_FW_AUX_HOST_CMD_SPACE_SIZE, 0);
 		if (!ptr) {
@@ -289,6 +295,11 @@
 		DDL_MSG_ERROR("ddl_enc_start:Seq_hdr_alloc_failed");
 		return VCD_ERR_ALLOC_FAIL;
 	}
+	msm_ion_do_cache_op(ddl_context->video_ion_client,
+				encoder->seq_header.alloc_handle,
+				encoder->seq_header.virtual_base_addr,
+				encoder->seq_header.buffer_size,
+				ION_IOC_CLEAN_INV_CACHES);
 	if (!ddl_take_command_channel(ddl_context, ddl, client_data))
 		return VCD_ERR_BUSY;
 	ddl_vidc_channel_set(ddl);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index e613f29..c3874fa 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.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
@@ -239,6 +239,7 @@
 	struct vcd_property_intra_refresh_mb_number  intra_refresh;
 	struct vcd_property_buffer_format  buf_format;
 	struct vcd_property_buffer_format  recon_buf_format;
+	struct vcd_property_sps_pps_for_idr_enable sps_pps;
 	struct ddl_buf_addr  seq_header;
 	struct vcd_buffer_requirement  input_buf_req;
 	struct vcd_buffer_requirement  output_buf_req;
@@ -260,7 +261,7 @@
 	u32  mb_info_enable;
 	u32  ext_enc_control_val;
 	u32  num_references_for_p_frame;
-	u32	 closed_gop;
+	u32  closed_gop;
 };
 struct ddl_decoder_data {
 	struct ddl_codec_data_hdr  hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
index 51a0d13..433dad4 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.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
@@ -14,8 +14,8 @@
 #ifndef _VCD_DDL_API_H_
 #define _VCD_DDL_API_H_
 
+#include <media/msm/vcd_api.h>
 #include "vidc.h"
-#include "vcd_api.h"
 
 #define VCD_EVT_RESP_DDL_BASE             0x3000
 #define VCD_EVT_RESP_DEVICE_INIT          (VCD_EVT_RESP_DDL_BASE + 0x1)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index a0d30b6..b4161dd 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -132,4 +132,8 @@
 #define DDL_RESL_CHANGE_INCREASED               1
 #define DDL_RESL_CHANGE_DECREASED               2
 
+#define VIDC_SM_ERR_CONCEALMENT_ENABLE				1
+#define VIDC_SM_ERR_CONCEALMENT_INTER_SLICE_MB_COPY		2
+#define VIDC_SM_ERR_CONCEALMENT_INTRA_SLICE_COLOR_CONCEALMENT	1
+
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
index d658647..a2327d5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.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
@@ -236,7 +236,6 @@
 	case VIDC_1080P_ERROR_PICTURE_STRUCTURE_ERR:
 	case VIDC_1080P_ERROR_SLICE_ADDR_INVALID:
 	case VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED:
-	case VIDC_1080P_ERROR_INCOMPLETE_FRAME:
 	case VIDC_1080P_ERROR_NALU_HEADER_ERROR:
 	case VIDC_1080P_ERROR_SPS_PARSE_ERROR:
 	case VIDC_1080P_ERROR_PPS_PARSE_ERROR:
@@ -309,6 +308,8 @@
 	case VIDC_1080P_WARN_BIT_RATE_NOT_SUPPORTED:
 	case VIDC_1080P_WARN_COLOR_DIFF_FORMAT_NOT_SUPPORTED:
 	case VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER:
+	case VIDC_1080P_WARN_DEBLOCKING_NOT_DONE:
+	case VIDC_1080P_WARN_INCOMPLETE_FRAME:
 	case VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER:
 	case VIDC_1080P_ERROR_ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT:
 	case VIDC_1080P_WARN_METADATA_NO_SPACE_NUM_CONCEAL_MB:
@@ -322,6 +323,9 @@
 	case VIDC_1080P_WARN_METADATA_NO_SPACE_MB_INFO:
 	case VIDC_1080P_WARN_METADATA_NO_SPACE_SLICE_SIZE:
 	case VIDC_1080P_WARN_RESOLUTION_WARNING:
+	case VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE:
+	case VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP:
+	case VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB:
 		status = true;
 		DDL_MSG_ERROR("VIDC_WARNING_IGNORED");
 	break;
@@ -626,6 +630,12 @@
 	case VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER:
 		string = "VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER";
 	break;
+	case VIDC_1080P_WARN_DEBLOCKING_NOT_DONE:
+		string = "VIDC_1080P_WARN_DEBLOCKING_NOT_DONE";
+	break;
+	case VIDC_1080P_WARN_INCOMPLETE_FRAME:
+		string = "VIDC_1080P_WARN_INCOMPLETE_FRAME";
+	break;
 	case VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER:
 		string = "VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER";
 	break;
@@ -666,6 +676,15 @@
 	case VIDC_1080P_WARN_RESOLUTION_WARNING:
 		string = "VIDC_1080P_WARN_RESOLUTION_WARNING";
 	break;
+	case VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE:
+		string = "VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE";
+	break;
+	case VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP:
+		string = "VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP";
+	break;
+	case VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB:
+		string = "VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB";
+	break;
 	}
 	if (string)
 		DDL_MSG_ERROR("Error code = 0x%x : %s", error_code, string);
@@ -733,9 +752,6 @@
 	case VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED:
 		string = "VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED";
 	break;
-	case VIDC_1080P_ERROR_INCOMPLETE_FRAME:
-		string = "VIDC_1080P_ERROR_INCOMPLETE_FRAME";
-	break;
 	case VIDC_1080P_ERROR_NALU_HEADER_ERROR:
 		string = "VIDC_1080P_ERROR_NALU_HEADER_ERROR";
 	break;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 75df48d..b720800 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -14,7 +14,7 @@
 #include <mach/msm_memtypes.h>
 #include "vcd_ddl.h"
 #include "vcd_ddl_shared_mem.h"
-
+#include "vcd_res_tracker_api.h"
 
 struct ddl_context *ddl_get_context(void)
 {
@@ -248,7 +248,8 @@
 	if (dpb > DDL_MAX_BUFFER_COUNT)
 		dpb = DDL_MAX_BUFFER_COUNT;
 	for (i = 0; i < dpb; i++) {
-		if (frame[i].vcd_frm.virtual) {
+		if (!(res_trk_check_for_sec_session()) &&
+			frame[i].vcd_frm.virtual) {
 			if (luma_size <= frame[i].vcd_frm.alloc_len) {
 				memset(frame[i].vcd_frm.virtual,
 					 0x10101010, luma_size);
@@ -256,13 +257,14 @@
 					 0x80808080,
 					frame[i].vcd_frm.alloc_len - luma_size);
 				if (frame[i].vcd_frm.ion_flag == CACHED) {
-					clean_and_invalidate_caches(
-					(unsigned long)frame[i].
+					msm_ion_do_cache_op(
+					ddl_context->video_ion_client,
+					frame[i].vcd_frm.buff_ion_handle,
+					(unsigned long *)frame[i].
 					vcd_frm.virtual,
 					(unsigned long)frame[i].
 					vcd_frm.alloc_len,
-					(unsigned long)frame[i].
-					vcd_frm.physical);
+					ION_IOC_CLEAN_INV_CACHES);
 				}
 			} else {
 				DDL_MSG_ERROR("luma size error");
@@ -639,6 +641,7 @@
 	u32 status = VCD_S_SUCCESS, dpb = 0;
 	u32 width = 0, height = 0;
 	u8 *ptr;
+	struct ddl_context *ddl_context = ddl->ddl_context;
 
 	dec_bufs = &ddl->codec_data.decoder.hw_bufs;
 	ddl_calc_dec_hw_buffers_size(ddl->codec_data.decoder.
@@ -649,6 +652,11 @@
 			DDL_KILO_BYTE(2));
 		if (!ptr)
 			status = VCD_ERR_ALLOC_FAIL;
+		msm_ion_do_cache_op(ddl_context->video_ion_client,
+					dec_bufs->context.alloc_handle,
+					dec_bufs->context.virtual_base_addr,
+					dec_bufs->context.buffer_size,
+					ION_IOC_CLEAN_INV_CACHES);
 	}
 	if (buf_size.sz_nb_ip > 0) {
 		dec_bufs->h264_nb_ip.mem_type = DDL_MM_MEM;
@@ -726,9 +734,18 @@
 			DDL_KILO_BYTE(2));
 		if (!ptr)
 			status = VCD_ERR_ALLOC_FAIL;
-		else
-			memset(dec_bufs->desc.align_virtual_addr,
-				   0, buf_size.sz_desc);
+		else {
+			if (!res_trk_check_for_sec_session()) {
+				memset(dec_bufs->desc.align_virtual_addr,
+					   0, buf_size.sz_desc);
+				msm_ion_do_cache_op(
+						ddl_context->video_ion_client,
+						dec_bufs->desc.alloc_handle,
+						dec_bufs->desc.alloc_handle,
+						dec_bufs->desc.buffer_size,
+						ION_IOC_CLEAN_INV_CACHES);
+			}
+		}
 	}
 	if (status)
 		ddl_free_dec_hw_buffers(ddl);
@@ -767,7 +784,7 @@
 		sz_strm = DDL_ALIGN(ddl_get_yuv_buf_size(width, height,
 			DDL_YUV_BUF_TYPE_LINEAR) + ddl_get_yuv_buf_size(width,
 			height/2, DDL_YUV_BUF_TYPE_LINEAR), DDL_KILO_BYTE(4));
-		sz_mv = DDL_ALIGN(2 * mb_x * 8, DDL_KILO_BYTE(2));
+		sz_mv = DDL_ALIGN(2 * mb_x * mb_y * 8, DDL_KILO_BYTE(2));
 		if ((codec == VCD_CODEC_MPEG4) ||
 			(codec == VCD_CODEC_H264)) {
 			sz_col_zero = DDL_ALIGN(((mb_x * mb_y + 7) / 8) *
@@ -830,6 +847,7 @@
 	struct ddl_enc_buffer_size buf_size;
 	void *ptr;
 	u32 status = VCD_S_SUCCESS;
+	struct ddl_context *ddl_context = ddl->ddl_context;
 
 	enc_bufs = &ddl->codec_data.encoder.hw_bufs;
 	enc_bufs->dpb_count = DDL_ENC_MIN_DPB_BUFFERS;
@@ -908,6 +926,11 @@
 				buf_size.sz_context, DDL_KILO_BYTE(2));
 			if (!ptr)
 				status = VCD_ERR_ALLOC_FAIL;
+			msm_ion_do_cache_op(ddl_context->video_ion_client,
+					enc_bufs->context.alloc_handle,
+					enc_bufs->context.virtual_base_addr,
+					enc_bufs->context.buffer_size,
+					ION_IOC_CLEAN_INV_CACHES);
 		}
 		if (status)
 			ddl_free_enc_hw_buffers(ddl);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 8eba8bd..830c777c3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1236,6 +1236,9 @@
 		if (vidc_msg_timing)
 			ddl_calc_core_proc_time(__func__, DEC_OP_TIME);
 		ddl_process_decoder_metadata(ddl);
+		vidc_sm_get_aspect_ratio_info(
+			&ddl->shared_mem[ddl->command_channel],
+			&output_vcd_frm->aspect_ratio_info);
 		ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
 			vcd_status, output_frame,
 			sizeof(struct ddl_frame_data_tag),
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..d6749e2 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -915,14 +915,34 @@
 	}
 	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;
 		break;
+	case VCD_I_ENABLE_SPS_PPS_FOR_IDR:
+	{
+		struct vcd_property_sps_pps_for_idr_enable *sps_pps =
+		(struct vcd_property_sps_pps_for_idr_enable *) property_value;
+
+		if ((sizeof(struct vcd_property_sps_pps_for_idr_enable)) ==
+		property_hdr->sz) {
+			DDL_MSG_LOW("SPS PPS generation for IDR Encode "
+				"is Requested");
+			encoder->sps_pps.sps_pps_for_idr_enable_flag =
+			sps_pps->sps_pps_for_idr_enable_flag;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
 	default:
 		DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1387,6 +1407,14 @@
 			property_value);
 		vcd_status = VCD_S_SUCCESS;
 	break;
+	case VCD_I_ENABLE_SPS_PPS_FOR_IDR:
+		if (sizeof(struct vcd_property_sps_pps_for_idr_enable) ==
+			property_hdr->sz) {
+			*(struct vcd_property_sps_pps_for_idr_enable *)
+				property_value = encoder->sps_pps;
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1736,7 +1764,7 @@
 	}
 	memset(output_buf_req, 0,
 		sizeof(struct vcd_buffer_requirement));
-	if (!estimate && !decoder->idr_only_decoding && !decoder->cont_mode)
+	if (!decoder->idr_only_decoding && !decoder->cont_mode)
 		output_buf_req->actual_count = min_dpb + 4;
 	else
 		output_buf_req->actual_count = min_dpb;
@@ -1836,8 +1864,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;
 }
 
@@ -1946,5 +1982,6 @@
 		encoder->frame_rate.fps_numerator = DDL_INITIAL_FRAME_RATE;
 		encoder->frame_rate.fps_denominator = 1;
 		ddl_set_default_enc_property(ddl);
+		encoder->sps_pps.sps_pps_for_idr_enable_flag = false;
 	}
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index f8977e9..cce779e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.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
@@ -85,6 +85,8 @@
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT    16
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK  0x80
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT  7
+#define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK    0X100
+#define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_SHFT    8
 #define VIDC_SM_ENC_EXT_CTRL_SEQ_HDR_CTRL_BMSK       0x8
 #define VIDC_SM_ENC_EXT_CTRL_SEQ_HDR_CTRL_SHFT       3
 #define VIDC_SM_ENC_EXT_CTRL_FRAME_SKIP_ENABLE_BMSK  0x6
@@ -182,6 +184,14 @@
 #define VIDC_SM_METADATA_ENABLE_QP_BMSK              0x1
 #define VIDC_SM_METADATA_ENABLE_QP_SHFT              0
 
+#define VIDC_SM_ASPECT_RATIO_INFO_ADDR               0x00c8
+#define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK         0xf
+#define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT         0x0
+#define VIDC_SM_EXTENDED_PAR_ADDR                    0x00cc
+#define VIDC_SM_EXTENDED_PAR_WIDTH_BMSK              0xffff0000
+#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT              0xf
+#define VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK             0x0000ffff
+#define VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT             0x0
 
 #define VIDC_SM_METADATA_STATUS_ADDR         0x003c
 #define VIDC_SM_METADATA_STATUS_STATUS_BMSK  0x1
@@ -200,10 +210,21 @@
 #define VIDC_SM_CHROMA_ADDR_CHANGE_BMASK  0x00000001
 #define VIDC_SM_CHROMA_ADDR_CHANGE_SHFT   0
 
+#define VIDC_SM_ERROR_CONCEALMENT_CONFIG_ADDR   0x0154
+
+#define VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTER_SLICE_BMSK  0x0c
+#define VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTER_SLICE_SHFT 2
+#define VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTRA_SLICE_BMSK 0X02
+#define VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTRA_SLICE_SHFT 1
+#define VIDC_SM_ERROR_CONCEALMENT_CONFIG_CONCEAL_ENABLE_BMSK  0x01
+#define VIDC_SM_ERROR_CONCEALMENT_CONFIG_CONCEAL_ENABLE_SHFT   0
+
 #define VIDC_SM_SEI_ENABLE_ADDR                     0x0180
 #define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_BMSK  0x00000001
 #define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_SHFT  0
 
+#define VIDC_SM_NUM_STUFF_BYTES_CONSUME_ADDR    0X01ac
+
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK	0x40
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT	6
 
@@ -352,7 +373,7 @@
 	*shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip frame_skip_mode,
 	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
-	u32 closed_gop_enable)
+	u32 sps_pps_control, u32 closed_gop_enable)
 {
 	u32 enc_ctrl;
 
@@ -371,6 +392,9 @@
 			VIDC_SETFIELD((cpcfc_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT,
 			VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK) |
+			VIDC_SETFIELD((sps_pps_control) ? 1 : 0,
+			VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK) |
 			VIDC_SETFIELD(closed_gop_enable,
 			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
 			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK);
@@ -725,3 +749,53 @@
 {
 	*sei_enable = DDL_MEM_READ_32(shared_mem, VIDC_SM_SEI_ENABLE_ADDR);
 }
+
+void vidc_sm_set_error_concealment_config(struct ddl_buf_addr *shared_mem,
+	u32 inter_slice, u32 intra_slice, u32 conceal_config_enable)
+{
+	u32 error_conceal_config = 0;
+
+	error_conceal_config = VIDC_SETFIELD(inter_slice,
+			VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTER_SLICE_SHFT,
+			VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTER_SLICE_BMSK);
+
+	error_conceal_config |= VIDC_SETFIELD(intra_slice,
+			VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTRA_SLICE_SHFT,
+			VIDC_SM_ERROR_CONCEALMENT_CONFIG_INTRA_SLICE_BMSK);
+
+	error_conceal_config |= VIDC_SETFIELD(conceal_config_enable,
+			VIDC_SM_ERROR_CONCEALMENT_CONFIG_CONCEAL_ENABLE_SHFT,
+			VIDC_SM_ERROR_CONCEALMENT_CONFIG_CONCEAL_ENABLE_BMSK);
+
+	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ERROR_CONCEALMENT_CONFIG_ADDR,
+			error_conceal_config);
+}
+
+void vidc_sm_set_decoder_stuff_bytes_consumption(
+	struct ddl_buf_addr *shared_mem,
+	enum vidc_sm_num_stuff_bytes_consume_info consume_info)
+{
+	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_NUM_STUFF_BYTES_CONSUME_ADDR,
+	consume_info);
+}
+
+void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
+	struct vcd_aspect_ratio *aspect_ratio_info)
+{
+	u32 extended_par_info = 0;
+	aspect_ratio_info->aspect_ratio = DDL_MEM_READ_32(shared_mem,
+				VIDC_SM_ASPECT_RATIO_INFO_ADDR);
+
+	if (aspect_ratio_info->aspect_ratio == 0x0f) {
+		extended_par_info = DDL_MEM_READ_32(shared_mem,
+			VIDC_SM_EXTENDED_PAR_ADDR);
+		aspect_ratio_info->extended_par_width =
+			VIDC_GETFIELD(extended_par_info,
+			VIDC_SM_EXTENDED_PAR_WIDTH_BMSK,
+			VIDC_SM_EXTENDED_PAR_WIDTH_SHFT);
+		aspect_ratio_info->extended_par_height =
+			VIDC_GETFIELD(extended_par_info,
+			VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK,
+			VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
+	}
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 78bfee5..b0e6758 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.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
@@ -73,6 +73,11 @@
 	VIDC_SM_PROFILE_INFO_MAX      = 0x7fffffff
 };
 
+enum vidc_sm_num_stuff_bytes_consume_info {
+	VIDC_SM_NUM_STUFF_BYTES_CONSUME_ALL  = 0x0,
+	VIDC_SM_NUM_STUFF_BYTES_CONSUME_NONE = 0xffffffff
+};
+
 void vidc_sm_get_extended_decode_status(struct ddl_buf_addr *shared_mem,
 	u32 *more_field_needed,
 	u32 *resl_change);
@@ -100,7 +105,8 @@
 void vidc_sm_set_extended_encoder_control(
 	struct ddl_buf_addr *shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
-	u32 vbv_buffer_size, u32 cpcfc_enable, u32 closed_gop_enable);
+	u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
+	u32 closed_gop_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
@@ -168,4 +174,11 @@
 	u32 sei_enable);
 void vidc_sm_get_decoder_sei_enable(struct ddl_buf_addr *shared_mem,
 	u32 *sei_enable);
+void vidc_sm_set_error_concealment_config(struct ddl_buf_addr *shared_mem,
+	u32 inter_slice, u32 intra_slice, u32 conceal_config_enable);
+void vidc_sm_set_decoder_stuff_bytes_consumption(
+	struct ddl_buf_addr *shared_mem,
+	enum vidc_sm_num_stuff_bytes_consume_info consume_info);
+void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
+	struct vcd_aspect_ratio *aspect_ratio_info);
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 7ccf4c2..6aa7451 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -23,7 +23,6 @@
 };
 static struct time_data proc_time[MAX_TIME_DATA];
 #define DDL_MSG_TIME(x...) printk(KERN_DEBUG x)
-
 static unsigned int vidc_mmu_subsystem[] =	{
 		MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
 
@@ -37,13 +36,16 @@
 #endif
 void *ddl_pmem_alloc(struct ddl_buf_addr *addr, size_t sz, u32 alignment)
 {
-	u32 alloc_size, offset = 0, flags = 0;
+	u32 alloc_size, offset = 0 ;
 	u32 index = 0;
 	struct ddl_context *ddl_context;
 	struct msm_mapped_buffer *mapped_buffer = NULL;
-	int rc = -EINVAL;
-	ion_phys_addr_t phyaddr = 0;
-	size_t len = 0;
+	unsigned long iova = 0;
+	unsigned long buffer_size = 0;
+	unsigned long *kernel_vaddr = NULL;
+	unsigned long ionflag = 0;
+	unsigned long flags = 0;
+	int ret = 0;
 	DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
 	if (!addr) {
 		DDL_MSG_ERROR("\n%s() Invalid Parameters", __func__);
@@ -61,6 +63,7 @@
 						 __func__);
 			goto bail_out;
 		}
+		alloc_size = (alloc_size+4095) & ~4095;
 		addr->alloc_handle = ion_alloc(
 		ddl_context->video_ion_client, alloc_size, SZ_4K,
 			res_trk_get_mem_type());
@@ -69,15 +72,48 @@
 						 __func__);
 			goto bail_out;
 		}
-		rc = ion_phys(ddl_context->video_ion_client,
-				addr->alloc_handle, &phyaddr,
-				 &len);
-		if (rc || !phyaddr) {
+		if (res_trk_check_for_sec_session() ||
+			addr->mem_type == DDL_FW_MEM)
+			ionflag = UNCACHED;
+		else
+			ionflag = CACHED;
+		kernel_vaddr = (unsigned long *) ion_map_kernel(
+					ddl_context->video_ion_client,
+					addr->alloc_handle, ionflag);
+		if (IS_ERR_OR_NULL(kernel_vaddr)) {
+				DDL_MSG_ERROR("%s() :DDL ION map failed\n",
+							 __func__);
+				goto free_ion_alloc;
+		}
+		addr->virtual_base_addr = (u8 *) kernel_vaddr;
+		ret = ion_map_iommu(ddl_context->video_ion_client,
+				addr->alloc_handle,
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL,
+				SZ_4K,
+				0,
+				&iova,
+				&buffer_size,
+				UNCACHED, 0);
+		if (ret) {
+			DDL_MSG_ERROR("%s():DDL ION ion map iommu failed\n",
+						 __func__);
+			goto unmap_ion_alloc;
+		}
+		addr->alloced_phys_addr = (phys_addr_t) iova;
+		if (!addr->alloced_phys_addr) {
 			DDL_MSG_ERROR("%s():DDL ION client physical failed\n",
 						 __func__);
-			goto free_acm_ion_alloc;
+			goto unmap_ion_alloc;
 		}
-		addr->alloced_phys_addr = phyaddr;
+		addr->mapped_buffer = NULL;
+		addr->physical_base_addr = (u8 *) iova;
+		addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
+			addr->physical_base_addr, alignment);
+		offset = (u32)(addr->align_physical_addr -
+				addr->physical_base_addr);
+		addr->align_virtual_addr = addr->virtual_base_addr + offset;
+		addr->buffer_size = alloc_size;
 	} else {
 		addr->alloced_phys_addr = (phys_addr_t)
 		allocate_contiguous_memory_nomap(alloc_size,
@@ -87,51 +123,52 @@
 					 __func__, alloc_size);
 			goto bail_out;
 		}
-	}
-	flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
-	if (alignment == DDL_KILO_BYTE(128))
-			index = 1;
-	else if (alignment > SZ_4K)
-		flags |= MSM_SUBSYSTEM_ALIGN_IOVA_8K;
+		flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
+		if (alignment == DDL_KILO_BYTE(128))
+				index = 1;
+		else if (alignment > SZ_4K)
+			flags |= MSM_SUBSYSTEM_ALIGN_IOVA_8K;
 
-	addr->mapped_buffer =
-	msm_subsystem_map_buffer((unsigned long)addr->alloced_phys_addr,
-	alloc_size, flags, &vidc_mmu_subsystem[index],
-	sizeof(vidc_mmu_subsystem[index])/sizeof(unsigned int));
-	if (IS_ERR(addr->mapped_buffer)) {
-		pr_err(" %s() buffer map failed", __func__);
-		goto free_acm_ion_alloc;
+		addr->mapped_buffer =
+		msm_subsystem_map_buffer((unsigned long)addr->alloced_phys_addr,
+			alloc_size, flags, &vidc_mmu_subsystem[index],
+			sizeof(vidc_mmu_subsystem[index])/sizeof(unsigned int));
+		if (IS_ERR(addr->mapped_buffer)) {
+			pr_err(" %s() buffer map failed", __func__);
+			goto free_acm_alloc;
+		}
+		mapped_buffer = addr->mapped_buffer;
+		if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
+			pr_err("%s() map buffers failed\n", __func__);
+			goto free_map_buffers;
+		}
+		addr->physical_base_addr = (u8 *)mapped_buffer->iova[0];
+		addr->virtual_base_addr = mapped_buffer->vaddr;
+		addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
+			addr->physical_base_addr, alignment);
+		offset = (u32)(addr->align_physical_addr -
+				addr->physical_base_addr);
+		addr->align_virtual_addr = addr->virtual_base_addr + offset;
+		addr->buffer_size = sz;
 	}
-	mapped_buffer = addr->mapped_buffer;
-	if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
-		pr_err("%s() map buffers failed\n", __func__);
-		goto free_map_buffers;
-	}
-	addr->physical_base_addr = (u8 *)mapped_buffer->iova[0];
-	addr->virtual_base_addr = mapped_buffer->vaddr;
-	addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
-		addr->physical_base_addr, alignment);
-	offset = (u32)(addr->align_physical_addr -
-			addr->physical_base_addr);
-	addr->align_virtual_addr = addr->virtual_base_addr + offset;
-	addr->buffer_size = sz;
 	return addr->virtual_base_addr;
-
 free_map_buffers:
 	msm_subsystem_unmap_buffer(addr->mapped_buffer);
 	addr->mapped_buffer = NULL;
-free_acm_ion_alloc:
-	if (ddl_context->video_ion_client) {
-		if (addr->alloc_handle) {
-			ion_free(ddl_context->video_ion_client,
-				addr->alloc_handle);
-			addr->alloc_handle = NULL;
-		}
-	} else {
+free_acm_alloc:
 		free_contiguous_memory_by_paddr(
 			(unsigned long)addr->alloced_phys_addr);
 		addr->alloced_phys_addr = (phys_addr_t)NULL;
-	}
+		return NULL;
+unmap_ion_alloc:
+	ion_unmap_kernel(ddl_context->video_ion_client,
+		addr->alloc_handle);
+	addr->virtual_base_addr = NULL;
+	addr->alloced_phys_addr = (phys_addr_t)NULL;
+free_ion_alloc:
+	ion_free(ddl_context->video_ion_client,
+		addr->alloc_handle);
+	addr->alloc_handle = NULL;
 bail_out:
 	return NULL;
 }
@@ -146,16 +183,22 @@
 	}
 	if (ddl_context->video_ion_client) {
 		if (!IS_ERR_OR_NULL(addr->alloc_handle)) {
+			ion_unmap_kernel(ddl_context->video_ion_client,
+					addr->alloc_handle);
+			ion_unmap_iommu(ddl_context->video_ion_client,
+					addr->alloc_handle,
+					VIDEO_DOMAIN,
+					VIDEO_MAIN_POOL);
 			ion_free(ddl_context->video_ion_client,
 				addr->alloc_handle);
-		}
+			}
 	} else {
+		if (addr->mapped_buffer)
+			msm_subsystem_unmap_buffer(addr->mapped_buffer);
 		if (addr->alloced_phys_addr)
 			free_contiguous_memory_by_paddr(
 				(unsigned long)addr->alloced_phys_addr);
 	}
-	if (addr->mapped_buffer)
-		msm_subsystem_unmap_buffer(addr->mapped_buffer);
 	memset(addr, 0, sizeof(struct ddl_buf_addr));
 }
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index 42a991c..10b3404 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.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
@@ -15,7 +15,7 @@
 #define _VCD_DDL_UTILS_H_
 
 #include <linux/delay.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 
 extern u32 vidc_msg_pmem;
 extern u32 vidc_msg_timing;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index ab50258..66e129c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.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
@@ -197,6 +197,13 @@
 	vidc_1080p_set_decode_mpeg4_pp_filter(decoder->post_filter.post_filter);
 	vidc_sm_set_concealment_color(&ddl->shared_mem[ddl->command_channel],
 		DDL_CONCEALMENT_Y_COLOR, DDL_CONCEALMENT_C_COLOR);
+
+	vidc_sm_set_error_concealment_config(
+		&ddl->shared_mem[ddl->command_channel],
+		VIDC_SM_ERR_CONCEALMENT_INTER_SLICE_MB_COPY,
+		VIDC_SM_ERR_CONCEALMENT_INTRA_SLICE_COLOR_CONCEALMENT,
+		VIDC_SM_ERR_CONCEALMENT_ENABLE);
+
 	ddl_vidc_metadata_enable(ddl);
 	vidc_sm_set_metadata_start_address(&ddl->shared_mem
 		[ddl->command_channel],
@@ -256,6 +263,10 @@
 			VIDC_SM_RECOVERY_POINT_SEI);
 	ddl_context->vidc_decode_seq_start[ddl->command_channel](
 		&seq_start_param);
+
+	vidc_sm_set_decoder_stuff_bytes_consumption(
+		&ddl->shared_mem[ddl->command_channel],
+		VIDC_SM_NUM_STUFF_BYTES_CONSUME_NONE);
 }
 
 void ddl_vidc_decode_dynamic_property(struct ddl_client_context *ddl,
@@ -541,7 +552,8 @@
 	vidc_sm_set_extended_encoder_control(&ddl->shared_mem
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
-		h263_cpfc_enable, encoder->closed_gop);
+		h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
+		encoder->closed_gop);
 	vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
 		[ddl->command_channel],
 		encoder->target_bit_rate.target_bitrate);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 55db33c..7573ee8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.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
@@ -94,7 +94,6 @@
 #define VIDC_1080P_ERROR_SLICE_ADDR_INVALID       121
 #define VIDC_1080P_ERROR_NON_PAIRED_FIELD_NOT_SUPPORTED         122
 #define VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED                123
-#define VIDC_1080P_ERROR_INCOMPLETE_FRAME                       124
 #define VIDC_1080P_ERROR_NO_BUFFER_RELEASED_FROM_HOST           125
 #define VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER             126
 #define VIDC_1080P_ERROR_ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT     127
@@ -126,10 +125,16 @@
 #define VIDC_1080P_WARN_BIT_RATE_NOT_SUPPORTED           168
 #define VIDC_1080P_WARN_COLOR_DIFF_FORMAT_NOT_SUPPORTED  169
 #define VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER      170
+#define VIDC_1080P_WARN_DEBLOCKING_NOT_DONE              178
+#define VIDC_1080P_WARN_INCOMPLETE_FRAME                 179
 #define VIDC_1080P_WARN_METADATA_NO_SPACE_MB_INFO        180
 #define VIDC_1080P_WARN_METADATA_NO_SPACE_SLICE_SIZE     181
 #define VIDC_1080P_WARN_RESOLUTION_WARNING               182
 
+#define VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE           183
+#define VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP         190
+#define VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB     191
+
 #define VIDC_1080P_H264_ENC_TYPE_P       0
 #define VIDC_1080P_H264_ENC_TYPE_B       1
 #define VIDC_1080P_H264_ENC_TYPE_IDR     2
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 c32ac81..708d34f 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
@@ -21,9 +21,9 @@
 #include <linux/interrupt.h>
 #include <linux/memory_alloc.h>
 #include <asm/sizes.h>
+#include <media/msm/vidc_init.h>
 #include "vidc.h"
 #include "vcd_res_tracker.h"
-#include "vidc_init.h"
 
 static unsigned int vidc_clk_table[3] = {
 	48000000, 133330000, 200000000
@@ -58,40 +58,88 @@
 	u32 index = 0;
 	struct ddl_context *ddl_context;
 	struct msm_mapped_buffer *mapped_buffer = NULL;
-	ddl_context = ddl_get_context();
-	if (!addr->alloced_phys_addr) {
-		pr_err(" %s() alloced addres NULL", __func__);
-		goto bail_out;
-	}
-	flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
-	if (alignment == DDL_KILO_BYTE(128))
-			index = 1;
-	else if (alignment > SZ_4K)
-		flags |= MSM_SUBSYSTEM_ALIGN_IOVA_8K;
+	int ret = 0;
+	unsigned long iova = 0;
+	unsigned long buffer_size  = 0;
+	unsigned long *kernel_vaddr = NULL;
 
-	addr->mapped_buffer =
-	msm_subsystem_map_buffer((unsigned long)addr->alloced_phys_addr,
-	sz, flags, &restrk_mmu_subsystem[index],
-	sizeof(restrk_mmu_subsystem[index])/sizeof(unsigned int));
-	if (IS_ERR(addr->mapped_buffer)) {
-		pr_err(" %s() buffer map failed", __func__);
-		goto bail_out;
-	}
-	mapped_buffer = addr->mapped_buffer;
-	if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
-		pr_err("%s() map buffers failed\n", __func__);
-		goto bail_out;
-	}
-	addr->physical_base_addr = (u8 *)mapped_buffer->iova[0];
-	addr->virtual_base_addr = mapped_buffer->vaddr;
-	addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
+	ddl_context = ddl_get_context();
+	if (res_trk_get_enable_ion()) {
+		kernel_vaddr = (unsigned long *) ion_map_kernel(
+					ddl_context->video_ion_client,
+					addr->alloc_handle, UNCACHED);
+		if (IS_ERR_OR_NULL(kernel_vaddr)) {
+			DDL_MSG_ERROR("%s():DDL ION client map failed\n",
+						 __func__);
+			goto ion_bail_out;
+		}
+		addr->virtual_base_addr = (u8 *) kernel_vaddr;
+		ret = ion_map_iommu(ddl_context->video_ion_client,
+				addr->alloc_handle,
+				VIDEO_DOMAIN,
+				VIDEO_FIRMWARE_POOL,
+				SZ_4K,
+				0,
+				&iova,
+				&buffer_size,
+				UNCACHED, 0);
+		if (ret) {
+			DDL_MSG_ERROR("%s():DDL ION client iommu map failed\n",
+						 __func__);
+			goto ion_unmap_bail_out;
+		}
+		addr->mapped_buffer = NULL;
+		addr->physical_base_addr = (u8 *)iova;
+		addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
 		addr->physical_base_addr, alignment);
-	offset = (u32)(addr->align_physical_addr -
-			addr->physical_base_addr);
-	addr->align_virtual_addr = addr->virtual_base_addr + offset;
-	addr->buffer_size = sz;
+		offset = (u32)(addr->align_physical_addr -
+				addr->physical_base_addr);
+		addr->align_virtual_addr = addr->virtual_base_addr + offset;
+		addr->buffer_size = buffer_size;
+	} else {
+		if (!addr->alloced_phys_addr) {
+			pr_err(" %s() alloced addres NULL", __func__);
+			goto bail_out;
+		}
+		flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
+		if (alignment == DDL_KILO_BYTE(128))
+				index = 1;
+		else if (alignment > SZ_4K)
+			flags |= MSM_SUBSYSTEM_ALIGN_IOVA_8K;
+
+		addr->mapped_buffer =
+		msm_subsystem_map_buffer((unsigned long)addr->alloced_phys_addr,
+		sz, flags, &restrk_mmu_subsystem[index],
+		sizeof(restrk_mmu_subsystem[index])/sizeof(unsigned int));
+		if (IS_ERR(addr->mapped_buffer)) {
+			pr_err(" %s() buffer map failed", __func__);
+			goto bail_out;
+		}
+		mapped_buffer = addr->mapped_buffer;
+		if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
+			pr_err("%s() map buffers failed\n", __func__);
+			goto bail_out;
+		}
+		addr->physical_base_addr = (u8 *)mapped_buffer->iova[0];
+		addr->virtual_base_addr = mapped_buffer->vaddr;
+		addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
+		addr->physical_base_addr, alignment);
+		offset = (u32)(addr->align_physical_addr -
+				addr->physical_base_addr);
+		addr->align_virtual_addr = addr->virtual_base_addr + offset;
+		addr->buffer_size = sz;
+	}
 	return addr->virtual_base_addr;
 bail_out:
+	if (addr->mapped_buffer)
+		msm_subsystem_unmap_buffer(addr->mapped_buffer);
+	return NULL;
+ion_unmap_bail_out:
+	if (!IS_ERR_OR_NULL(addr->alloc_handle)) {
+		ion_unmap_kernel(resource_context.
+			res_ion_client,	addr->alloc_handle);
+	}
+ion_bail_out:
 	return NULL;
 }
 
@@ -100,9 +148,6 @@
 {
 	u32 alloc_size;
 	struct ddl_context *ddl_context;
-	int rc = -EINVAL;
-	ion_phys_addr_t phyaddr = 0;
-	size_t len = 0;
 	DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
 	if (!addr) {
 		DDL_MSG_ERROR("\n%s() Invalid Parameters", __func__);
@@ -120,23 +165,16 @@
 						 __func__);
 			goto bail_out;
 		}
+		alloc_size = (alloc_size+4095) & ~4095;
 		addr->alloc_handle = ion_alloc(
 		ddl_context->video_ion_client, alloc_size, SZ_4K,
 			res_trk_get_mem_type());
 		if (IS_ERR_OR_NULL(addr->alloc_handle)) {
 			DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
 						 __func__);
-			goto bail_out;
-		}
-		rc = ion_phys(ddl_context->video_ion_client,
-				addr->alloc_handle, &phyaddr,
-				 &len);
-		if (rc || !phyaddr) {
-			DDL_MSG_ERROR("%s():DDL ION client physical failed\n",
-						 __func__);
 			goto free_acm_ion_alloc;
 		}
-		addr->alloced_phys_addr = phyaddr;
+		return (void *) addr->alloc_handle;
 	} else {
 		addr->alloced_phys_addr = (phys_addr_t)
 		allocate_contiguous_memory_nomap(alloc_size,
@@ -146,10 +184,10 @@
 					 __func__, alloc_size);
 			goto bail_out;
 		}
+		addr->buffer_size = sz;
+		return (void *)addr->alloced_phys_addr;
 	}
 
-	addr->buffer_size = sz;
-	return (void *)addr->alloced_phys_addr;
 
 free_acm_ion_alloc:
 	if (ddl_context->video_ion_client) {
@@ -169,7 +207,18 @@
 		pr_err("%s() invalid args\n", __func__);
 		return;
 	}
-	if (addr->mapped_buffer)
+	if (!IS_ERR_OR_NULL(addr->alloc_handle)) {
+		if (addr->physical_base_addr) {
+			ion_unmap_kernel(resource_context.res_ion_client,
+					addr->alloc_handle);
+			ion_unmap_iommu(resource_context.res_ion_client,
+				addr->alloc_handle,
+				VIDEO_DOMAIN,
+				VIDEO_FIRMWARE_POOL);
+			addr->virtual_base_addr = NULL;
+			addr->physical_base_addr = NULL;
+		}
+	} else if (addr->mapped_buffer)
 		msm_subsystem_unmap_buffer(addr->mapped_buffer);
 	addr->mapped_buffer = NULL;
 }
@@ -595,8 +644,9 @@
 			VIDC_FW_SIZE, DDL_KILO_BYTE(128))) {
 			pr_err("%s() Firmware buffer allocation failed",
 				   __func__);
-			memset(&resource_context.firmware_addr, 0,
-			   sizeof(resource_context.firmware_addr));
+			if (!res_trk_check_for_sec_session())
+				memset(&resource_context.firmware_addr, 0,
+				sizeof(resource_context.firmware_addr));
 		}
 	}
 }
@@ -628,8 +678,8 @@
 	int mem_type = -1;
 	switch (resource_context.res_mem_type) {
 	case DDL_FW_MEM:
-		mem_type = resource_context.fw_mem_type;
-		break;
+		mem_type = ION_HEAP(resource_context.fw_mem_type);
+		return mem_type;
 	case DDL_MM_MEM:
 		mem_type = resource_context.memtype;
 		break;
@@ -646,7 +696,8 @@
 		if (res_trk_check_for_sec_session())
 			mem_type = (ION_HEAP(mem_type) | ION_SECURE);
 		else
-			mem_type = ION_HEAP(mem_type);
+			mem_type = (ION_HEAP(mem_type) |
+					ION_HEAP(ION_IOMMU_HEAP_ID));
 	}
 	return mem_type;
 }
@@ -740,16 +791,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/ddl/vcd_ddl.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
index 7c68d63..02b2369 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
 #include "vcd_res_tracker_api.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
index eb08b7e..ac5bce9 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
index 25aa6bc..965c3aa 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_firmware.h"
 #include "vcd_ddl_utils.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
index 7952dfb..a136de8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
@@ -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
@@ -12,7 +12,7 @@
  */
 #ifndef _VCD_DDL_FIRMWARE_H_
 #define _VCD_DDL_FIRMWARE_H_
-#include "vcd_property.h"
+#include <media/msm/vcd_property.h>
 
 #define VCD_FW_BIG_ENDIAN     0x0
 #define VCD_FW_LITTLE_ENDIAN  0x1
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
index f09bd71..6a69955 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
index 2ec8419..15adf21 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 
 DDL_INLINE struct ddl_context *ddl_get_context(void)
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
index 00c00cd..9dc495b 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
@@ -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
@@ -12,7 +12,7 @@
  */
 #ifndef _VCD_DDL_INTERNAL_PROPERTY_H_
 #define _VCD_DDL_INTERNAL_PROPERTY_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 
 #define VCD_EVT_RESP_DDL_BASE          0x3000
 #define VCD_EVT_RESP_DEVICE_INIT       (VCD_EVT_RESP_DDL_BASE + 0x1)
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
index ece4c30..fe71dc1 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vidc.h"
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
index 376ea6d..2a74da8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/720p/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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
index 6d3c666..3aebdaf 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index c8ea83f..17dedb8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.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
@@ -11,7 +11,7 @@
  *
  */
 #include <linux/memory_alloc.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 
 #if DEBUG
diff --git a/drivers/video/msm/vidc/720p/ddl/vidc.c b/drivers/video/msm/vidc/720p/ddl/vidc.c
index 0f5932a..de6cbbb 100644
--- a/drivers/video/msm/vidc/720p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/720p/ddl/vidc.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
@@ -12,8 +12,8 @@
  */
 
 #include <linux/unistd.h>
+#include <media/msm/vidc_type.h>
 #include "vidc.h"
-#include "vidc_type.h"
 
 #if DEBUG
 #define DBG(x...) printk(KERN_DEBUG x)
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 522ff16..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
@@ -16,9 +16,9 @@
 #include <linux/regulator/consumer.h>
 #include <mach/clk.h>
 #include <linux/interrupt.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_init.h>
+#include <media/msm/vidc_type.h>
 #include "vcd_res_tracker.h"
-#include "vidc_init.h"
 
 #define MSM_AXI_QOS_NAME "msm_vidc_reg"
 #define AXI_CLK_SCALING
@@ -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 dee4da7..61deb8d 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -29,11 +29,11 @@
 #include <linux/clk.h>
 #include <linux/timer.h>
 #include <mach/msm_subsystem_map.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 #include "vcd_res_tracker_api.h"
-#include "vidc_type.h"
-#include "vcd_api.h"
 #include "vdec_internal.h"
-#include "vidc_init.h"
 
 
 
@@ -236,6 +236,8 @@
 	s32 buffer_index = -1;
 	enum vdec_picture pic_type;
 	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
+	struct vdec_output_frameinfo  *output_frame;
 
 	if (!client_ctx || !vcd_frame_data) {
 		ERR("vid_dec_input_frame_done() NULL pointer\n");
@@ -328,6 +330,13 @@
 		}
 		vdec_msg->vdec_msg_info.msgdata.output_frame.pic_type =
 			pic_type;
+		output_frame = &vdec_msg->vdec_msg_info.msgdata.output_frame;
+		output_frame->aspect_ratio_info.aspect_ratio =
+			vcd_frame_data->aspect_ratio_info.aspect_ratio;
+		output_frame->aspect_ratio_info.par_width =
+			vcd_frame_data->aspect_ratio_info.extended_par_width;
+		output_frame->aspect_ratio_info.par_height =
+			vcd_frame_data->aspect_ratio_info.extended_par_height;
 		vdec_msg->vdec_msg_info.msgdatasize =
 		    sizeof(struct vdec_output_frameinfo);
 	} else {
@@ -336,11 +345,14 @@
 	}
 	if (vcd_frame_data->data_len > 0) {
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
-				pmem_fd, kernel_vaddr, buffer_index);
+				pmem_fd, kernel_vaddr, buffer_index,
+				&buff_handle);
 		if (ion_flag == CACHED) {
-			invalidate_caches(kernel_vaddr,
+			msm_ion_do_cache_op(client_ctx->user_ion_client,
+					buff_handle,
+					(unsigned long *) kernel_vaddr,
 					(unsigned long)vcd_frame_data->data_len,
-					phy_addr);
+					ION_IOC_INV_CACHES);
 		}
 	}
 	mutex_lock(&client_ctx->msg_queue_lock);
@@ -812,7 +824,9 @@
 	u32 len = 0, flags = 0;
 	struct file *file;
 	int rc = 0;
-	unsigned long ionflag;
+	unsigned long ionflag = 0;
+	unsigned long buffer_size = 0;
+	unsigned long iova = 0;
 
 	if (!client_ctx || !mv_data)
 		return false;
@@ -839,13 +853,25 @@
 			return false;
 		}
 		put_pmem_file(file);
+		flags = MSM_SUBSYSTEM_MAP_IOVA;
+		mapped_buffer = msm_subsystem_map_buffer(
+			(unsigned long)vcd_h264_mv_buffer->physical_addr, len,
+				flags, vidc_mmu_subsystem,
+				sizeof(vidc_mmu_subsystem)/
+				sizeof(unsigned int));
+		if (IS_ERR(mapped_buffer)) {
+			pr_err("buffer map failed");
+			return false;
+		}
+		vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
+		vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
 	} else {
 		client_ctx->h264_mv_ion_handle = ion_import_fd(
 					client_ctx->user_ion_client,
 					vcd_h264_mv_buffer->pmem_fd);
 		if (!client_ctx->h264_mv_ion_handle) {
 			ERR("%s(): get_ION_handle failed\n", __func__);
-			goto ion_error;
+			goto import_ion_error;
 		}
 		rc = ion_handle_get_flags(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle,
@@ -853,7 +879,7 @@
 		if (rc) {
 			ERR("%s():get_ION_flags fail\n",
 					 __func__);
-			goto ion_error;
+			goto import_ion_error;
 		}
 		vcd_h264_mv_buffer->kernel_virtual_addr = (u8 *) ion_map_kernel(
 			client_ctx->user_ion_client,
@@ -862,29 +888,22 @@
 		if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
 			ERR("%s(): get_ION_kernel virtual addr failed\n",
 				 __func__);
-			goto ion_error;
+			goto import_ion_error;
 		}
-		rc = ion_phys(client_ctx->user_ion_client,
+		rc = ion_map_iommu(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle,
-				(unsigned long *) (&(vcd_h264_mv_buffer->
-				physical_addr)), &len);
+				VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+				SZ_4K, 0, (unsigned long *)&iova,
+				(unsigned long *)&buffer_size, UNCACHED, 0);
 		if (rc) {
 			ERR("%s():get_ION_kernel physical addr fail\n",
 					 __func__);
-			goto ion_error;
+			goto ion_map_error;
 		}
+		vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
+		vcd_h264_mv_buffer->client_data = NULL;
+		vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
 	}
-	flags = MSM_SUBSYSTEM_MAP_IOVA;
-	mapped_buffer = msm_subsystem_map_buffer(
-		(unsigned long)vcd_h264_mv_buffer->physical_addr, len,
-			flags, vidc_mmu_subsystem,
-			sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
-	if (IS_ERR(mapped_buffer)) {
-		pr_err("buffer map failed");
-		return false;
-	}
-	vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
-	vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
 	DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
 		kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
 		vcd_h264_mv_buffer->pmem_fd);
@@ -896,13 +915,14 @@
 		return false;
 	else
 		return true;
-ion_error:
+ion_map_error:
 	if (vcd_h264_mv_buffer->kernel_virtual_addr)
 		ion_unmap_kernel(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle);
 	if (client_ctx->h264_mv_ion_handle)
 		ion_free(client_ctx->user_ion_client,
 			client_ctx->h264_mv_ion_handle);
+import_ion_error:
 	return false;
 }
 
@@ -973,6 +993,10 @@
 	if (client_ctx->h264_mv_ion_handle != NULL) {
 		ion_unmap_kernel(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
+		ion_unmap_iommu(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle,
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL);
 		ion_free(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
 	}
@@ -1188,6 +1212,7 @@
 	s32 buffer_index = -1;
 	u32 vcd_status = VCD_ERR_FAIL;
 	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
 
 	if (!client_ctx || !input_frame_info)
 		return false;
@@ -1220,11 +1245,14 @@
 						BUFFER_TYPE_INPUT,
 						pmem_fd,
 						kernel_vaddr,
-						buffer_index);
+						buffer_index,
+						&buff_handle);
 			if (ion_flag == CACHED) {
-				clean_caches(kernel_vaddr,
-				(unsigned long)vcd_input_buffer.data_len,
-				phy_addr);
+				msm_ion_do_cache_op(client_ctx->user_ion_client,
+				buff_handle,
+				(unsigned long *)kernel_vaddr,
+				(unsigned long) vcd_input_buffer.data_len,
+				ION_IOC_CLEAN_CACHES);
 			}
 		}
 		vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
@@ -1251,6 +1279,7 @@
 	struct file *file;
 	s32 buffer_index = -1;
 	u32 vcd_status = VCD_ERR_FAIL;
+	struct ion_handle *buff_handle = NULL;
 
 	struct vcd_frame_data vcd_frame;
 
@@ -1272,7 +1301,9 @@
 		vcd_frame.ion_flag = vidc_get_fd_info(client_ctx,
 						 BUFFER_TYPE_OUTPUT,
 						pmem_fd, kernel_vaddr,
-						buffer_index);
+						buffer_index,
+						&buff_handle);
+		vcd_frame.buff_ion_handle = buff_handle;
 		vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
 						    &vcd_frame);
 		if (!vcd_status)
@@ -2024,8 +2055,8 @@
 	}
 
 	client_index = vid_dec_get_empty_client_index();
-	if (client_index == -1) {
-		ERR("%s() : No free clients client_index == -1\n", __func__);
+	if (client_index < 0) {
+		ERR("%s() : No free clients client_index < 0\n", __func__);
 		goto client_failure;
 	}
 	client_ctx = &vid_dec_device_p->vdec_clients[client_index];
@@ -2073,19 +2104,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 +2149,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/dec/vdec_internal.h b/drivers/video/msm/vidc/common/dec/vdec_internal.h
index f310e25..89da9a2 100644
--- a/drivers/video/msm/vidc/common/dec/vdec_internal.h
+++ b/drivers/video/msm/vidc/common/dec/vdec_internal.h
@@ -16,7 +16,7 @@
 
 #include <linux/msm_vidc_dec.h>
 #include <linux/cdev.h>
-#include "vidc_init.h"
+#include <media/msm/vidc_init.h>
 
 #define NUM_OF_DRIVER_NODES 2
 
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index cc6606c..f983e25 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -27,11 +27,11 @@
 #include <linux/workqueue.h>
 #include <linux/android_pmem.h>
 #include <linux/clk.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 
-#include "vidc_type.h"
-#include "vcd_api.h"
 #include "venc_internal.h"
-#include "vidc_init.h"
 #include "vcd_res_tracker_api.h"
 
 #define VID_ENC_NAME	"msm_vidc_enc"
@@ -198,6 +198,7 @@
 	struct file *file;
 	s32 buffer_index = -1;
 	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
 
 	if (!client_ctx || !vcd_frame_data) {
 		ERR("vid_enc_input_frame_done() NULL pointer\n");
@@ -262,11 +263,14 @@
 	}
 	if (venc_msg->venc_msg_info.buf.len > 0) {
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
-					pmem_fd, kernel_vaddr, buffer_index);
+					pmem_fd, kernel_vaddr, buffer_index,
+					&buff_handle);
 		if (ion_flag == CACHED) {
-			clean_and_invalidate_caches(kernel_vaddr,
+			msm_ion_do_cache_op(client_ctx->user_ion_client,
+				buff_handle,
+				(unsigned long *) kernel_vaddr,
 				(unsigned long)venc_msg->venc_msg_info.buf.len,
-				phy_addr);
+				ION_IOC_CLEAN_INV_CACHES);
 		}
 	}
 	mutex_lock(&client_ctx->msg_queue_lock);
@@ -1575,6 +1579,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 e3bb9db..46dcaf4 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -28,10 +28,10 @@
 #include <linux/android_pmem.h>
 #include <linux/clk.h>
 #include <mach/msm_subsystem_map.h>
-#include "vidc_type.h"
-#include "vcd_api.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 #include "venc_internal.h"
-#include "vidc_init.h"
 
 #if DEBUG
 #define DBG(x...) printk(KERN_DEBUG x)
@@ -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);
 
@@ -1610,6 +1656,7 @@
 	struct file *file;
 	s32 buffer_index = -1;
 	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
 
 	u32 vcd_status = VCD_ERR_FAIL;
 
@@ -1642,14 +1689,17 @@
 		vcd_input_buffer.flags = input_frame_info->flags;
 
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_INPUT,
-				pmem_fd, kernel_vaddr, buffer_index);
+				pmem_fd, kernel_vaddr, buffer_index,
+				&buff_handle);
 
 		if (vcd_input_buffer.data_len > 0) {
 			if (ion_flag == CACHED) {
-				clean_caches(
-				(unsigned long) vcd_input_buffer.virtual,
+				msm_ion_do_cache_op(
+				client_ctx->user_ion_client,
+				buff_handle,
+				(unsigned long *) vcd_input_buffer.virtual,
 				(unsigned long) vcd_input_buffer.data_len,
-				(phy_addr + input_frame_info->offset));
+				ION_IOC_CLEAN_CACHES);
 			}
 		}
 
@@ -1720,10 +1770,11 @@
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_enc_recon_buffer *control = NULL;
 	struct msm_mapped_buffer *mapped_buffer = NULL;
-	size_t ion_len = -1;
-	unsigned long phy_addr;
 	int rc = -1;
-	unsigned long ionflag;
+	unsigned long ionflag = 0;
+	unsigned long iova = 0;
+	unsigned long buffer_size = 0;
+
 	if (!client_ctx || !venc_recon) {
 		pr_err("%s() Invalid params", __func__);
 		return false;
@@ -1756,12 +1807,23 @@
 				return false;
 			}
 			put_pmem_file(file);
+			flags = MSM_SUBSYSTEM_MAP_IOVA;
+			mapped_buffer = msm_subsystem_map_buffer(
+			(unsigned long)control->physical_addr, len,
+			flags, vidc_mmu_subsystem,
+			sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
+			if (IS_ERR(mapped_buffer)) {
+				pr_err("buffer map failed");
+				return false;
+			}
+			control->client_data = (void *) mapped_buffer;
+			control->dev_addr = (u8 *)mapped_buffer->iova[0];
 	} else {
 		client_ctx->recon_buffer_ion_handle[i] = ion_import_fd(
 				client_ctx->user_ion_client, control->pmem_fd);
 		if (IS_ERR_OR_NULL(client_ctx->recon_buffer_ion_handle[i])) {
 			ERR("%s(): get_ION_handle failed\n", __func__);
-			goto ion_error;
+			goto import_ion_error;
 		}
 		rc = ion_handle_get_flags(client_ctx->user_ion_client,
 					client_ctx->recon_buffer_ion_handle[i],
@@ -1769,7 +1831,7 @@
 		if (rc) {
 			ERR("%s():get_ION_flags fail\n",
 				 __func__);
-			goto ion_error;
+			goto import_ion_error;
 		}
 		control->kernel_virtual_addr = (u8 *) ion_map_kernel(
 			client_ctx->user_ion_client,
@@ -1778,30 +1840,27 @@
 		if (!control->kernel_virtual_addr) {
 			ERR("%s(): get_ION_kernel virtual addr fail\n",
 				 __func__);
-			goto ion_error;
+			goto import_ion_error;
 		}
-		rc = ion_phys(client_ctx->user_ion_client,
+		rc = ion_map_iommu(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],
-				&phy_addr, &ion_len);
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL,
+				SZ_4K,
+				0,
+				(unsigned long *)&iova,
+				(unsigned long *)&buffer_size,
+				UNCACHED, 0);
 		if (rc) {
-			ERR("%s():get_ION_kernel physical addr fail\n",
+			ERR("%s():ION map iommu addr fail\n",
 				 __func__);
-			goto ion_error;
+			goto map_ion_error;
 		}
-		control->physical_addr =  (u8 *) phy_addr;
-		len = (unsigned long) ion_len;
+		control->physical_addr =  (u8 *) iova;
+		len = buffer_size;
+		control->client_data = NULL;
+		control->dev_addr = (u8 *)iova;
 	}
-	flags = MSM_SUBSYSTEM_MAP_IOVA;
-	mapped_buffer = msm_subsystem_map_buffer(
-	(unsigned long)control->physical_addr, len,
-	flags, vidc_mmu_subsystem,
-	sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
-	if (IS_ERR(mapped_buffer)) {
-		pr_err("buffer map failed");
-		return false;
-	}
-	control->client_data = (void *) mapped_buffer;
-	control->dev_addr = (u8 *)mapped_buffer->iova[0];
 
 	vcd_property_hdr.prop_id = VCD_I_RECON_BUFFERS;
 	vcd_property_hdr.sz =
@@ -1817,7 +1876,7 @@
 				__func__, vcd_status);
 		return false;
 	}
-ion_error:
+map_ion_error:
 	if (control->kernel_virtual_addr)
 		ion_unmap_kernel(client_ctx->user_ion_client,
 			client_ctx->recon_buffer_ion_handle[i]);
@@ -1825,6 +1884,7 @@
 		ion_free(client_ctx->user_ion_client,
 			client_ctx->recon_buffer_ion_handle[i]);
 		client_ctx->recon_buffer_ion_handle[i] = NULL;
+import_ion_error:
 	return false;
 }
 
@@ -1868,6 +1928,10 @@
 		if (client_ctx->recon_buffer_ion_handle[i]) {
 			ion_unmap_kernel(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i]);
+			ion_unmap_iommu(client_ctx->user_ion_client,
+				client_ctx->recon_buffer_ion_handle[i],
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL);
 			ion_free(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i]);
 			client_ctx->recon_buffer_ion_handle[i] = NULL;
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index 2b5a532..8a07fdb 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.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
@@ -16,8 +16,7 @@
 
 #include <linux/msm_vidc_enc.h>
 #include <linux/cdev.h>
-
-#include "vidc_init.h"
+#include <media/msm/vidc_init.h>
 
 #define VID_ENC_MAX_NUM_OF_BUFF 100
 
@@ -69,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/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index f799a6c..dda81ed 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -31,9 +31,9 @@
 #include <mach/clk.h>
 #include <linux/pm_runtime.h>
 #include <mach/msm_subsystem_map.h>
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 #include "vidc_init_internal.h"
-#include "vidc_init.h"
 #include "vcd_res_tracker_api.h"
 
 #if DEBUG
@@ -366,7 +366,8 @@
 
 u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
 		enum buffer_dir buffer, int pmem_fd,
-		unsigned long kvaddr, int index)
+		unsigned long kvaddr, int index,
+		struct ion_handle **buff_handle)
 {
 	struct buf_addr_table *buf_addr_table;
 	u32 rc = 0;
@@ -377,9 +378,13 @@
 	else
 		buf_addr_table = client_ctx->output_buf_addr_table;
 	if (buf_addr_table[index].pmem_fd == pmem_fd) {
-		if (buf_addr_table[index].kernel_vaddr == kvaddr)
+		if (buf_addr_table[index].kernel_vaddr == kvaddr) {
 			rc = buf_addr_table[index].buff_ion_flag;
-	}
+			*buff_handle = buf_addr_table[index].buff_ion_handle;
+		} else
+			*buff_handle = NULL;
+	} else
+		*buff_handle = NULL;
 	return rc;
 }
 EXPORT_SYMBOL(vidc_get_fd_info);
@@ -415,6 +420,10 @@
 		if (buf_addr_table[i].buff_ion_handle) {
 			ion_unmap_kernel(client_ctx->user_ion_client,
 					buf_addr_table[i].buff_ion_handle);
+			ion_unmap_iommu(client_ctx->user_ion_client,
+					buf_addr_table[i].buff_ion_handle,
+					VIDEO_DOMAIN,
+					VIDEO_MAIN_POOL);
 			ion_free(client_ctx->user_ion_client,
 					buf_addr_table[i].buff_ion_handle);
 			buf_addr_table[i].buff_ion_handle = NULL;
@@ -428,6 +437,10 @@
 	if (client_ctx->h264_mv_ion_handle) {
 		ion_unmap_kernel(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle);
+		ion_unmap_iommu(client_ctx->user_ion_client,
+				client_ctx->h264_mv_ion_handle,
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL);
 		ion_free(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle);
 		client_ctx->h264_mv_ion_handle = NULL;
@@ -530,9 +543,11 @@
 	u32 i, flags;
 	struct buf_addr_table *buf_addr_table;
 	struct msm_mapped_buffer *mapped_buffer = NULL;
-	size_t ion_len;
 	struct ion_handle *buff_ion_handle = NULL;
 	unsigned long ionflag = 0;
+	unsigned long iova = 0;
+	int ret = 0;
+	unsigned long buffer_size  = 0;
 
 	if (!client_ctx || !length)
 		return false;
@@ -548,6 +563,7 @@
 		num_of_buffers = &client_ctx->num_of_output_buffers;
 		DBG("%s(): buffer = OUTPUT #Buf = %d\n",
 			__func__, *num_of_buffers);
+		length = length * 2; /* workaround for iommu video h/w bug */
 	}
 
 	if (*num_of_buffers == max_num_buffers) {
@@ -573,6 +589,20 @@
 				goto bail_out_add;
 			}
 			put_pmem_file(file);
+			flags = (buffer == BUFFER_TYPE_INPUT)
+			? MSM_SUBSYSTEM_MAP_IOVA :
+			MSM_SUBSYSTEM_MAP_IOVA|MSM_SUBSYSTEM_ALIGN_IOVA_8K;
+			mapped_buffer = msm_subsystem_map_buffer(phys_addr,
+			length, flags, vidc_mmu_subsystem,
+			sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
+			if (IS_ERR(mapped_buffer)) {
+				pr_err("buffer map failed");
+				goto bail_out_add;
+			}
+			buf_addr_table[*num_of_buffers].client_data = (void *)
+				mapped_buffer;
+			buf_addr_table[*num_of_buffers].dev_addr =
+				mapped_buffer->iova[0];
 		} else {
 			buff_ion_handle = ion_import_fd(
 				client_ctx->user_ion_client, pmem_fd);
@@ -586,7 +616,7 @@
 						&ionflag)) {
 				ERR("%s():ION flags fail\n",
 				 __func__);
-				goto ion_error;
+				goto bail_out_add;
 			}
 			*kernel_vaddr = (unsigned long)
 				ion_map_kernel(
@@ -597,32 +627,28 @@
 				ERR("%s():ION virtual addr fail\n",
 				 __func__);
 				*kernel_vaddr = (unsigned long)NULL;
-				goto ion_error;
+				goto ion_free_error;
 			}
-			if (ion_phys(client_ctx->user_ion_client,
+			ret = ion_map_iommu(client_ctx->user_ion_client,
 					buff_ion_handle,
-					&phys_addr, &ion_len)) {
-				ERR("%s():ION physical addr fail\n",
+					VIDEO_DOMAIN,
+					VIDEO_MAIN_POOL,
+					SZ_8K,
+					length,
+					(unsigned long *) &iova,
+					(unsigned long *) &buffer_size,
+					UNCACHED, ION_IOMMU_UNMAP_DELAYED);
+			if (ret) {
+				ERR("%s():ION iommu map fail\n",
 				 __func__);
-				goto ion_error;
+				goto ion_map_error;
 			}
-			len = (unsigned long) ion_len;
+			phys_addr = iova;
+			buf_addr_table[*num_of_buffers].client_data = NULL;
+			buf_addr_table[*num_of_buffers].dev_addr = iova;
 		}
 		phys_addr += buffer_addr_offset;
 		(*kernel_vaddr) += buffer_addr_offset;
-		flags = (buffer == BUFFER_TYPE_INPUT) ? MSM_SUBSYSTEM_MAP_IOVA :
-		MSM_SUBSYSTEM_MAP_IOVA|MSM_SUBSYSTEM_ALIGN_IOVA_8K;
-		mapped_buffer = msm_subsystem_map_buffer(phys_addr, length,
-		flags, vidc_mmu_subsystem,
-		sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
-		if (IS_ERR(mapped_buffer)) {
-			pr_err("buffer map failed");
-			goto ion_error;
-		}
-		buf_addr_table[*num_of_buffers].client_data = (void *)
-			mapped_buffer;
-		buf_addr_table[*num_of_buffers].dev_addr =
-			mapped_buffer->iova[0];
 		buf_addr_table[*num_of_buffers].user_vaddr = user_vaddr;
 		buf_addr_table[*num_of_buffers].kernel_vaddr = *kernel_vaddr;
 		buf_addr_table[*num_of_buffers].pmem_fd = pmem_fd;
@@ -640,9 +666,10 @@
 	}
 	mutex_unlock(&client_ctx->enrty_queue_lock);
 	return true;
-ion_error:
+ion_map_error:
 	if (*kernel_vaddr && buff_ion_handle)
 		ion_unmap_kernel(client_ctx->user_ion_client, buff_ion_handle);
+ion_free_error:
 	if (!IS_ERR_OR_NULL(buff_ion_handle))
 		ion_free(client_ctx->user_ion_client, buff_ion_handle);
 bail_out_add:
@@ -651,6 +678,77 @@
 }
 EXPORT_SYMBOL(vidc_insert_addr_table);
 
+/*
+ * Similar to vidc_insert_addr_table except intended for in-kernel
+ * use where buffers have already been alloced and mapped properly
+ */
+u32 vidc_insert_addr_table_kernel(struct video_client_ctx *client_ctx,
+	enum buffer_dir buffer, unsigned long user_vaddr,
+	unsigned long kernel_vaddr, unsigned long phys_addr,
+	unsigned int max_num_buffers,
+	unsigned long length)
+{
+	u32 *num_of_buffers = NULL;
+	u32 i;
+	struct buf_addr_table *buf_addr_table;
+	struct msm_mapped_buffer *mapped_buffer = NULL;
+
+	if (!client_ctx || !length || !kernel_vaddr || !phys_addr)
+		return false;
+	mutex_lock(&client_ctx->enrty_queue_lock);
+	if (buffer == BUFFER_TYPE_INPUT) {
+		buf_addr_table = client_ctx->input_buf_addr_table;
+		num_of_buffers = &client_ctx->num_of_input_buffers;
+		DBG("%s(): buffer = INPUT #Buf = %d\n",
+			__func__, *num_of_buffers);
+
+	} else {
+		buf_addr_table = client_ctx->output_buf_addr_table;
+		num_of_buffers = &client_ctx->num_of_output_buffers;
+		DBG("%s(): buffer = OUTPUT #Buf = %d\n",
+			__func__, *num_of_buffers);
+	}
+
+	if (*num_of_buffers == max_num_buffers) {
+		ERR("%s(): Num of buffers reached max value : %d",
+			__func__, max_num_buffers);
+		goto bail_out_add;
+	}
+
+	i = 0;
+	while (i < *num_of_buffers &&
+		user_vaddr != buf_addr_table[i].user_vaddr) {
+		i++;
+	}
+	if (i < *num_of_buffers) {
+		DBG("%s() : client_ctx = %p."
+			" user_virt_addr = 0x%08lx already set",
+			__func__, client_ctx, user_vaddr);
+		goto bail_out_add;
+	} else {
+		mapped_buffer = NULL;
+		buf_addr_table[*num_of_buffers].client_data = (void *)
+			mapped_buffer;
+		buf_addr_table[*num_of_buffers].dev_addr = phys_addr;
+		buf_addr_table[*num_of_buffers].user_vaddr = user_vaddr;
+		buf_addr_table[*num_of_buffers].kernel_vaddr = kernel_vaddr;
+		buf_addr_table[*num_of_buffers].pmem_fd = -1;
+		buf_addr_table[*num_of_buffers].file = NULL;
+		buf_addr_table[*num_of_buffers].phy_addr = phys_addr;
+		buf_addr_table[*num_of_buffers].buff_ion_handle = NULL;
+		*num_of_buffers = *num_of_buffers + 1;
+		DBG("%s() : client_ctx = %p, user_virt_addr = 0x%08lx, "
+			"kernel_vaddr = 0x%08lx inserted!", __func__,
+			client_ctx, user_vaddr, *kernel_vaddr);
+	}
+	mutex_unlock(&client_ctx->enrty_queue_lock);
+	return true;
+bail_out_add:
+	mutex_unlock(&client_ctx->enrty_queue_lock);
+	return false;
+}
+EXPORT_SYMBOL(vidc_insert_addr_table_kernel);
+
 u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
 	enum buffer_dir buffer,
 	unsigned long user_vaddr,
@@ -685,12 +783,19 @@
 			__func__, client_ctx, user_vaddr);
 		goto bail_out_del;
 	}
-	msm_subsystem_unmap_buffer(
-	(struct msm_mapped_buffer *)buf_addr_table[i].client_data);
+	if (buf_addr_table[i].client_data) {
+		msm_subsystem_unmap_buffer(
+		(struct msm_mapped_buffer *)buf_addr_table[i].client_data);
+		buf_addr_table[i].client_data = NULL;
+	}
 	*kernel_vaddr = buf_addr_table[i].kernel_vaddr;
 	if (buf_addr_table[i].buff_ion_handle) {
 		ion_unmap_kernel(client_ctx->user_ion_client,
 				buf_addr_table[i].buff_ion_handle);
+		ion_unmap_iommu(client_ctx->user_ion_client,
+				buf_addr_table[i].buff_ion_handle,
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL);
 		ion_free(client_ctx->user_ion_client,
 				buf_addr_table[i].buff_ion_handle);
 		buf_addr_table[i].buff_ion_handle = NULL;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.h b/drivers/video/msm/vidc/common/init/vidc_init.h
deleted file mode 100644
index a67329c..0000000
--- a/drivers/video/msm/vidc/common/init/vidc_init.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* 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
- * 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 VIDC_INIT_H
-#define VIDC_INIT_H
-#include <linux/ion.h>
-#include "vidc_type.h"
-
-#define VIDC_MAX_NUM_CLIENTS 4
-#define MAX_VIDEO_NUM_OF_BUFF 100
-
-enum buffer_dir {
-	BUFFER_TYPE_INPUT,
-	BUFFER_TYPE_OUTPUT
-};
-
-struct buf_addr_table {
-	unsigned long user_vaddr;
-	unsigned long kernel_vaddr;
-	unsigned long phy_addr;
-	unsigned long buff_ion_flag;
-	struct ion_handle *buff_ion_handle;
-	int pmem_fd;
-	struct file *file;
-	unsigned long dev_addr;
-	void *client_data;
-};
-
-struct video_client_ctx {
-	void *vcd_handle;
-	u32 num_of_input_buffers;
-	u32 num_of_output_buffers;
-	struct buf_addr_table input_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
-	struct buf_addr_table output_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
-	struct list_head msg_queue;
-	struct mutex msg_queue_lock;
-	struct mutex enrty_queue_lock;
-	wait_queue_head_t msg_wait;
-	struct completion event;
-	struct vcd_property_h264_mv_buffer vcd_h264_mv_buffer;
-	struct vcd_property_enc_recon_buffer recon_buffer[4];
-	u32 event_status;
-	u32 seq_header_set;
-	u32 stop_msg;
-	u32 stop_called;
-	u32 stop_sync_cb;
-	struct ion_client *user_ion_client;
-	struct ion_handle *seq_hdr_ion_handle;
-	struct ion_handle *h264_mv_ion_handle;
-	struct ion_handle *recon_buffer_ion_handle[4];
-	u32 dmx_disable;
-};
-
-void __iomem *vidc_get_ioaddr(void);
-int vidc_load_firmware(void);
-void vidc_release_firmware(void);
-u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
-		enum buffer_dir buffer, int pmem_fd,
-		unsigned long kvaddr, int index);
-u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
-	enum buffer_dir buffer, u32 search_with_user_vaddr,
-	unsigned long *user_vaddr, unsigned long *kernel_vaddr,
-	unsigned long *phy_addr, int *pmem_fd, struct file **file,
-	s32 *buffer_index);
-u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx,
-	enum buffer_dir buffer, unsigned long user_vaddr,
-	unsigned long *kernel_vaddr, int pmem_fd,
-	unsigned long buffer_addr_offset,
-	unsigned int max_num_buffers, unsigned long length);
-u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
-	enum buffer_dir buffer, unsigned long user_vaddr,
-	unsigned long *kernel_vaddr);
-void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
-				enum buffer_dir buffer);
-
-u32 vidc_timer_create(void (*timer_handler)(void *),
-	void *user_data, void **timer_handle);
-void  vidc_timer_release(void *timer_handle);
-void  vidc_timer_start(void *timer_handle, u32 time_out);
-void  vidc_timer_stop(void *timer_handle);
-
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index b557752..9fc76d8 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.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,10 +13,10 @@
 #ifndef _VCD_H_
 #define _VCD_H_
 
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
+#include "vcd_util.h"
 #include "vcd_ddl_api.h"
 #include "vcd_res_tracker_api.h"
-#include "vcd_util.h"
 #include "vcd_client_sm.h"
 #include "vcd_core.h"
 #include "vcd_device_sm.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.c b/drivers/video/msm/vidc/common/vcd/vcd_api.c
index 5e9fd55..e0ef3af 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.c
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle)
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.h b/drivers/video/msm/vidc/common/vcd/vcd_api.h
deleted file mode 100644
index 9580ece..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Copyright (c) 2010-2011, 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 _VCD_API_H_
-#define _VCD_API_H_
-#include "vcd_property.h"
-#include "vcd_status.h"
-
-#define VCD_FRAME_FLAG_EOS 0x00000001
-#define VCD_FRAME_FLAG_DECODEONLY   0x00000004
-#define VCD_FRAME_FLAG_DATACORRUPT 0x00000008
-#define VCD_FRAME_FLAG_ENDOFFRAME 0x00000010
-#define VCD_FRAME_FLAG_SYNCFRAME 0x00000020
-#define VCD_FRAME_FLAG_EXTRADATA 0x00000040
-#define VCD_FRAME_FLAG_CODECCONFIG  0x00000080
-#define VCD_FRAME_FLAG_BFRAME 0x00100000
-#define VCD_FRAME_FLAG_EOSEQ 0x00200000
-
-#define VCD_FLUSH_INPUT   0x0001
-#define VCD_FLUSH_OUTPUT  0x0002
-#define VCD_FLUSH_ALL     0x0003
-
-#define VCD_FRAMETAG_INVALID  0xffffffff
-
-struct vcd_handle_container {
-	void *handle;
-};
-struct vcd_flush_cmd {
-	u32 mode;
-};
-
-enum vcd_frame {
-	VCD_FRAME_YUV = 1,
-	VCD_FRAME_I,
-	VCD_FRAME_P,
-	VCD_FRAME_B,
-	VCD_FRAME_NOTCODED,
-	VCD_FRAME_IDR,
-	VCD_FRAME_32BIT = 0x7fffffff
-};
-
-enum vcd_power_state {
-	VCD_PWR_STATE_ON = 1,
-	VCD_PWR_STATE_SLEEP,
-};
-
-struct vcd_frame_data {
-	u8 *virtual;
-	u8 *physical;
-	u32 ion_flag;
-	u32 alloc_len;
-	u32 data_len;
-	u32 offset;
-	s64 time_stamp;
-	u32 flags;
-	u32 frm_clnt_data;
-	struct vcd_property_dec_output_buffer dec_op_prop;
-	u32 interlaced;
-	enum vcd_frame frame;
-	u32 ip_frm_tag;
-	u32 intrlcd_ip_frm_tag;
-	u8 *desc_buf;
-	u32 desc_size;
-};
-
-struct vcd_sequence_hdr {
-	u8 *sequence_header;
-	u32 sequence_header_len;
-
-};
-
-enum vcd_buffer_type {
-	VCD_BUFFER_INPUT = 0x1,
-	VCD_BUFFER_OUTPUT = 0x2,
-	VCD_BUFFER_INVALID = 0x3,
-	VCD_BUFFER_32BIT = 0x7FFFFFFF
-};
-
-struct vcd_buffer_requirement {
-	u32 min_count;
-	u32 actual_count;
-	u32 max_count;
-	size_t sz;
-	u32 align;
-	u32 buf_pool_id;
-};
-
-struct vcd_init_config {
-	void *device_name;
-	void *(*map_dev_base_addr) (void *device_name);
-	void (*un_map_dev_base_addr) (void);
-	void (*interrupt_clr) (void);
-	void (*register_isr) (void *device_name);
-	void (*deregister_isr) (void);
-	u32  (*timer_create) (void (*timer_handler)(void *),
-		void *user_data, void **timer_handle);
-	void (*timer_release) (void *timer_handle);
-	void (*timer_start) (void *timer_handle, u32 time_out);
-	void (*timer_stop) (void *timer_handle);
-};
-
-u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle);
-u32 vcd_term(s32 driver_handle);
-u32 vcd_open(s32 driver_handle, u32 decoding,
-	void (*callback) (u32 event, u32 status, void *info, size_t sz,
-	void *handle, void *const client_data), void *client_data);
-u32 vcd_close(void *handle);
-u32 vcd_encode_start(void *handle);
-u32 vcd_encode_frame(void *handle, struct vcd_frame_data *input_frame);
-u32 vcd_decode_start(void *handle, struct vcd_sequence_hdr *seq_hdr);
-u32 vcd_decode_frame(void *handle, struct vcd_frame_data *input_frame);
-u32 vcd_pause(void *handle);
-u32 vcd_resume(void *handle);
-u32 vcd_flush(void *handle, u32 mode);
-u32 vcd_stop(void *handle);
-u32 vcd_set_property(void *handle, struct vcd_property_hdr *prop_hdr,
-					void *prop_val);
-u32 vcd_get_property(void *handle, struct vcd_property_hdr *prop_hdr,
-					 void *prop_val);
-u32 vcd_set_buffer_requirements(void *handle, enum vcd_buffer_type buffer,
-		struct vcd_buffer_requirement *buffer_req);
-u32 vcd_get_buffer_requirements(void *handle, enum vcd_buffer_type buffer,
-		struct vcd_buffer_requirement *buffer_req);
-u32 vcd_set_buffer(void *handle, enum vcd_buffer_type buffer_type,
-		u8 *buffer, u32 buf_size);
-u32 vcd_allocate_buffer(void *handle, enum vcd_buffer_type buffer,
-		u32 buf_size, u8 **vir_buf_addr, u8 **phy_buf_addr);
-
-u32 vcd_free_buffer(void *handle, enum vcd_buffer_type buffer_type, u8 *buffer);
-u32 vcd_fill_output_buffer(void *handle, struct vcd_frame_data *buffer);
-u32 vcd_set_device_power(s32 driver_handle,
-		enum vcd_power_state pwr_state);
-void vcd_read_and_clear_interrupt(void);
-void vcd_response_handler(void);
-u8 vcd_get_num_of_clients(void);
-u32 vcd_get_ion_status(void);
-struct ion_client *vcd_get_ion_client(void);
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index e00e85f..9376900 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 static const struct vcd_clnt_state_table *vcd_clnt_state_table[];
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
index e9ab41c..9f2d63d 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
@@ -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
@@ -12,7 +12,7 @@
  */
 #ifndef _VCD_CLIENT_SM_H_
 #define _VCD_CLIENT_SM_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 #include "vcd_ddl_api.h"
 
 struct vcd_clnt_state_table;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index 64dec2d..1f844e8 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.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
@@ -14,7 +14,7 @@
 #define _VCD_CORE_H_
 
 #include <linux/ion.h>
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 #include "vcd_ddl_api.h"
 
 #include "vcd_util.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 4c477cb..9576387 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 static const struct vcd_dev_state_table *vcd_dev_state_table[];
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
index 8245966..2443c33 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
@@ -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
@@ -13,7 +13,7 @@
 #ifndef _VCD_DEVICE_SM_H_
 #define _VCD_DEVICE_SM_H_
 
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 #include "vcd_ddl_api.h"
 #include "vcd_core.h"
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
index 6a1cc80..01bd931 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_power_sm.h"
 #include "vcd_core.h"
 #include "vcd.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_property.h b/drivers/video/msm/vidc/common/vcd/vcd_property.h
deleted file mode 100644
index a3069e3..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_property.h
+++ /dev/null
@@ -1,350 +0,0 @@
-/* Copyright (c) 2010-2011, 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 _VCD_DRIVER_PROPERTY_H_
-#define _VCD_DRIVER_PROPERTY_H_
-
-#define VCD_START_BASE       0x0
-#define VCD_I_LIVE           (VCD_START_BASE + 0x1)
-#define VCD_I_CODEC          (VCD_START_BASE + 0x2)
-#define VCD_I_FRAME_SIZE     (VCD_START_BASE + 0x3)
-#define VCD_I_METADATA_ENABLE  (VCD_START_BASE + 0x4)
-#define VCD_I_METADATA_HEADER  (VCD_START_BASE + 0x5)
-#define VCD_I_PROFILE        (VCD_START_BASE + 0x6)
-#define VCD_I_LEVEL          (VCD_START_BASE + 0x7)
-#define VCD_I_BUFFER_FORMAT  (VCD_START_BASE + 0x8)
-#define VCD_I_FRAME_RATE  (VCD_START_BASE + 0x9)
-#define VCD_I_TARGET_BITRATE (VCD_START_BASE + 0xA)
-#define VCD_I_MULTI_SLICE    (VCD_START_BASE + 0xB)
-#define VCD_I_ENTROPY_CTRL   (VCD_START_BASE + 0xC)
-#define VCD_I_DEBLOCKING     (VCD_START_BASE + 0xD)
-#define VCD_I_RATE_CONTROL   (VCD_START_BASE + 0xE)
-#define VCD_I_QP_RANGE      (VCD_START_BASE + 0xF)
-#define VCD_I_SESSION_QP    (VCD_START_BASE + 0x10)
-#define VCD_I_INTRA_PERIOD   (VCD_START_BASE + 0x11)
-#define VCD_I_VOP_TIMING     (VCD_START_BASE + 0x12)
-#define VCD_I_SHORT_HEADER   (VCD_START_BASE + 0x13)
-#define VCD_I_SEQ_HEADER    (VCD_START_BASE + 0x14)
-#define VCD_I_HEADER_EXTENSION   (VCD_START_BASE + 0x15)
-#define VCD_I_INTRA_REFRESH  (VCD_START_BASE + 0x16)
-#define VCD_I_POST_FILTER    (VCD_START_BASE + 0x17)
-#define VCD_I_PROGRESSIVE_ONLY (VCD_START_BASE + 0x18)
-#define VCD_I_OUTPUT_ORDER (VCD_START_BASE + 0x19)
-#define VCD_I_RECON_BUFFERS   (VCD_START_BASE + 0x1A)
-#define VCD_I_FREE_RECON_BUFFERS   (VCD_START_BASE + 0x1B)
-#define VCD_I_GET_RECON_BUFFER_SIZE   (VCD_START_BASE + 0x1C)
-#define VCD_I_H264_MV_BUFFER   (VCD_START_BASE + 0x1D)
-#define VCD_I_FREE_H264_MV_BUFFER (VCD_START_BASE + 0x1E)
-#define VCD_I_GET_H264_MV_SIZE (VCD_START_BASE + 0x1F)
-#define VCD_I_DEC_PICTYPE (VCD_START_BASE + 0x20)
-#define VCD_I_CONT_ON_RECONFIG (VCD_START_BASE + 0x21)
-#define VCD_I_META_BUFFER_MODE (VCD_START_BASE + 0x22)
-#define VCD_I_DISABLE_DMX (VCD_START_BASE + 0x23)
-#define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
-
-#define VCD_START_REQ      (VCD_START_BASE + 0x1000)
-#define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
-
-#define VCD_I_RESERVED_BASE  (VCD_START_BASE + 0x10000)
-
-struct vcd_property_hdr {
-	u32    prop_id;
-	size_t sz;
-};
-
-struct vcd_property_live {
-	u32             live;
-};
-
-enum vcd_codec {
-	VCD_CODEC_H264      = 0x1,
-	VCD_CODEC_H263      = 0x2,
-	VCD_CODEC_MPEG1     = 0x3,
-	VCD_CODEC_MPEG2     = 0x4,
-	VCD_CODEC_MPEG4     = 0x5,
-	VCD_CODEC_DIVX_3    = 0x6,
-	VCD_CODEC_DIVX_4    = 0x7,
-	VCD_CODEC_DIVX_5    = 0x8,
-	VCD_CODEC_DIVX_6    = 0x9,
-	VCD_CODEC_XVID      = 0xA,
-	VCD_CODEC_VC1       = 0xB,
-	VCD_CODEC_VC1_RCV   = 0xC
-};
-
-struct vcd_property_codec {
-	enum vcd_codec       codec;
-};
-
-struct vcd_property_frame_size {
-	u32              width;
-	u32              height;
-	u32              stride;
-	u32              scan_lines;
-};
-
-
-#define VCD_METADATA_DATANONE       0x001
-#define VCD_METADATA_QCOMFILLER     0x002
-#define VCD_METADATA_QPARRAY        0x004
-#define VCD_METADATA_CONCEALMB      0x008
-#define VCD_METADATA_SEI            0x010
-#define VCD_METADATA_VUI            0x020
-#define VCD_METADATA_VC1            0x040
-#define VCD_METADATA_PASSTHROUGH    0x080
-#define VCD_METADATA_ENC_SLICE      0x100
-
-struct vcd_property_meta_data_enable {
-	u32 meta_data_enable_flag;
-};
-
-struct vcd_property_metadata_hdr {
-	u32 meta_data_id;
-	u32 version;
-	u32 port_index;
-	u32 type;
-};
-
-struct vcd_property_frame_rate {
-	u32              fps_denominator;
-	u32              fps_numerator;
-};
-
-struct vcd_property_target_bitrate {
-	u32             target_bitrate;
-};
-
-enum vcd_yuv_buffer_format {
-	VCD_BUFFER_FORMAT_NV12      = 0x1,
-	VCD_BUFFER_FORMAT_TILE_4x2    = 0x2,
-	VCD_BUFFER_FORMAT_NV12_16M2KA = 0x3,
-	VCD_BUFFER_FORMAT_TILE_1x1    = 0x4
-};
-
-struct vcd_property_buffer_format {
-	enum vcd_yuv_buffer_format  buffer_format;
-};
-
-struct vcd_property_post_filter {
-	u32           post_filter;
-};
-
-enum vcd_codec_profile {
-	VCD_PROFILE_UNKNOWN       = 0x0,
-	VCD_PROFILE_MPEG4_SP      = 0x1,
-	VCD_PROFILE_MPEG4_ASP     = 0x2,
-	VCD_PROFILE_H264_BASELINE = 0x3,
-	VCD_PROFILE_H264_MAIN     = 0x4,
-	VCD_PROFILE_H264_HIGH     = 0x5,
-	VCD_PROFILE_H263_BASELINE = 0x6,
-	VCD_PROFILE_VC1_SIMPLE    = 0x7,
-	VCD_PROFILE_VC1_MAIN      = 0x8,
-	VCD_PROFILE_VC1_ADVANCE   = 0x9,
-	VCD_PROFILE_MPEG2_MAIN    = 0xA,
-	VCD_PROFILE_MPEG2_SIMPLE  = 0xB
-};
-
-struct vcd_property_profile {
-	enum vcd_codec_profile       profile;
-};
-
-enum vcd_codec_level {
-   VCD_LEVEL_UNKNOWN       = 0x0,
-   VCD_LEVEL_MPEG4_0       = 0x1,
-   VCD_LEVEL_MPEG4_0b      = 0x2,
-   VCD_LEVEL_MPEG4_1       = 0x3,
-   VCD_LEVEL_MPEG4_2       = 0x4,
-   VCD_LEVEL_MPEG4_3       = 0x5,
-   VCD_LEVEL_MPEG4_3b      = 0x6,
-   VCD_LEVEL_MPEG4_4       = 0x7,
-   VCD_LEVEL_MPEG4_4a      = 0x8,
-   VCD_LEVEL_MPEG4_5       = 0x9,
-   VCD_LEVEL_MPEG4_6       = 0xA,
-   VCD_LEVEL_MPEG4_7       = 0xB,
-   VCD_LEVEL_MPEG4_X       = 0xC,
-   VCD_LEVEL_H264_1        = 0x10,
-   VCD_LEVEL_H264_1b       = 0x11,
-   VCD_LEVEL_H264_1p1      = 0x12,
-   VCD_LEVEL_H264_1p2      = 0x13,
-   VCD_LEVEL_H264_1p3      = 0x14,
-   VCD_LEVEL_H264_2        = 0x15,
-   VCD_LEVEL_H264_2p1      = 0x16,
-   VCD_LEVEL_H264_2p2      = 0x17,
-   VCD_LEVEL_H264_3        = 0x18,
-   VCD_LEVEL_H264_3p1      = 0x19,
-   VCD_LEVEL_H264_3p2      = 0x1A,
-   VCD_LEVEL_H264_4        = 0x1B,
-   VCD_LEVEL_H264_4p1      = 0x1C,
-   VCD_LEVEL_H264_4p2      = 0x1D,
-   VCD_LEVEL_H264_5        = 0x1E,
-   VCD_LEVEL_H264_5p1      = 0x1F,
-   VCD_LEVEL_H263_10       = 0x20,
-   VCD_LEVEL_H263_20       = 0x21,
-   VCD_LEVEL_H263_30       = 0x22,
-   VCD_LEVEL_H263_40       = 0x23,
-   VCD_LEVEL_H263_45       = 0x24,
-   VCD_LEVEL_H263_50       = 0x25,
-   VCD_LEVEL_H263_60       = 0x26,
-   VCD_LEVEL_H263_70       = 0x27,
-   VCD_LEVEL_H263_X        = 0x28,
-   VCD_LEVEL_MPEG2_LOW     = 0x30,
-   VCD_LEVEL_MPEG2_MAIN    = 0x31,
-   VCD_LEVEL_MPEG2_HIGH_14 = 0x32,
-   VCD_LEVEL_MPEG2_HIGH    = 0x33,
-   VCD_LEVEL_MPEG2_X       = 0x34,
-   VCD_LEVEL_VC1_S_LOW     = 0x40,
-   VCD_LEVEL_VC1_S_MEDIUM  = 0x41,
-   VCD_LEVEL_VC1_M_LOW     = 0x42,
-   VCD_LEVEL_VC1_M_MEDIUM  = 0x43,
-   VCD_LEVEL_VC1_M_HIGH    = 0x44,
-   VCD_LEVEL_VC1_A_0       = 0x45,
-   VCD_LEVEL_VC1_A_1       = 0x46,
-   VCD_LEVEL_VC1_A_2       = 0x47,
-   VCD_LEVEL_VC1_A_3       = 0x48,
-   VCD_LEVEL_VC1_A_4       = 0x49,
-   VCD_LEVEL_VC1_X         = 0x4A
-};
-
-struct vcd_property_level {
-	enum vcd_codec_level   level;
-};
-
-enum vcd_m_slice_sel {
-	VCD_MSLICE_OFF             = 0x1,
-	VCD_MSLICE_BY_MB_COUNT     = 0x2,
-	VCD_MSLICE_BY_BYTE_COUNT   = 0x3,
-	VCD_MSLICE_BY_GOB          = 0x4
-};
-
-struct vcd_property_multi_slice {
-	enum vcd_m_slice_sel   m_slice_sel;
-	u32             m_slice_size;
-};
-
-enum vcd_entropy_sel {
-	VCD_ENTROPY_SEL_CAVLC = 0x1,
-	VCD_ENTROPY_SEL_CABAC = 0x2
-};
-
-enum vcd_cabac_model {
-	VCD_CABAC_MODEL_NUMBER_0 = 0x1,
-	VCD_CABAC_MODEL_NUMBER_1 = 0x2,
-	VCD_CABAC_MODEL_NUMBER_2 = 0x3
-};
-
-struct vcd_property_entropy_control {
-	enum vcd_entropy_sel  entropy_sel;
-	enum vcd_cabac_model  cabac_model;
-};
-
-enum vcd_db_config {
-	VCD_DB_ALL_BLOCKING_BOUNDARY = 0x1,
-	VCD_DB_DISABLE               = 0x2,
-	VCD_DB_SKIP_SLICE_BOUNDARY   = 0x3
-};
-struct vcd_property_db_config {
-	enum vcd_db_config    db_config;
-	u32             slice_alpha_offset;
-	u32             slice_beta_offset;
-};
-
-enum vcd_rate_control {
-	VCD_RATE_CONTROL_OFF      = 0x1,
-	VCD_RATE_CONTROL_VBR_VFR  = 0x2,
-	VCD_RATE_CONTROL_VBR_CFR  = 0x3,
-	VCD_RATE_CONTROL_CBR_VFR  = 0x4,
-	VCD_RATE_CONTROL_CBR_CFR  = 0x5
-};
-
-struct vcd_property_rate_control {
-	enum vcd_rate_control     rate_control;
-};
-
-struct vcd_property_qp_range {
-	u32              max_qp;
-	u32              min_qp;
-};
-
-struct vcd_property_session_qp {
-	u32 i_frame_qp;
-	u32 p_frame_qp;
-	u32	b_frame_qp;
-};
-
-struct vcd_property_i_period {
-	u32 p_frames;
-	u32 b_frames;
-};
-
-struct vcd_property_vop_timing {
-	u32   vop_time_resolution;
-};
-
-struct vcd_property_short_header {
-	u32             short_header;
-};
-
-struct vcd_property_intra_refresh_mb_number {
-	u32            cir_mb_number;
-};
-
-struct vcd_property_req_i_frame {
-	u32        req_i_frame;
-};
-
-struct vcd_frame_rect{
-   u32   left;
-   u32   top;
-   u32   right;
-   u32   bottom;
-};
-
-struct vcd_property_dec_output_buffer {
-	struct vcd_frame_rect   disp_frm;
-	struct vcd_property_frame_size frm_size;
-};
-
-enum vcd_output_order {
-   VCD_DEC_ORDER_DISPLAY  = 0x0,
-   VCD_DEC_ORDER_DECODE   = 0x1
-};
-
-struct vcd_property_enc_recon_buffer{
-	u8 *user_virtual_addr;
-	u8 *kernel_virtual_addr;
-	u8 *physical_addr;
-	u8 *dev_addr;
-	u32 buffer_size;
-	u32 ysize;
-	int pmem_fd;
-	u32 offset;
-	void *client_data;
-};
-
-struct vcd_property_h264_mv_buffer{
-	u8 *kernel_virtual_addr;
-	u8 *physical_addr;
-	u32 size;
-	u32 count;
-	int pmem_fd;
-	u32 offset;
-	u8 *dev_addr;
-	void *client_data;
-};
-
-struct vcd_property_buffer_size{
-	int width;
-	int height;
-	int size;
-	int alignment;
-};
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
index 34a3445..dec9b4e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.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
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 #define NORMALIZATION_FACTOR 3600
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_status.h b/drivers/video/msm/vidc/common/vcd/vcd_status.h
deleted file mode 100644
index 1a36167..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_status.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (c) 2010-2011, 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 _VCD_ERR_STATUS_H_
-#define _VCD_ERR_STATUS_H_
-
-#define VCD_EVT_RESP_BASE                 0x1000
-#define VCD_EVT_RESP_OPEN                 (VCD_EVT_RESP_BASE + 0x1)
-#define VCD_EVT_RESP_START                (VCD_EVT_RESP_BASE + 0x2)
-#define VCD_EVT_RESP_STOP                 (VCD_EVT_RESP_BASE + 0x3)
-#define VCD_EVT_RESP_PAUSE                (VCD_EVT_RESP_BASE + 0x4)
-#define VCD_EVT_RESP_FLUSH_INPUT_DONE     (VCD_EVT_RESP_BASE + 0x5)
-#define VCD_EVT_RESP_FLUSH_OUTPUT_DONE    (VCD_EVT_RESP_BASE + 0x6)
-#define VCD_EVT_RESP_INPUT_FLUSHED        (VCD_EVT_RESP_BASE + 0x7)
-#define VCD_EVT_RESP_OUTPUT_FLUSHED       (VCD_EVT_RESP_BASE + 0x8)
-#define VCD_EVT_RESP_INPUT_DONE           (VCD_EVT_RESP_BASE + 0x9)
-#define VCD_EVT_RESP_OUTPUT_DONE          (VCD_EVT_RESP_BASE + 0xa)
-
-#define VCD_EVT_IND_BASE                  0x2000
-#define VCD_EVT_IND_INPUT_RECONFIG        (VCD_EVT_IND_BASE + 0x1)
-#define VCD_EVT_IND_OUTPUT_RECONFIG       (VCD_EVT_IND_BASE + 0x2)
-#define VCD_EVT_IND_HWERRFATAL            (VCD_EVT_IND_BASE + 0x3)
-#define VCD_EVT_IND_RESOURCES_LOST        (VCD_EVT_IND_BASE + 0x4)
-#define VCD_EVT_IND_INFO_OUTPUT_RECONFIG  (VCD_EVT_IND_BASE + 0x5)
-#define VCD_EVT_IND_INFO_FIELD_DROPPED    (VCD_EVT_IND_BASE + 0x6)
-
-#define VCD_S_SUCCESS           0x0
-
-#define VCD_S_ERR_BASE                    0x80000000
-#define VCD_ERR_FAIL                      (VCD_S_ERR_BASE + 0x01)
-#define VCD_ERR_ALLOC_FAIL                (VCD_S_ERR_BASE + 0x02)
-#define VCD_ERR_ILLEGAL_OP                (VCD_S_ERR_BASE + 0x03)
-#define VCD_ERR_ILLEGAL_PARM              (VCD_S_ERR_BASE + 0x04)
-#define VCD_ERR_BAD_POINTER               (VCD_S_ERR_BASE + 0x05)
-#define VCD_ERR_BAD_HANDLE                (VCD_S_ERR_BASE + 0x06)
-#define VCD_ERR_NOT_SUPPORTED             (VCD_S_ERR_BASE + 0x07)
-#define VCD_ERR_BAD_STATE                 (VCD_S_ERR_BASE + 0x08)
-#define VCD_ERR_BUSY                      (VCD_S_ERR_BASE + 0x09)
-#define VCD_ERR_MAX_CLIENT                (VCD_S_ERR_BASE + 0x0a)
-#define VCD_ERR_IFRAME_EXPECTED           (VCD_S_ERR_BASE + 0x0b)
-#define VCD_ERR_INTRLCD_FIELD_DROP        (VCD_S_ERR_BASE + 0x0c)
-#define VCD_ERR_HW_FATAL                  (VCD_S_ERR_BASE + 0x0d)
-#define VCD_ERR_BITSTREAM_ERR             (VCD_S_ERR_BASE + 0x0e)
-#define VCD_ERR_QEMPTY                    (VCD_S_ERR_BASE + 0x0f)
-#define VCD_ERR_SEQHDR_PARSE_FAIL         (VCD_S_ERR_BASE + 0x10)
-#define VCD_ERR_INPUT_NOT_PROCESSED       (VCD_S_ERR_BASE + 0x11)
-#define VCD_ERR_INDEX_NOMORE              (VCD_S_ERR_BASE + 0x12)
-
-#define VCD_FAILED(rc)   ((rc > VCD_S_ERR_BASE) ? true : false)
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 509b897..eec83b6b 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -13,7 +13,7 @@
 #include <linux/memory_alloc.h>
 #include <mach/msm_subsystem_map.h>
 #include <asm/div64.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 #include "vdec_internal.h"
 
@@ -36,9 +36,10 @@
 	u32 memtype, i = 0, flags = 0;
 	struct vcd_msm_map_buffer *map_buffer = NULL;
 	struct msm_mapped_buffer *mapped_buffer = NULL;
-	int rc = 0;
-	ion_phys_addr_t phyaddr = 0;
-	size_t len = 0;
+	unsigned long iova = 0;
+	unsigned long buffer_size = 0;
+	int ret = 0;
+	unsigned long ionflag = 0;
 
 	if (!kernel_vaddr || !phy_addr || !cctxt) {
 		pr_err("\n%s: Invalid parameters", __func__);
@@ -66,6 +67,22 @@
 			pr_err("%s() acm alloc failed", __func__);
 			goto free_map_table;
 		}
+		flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
+		map_buffer->mapped_buffer =
+		msm_subsystem_map_buffer((unsigned long)map_buffer->phy_addr,
+		sz, flags, vidc_mmu_subsystem,
+		sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
+		if (IS_ERR(map_buffer->mapped_buffer)) {
+			pr_err(" %s() buffer map failed", __func__);
+			goto free_acm_alloc;
+		}
+		mapped_buffer = map_buffer->mapped_buffer;
+		if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
+			pr_err("%s() map buffers failed", __func__);
+			goto free_map_buffers;
+		}
+		*phy_addr = (u8 *) mapped_buffer->iova[0];
+		*kernel_vaddr = (u8 *) mapped_buffer->vaddr;
 	} else {
 		map_buffer->alloc_handle = ion_alloc(
 			    cctxt->vcd_ion_client, sz, SZ_4K,
@@ -74,48 +91,58 @@
 			pr_err("%s() ION alloc failed", __func__);
 			goto bailout;
 		}
-		rc = ion_phys(cctxt->vcd_ion_client,
-		map_buffer->alloc_handle, &phyaddr, &len);
-		if (rc) {
-			pr_err("%s() : ION client physical fail\n",
-			 __func__);
-			goto free_acm_alloc;
+		if (ion_handle_get_flags(cctxt->vcd_ion_client,
+				map_buffer->alloc_handle,
+				&ionflag)) {
+			pr_err("%s() ION get flag failed", __func__);
+			goto bailout;
 		}
-		map_buffer->phy_addr = phyaddr;
+		*kernel_vaddr = (u8 *) ion_map_kernel(
+				cctxt->vcd_ion_client,
+				map_buffer->alloc_handle,
+				ionflag);
+		if (!(*kernel_vaddr)) {
+			pr_err("%s() ION map failed", __func__);
+			goto ion_free_bailout;
+		}
+		ret = ion_map_iommu(cctxt->vcd_ion_client,
+				map_buffer->alloc_handle,
+				VIDEO_DOMAIN,
+				VIDEO_MAIN_POOL,
+				SZ_4K,
+				0,
+				(unsigned long *)&iova,
+				(unsigned long *)&buffer_size,
+				UNCACHED, 0);
+		if (ret) {
+			pr_err("%s() ION iommu map failed", __func__);
+			goto ion_map_bailout;
+		}
+		map_buffer->phy_addr = iova;
 		if (!map_buffer->phy_addr) {
 			pr_err("%s() acm alloc failed", __func__);
 			goto free_map_table;
 		}
-
+		*phy_addr = (u8 *)iova;
+		mapped_buffer = NULL;
+		map_buffer->mapped_buffer = NULL;
 	}
 
-	flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
-	map_buffer->mapped_buffer =
-	msm_subsystem_map_buffer((unsigned long)map_buffer->phy_addr,
-	sz, flags, vidc_mmu_subsystem,
-	sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
-	if (IS_ERR(map_buffer->mapped_buffer)) {
-		pr_err(" %s() buffer map failed", __func__);
-		goto free_acm_alloc;
-	}
-	mapped_buffer = map_buffer->mapped_buffer;
-	if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
-		pr_err("%s() map buffers failed", __func__);
-		goto free_map_buffers;
-	}
-	*phy_addr = (u8 *) mapped_buffer->iova[0];
-	*kernel_vaddr = (u8 *) mapped_buffer->vaddr;
 	return 0;
 
 free_map_buffers:
-	msm_subsystem_unmap_buffer(map_buffer->mapped_buffer);
+	if (map_buffer->mapped_buffer)
+		msm_subsystem_unmap_buffer(map_buffer->mapped_buffer);
 free_acm_alloc:
 	if (!cctxt->vcd_enable_ion) {
 		free_contiguous_memory_by_paddr(
 		(unsigned long)map_buffer->phy_addr);
-	} else {
-		ion_free(cctxt->vcd_ion_client, map_buffer->alloc_handle);
 	}
+	return -ENOMEM;
+ion_map_bailout:
+	ion_unmap_kernel(cctxt->vcd_ion_client, map_buffer->alloc_handle);
+ion_free_bailout:
+	ion_free(cctxt->vcd_ion_client, map_buffer->alloc_handle);
 free_map_table:
 	map_buffer->in_use = 0;
 bailout:
@@ -145,9 +172,16 @@
 		pr_err("%s() Entry not found", __func__);
 		goto bailout;
 	}
-	msm_subsystem_unmap_buffer(map_buffer->mapped_buffer);
+	if (map_buffer->mapped_buffer)
+		msm_subsystem_unmap_buffer(map_buffer->mapped_buffer);
 	if (cctxt->vcd_enable_ion) {
 		if (map_buffer->alloc_handle) {
+			ion_unmap_kernel(cctxt->vcd_ion_client,
+					map_buffer->alloc_handle);
+			ion_unmap_iommu(cctxt->vcd_ion_client,
+					map_buffer->alloc_handle,
+					VIDEO_DOMAIN,
+					VIDEO_MAIN_POOL);
 			ion_free(cctxt->vcd_ion_client,
 			map_buffer->alloc_handle);
 		}
@@ -189,13 +223,15 @@
 }
 
 u32 vcd_get_ion_flag(struct video_client_ctx *client_ctx,
-			  unsigned long kernel_vaddr)
+			  unsigned long kernel_vaddr,
+			struct ion_handle **buff_ion_handle)
 {
 	unsigned long phy_addr, user_vaddr;
 	int pmem_fd;
 	struct file *file;
 	s32 buffer_index = -1;
 	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
 
 	if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT,
 					  false, &user_vaddr, &kernel_vaddr,
@@ -203,13 +239,17 @@
 					  &buffer_index)) {
 
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_INPUT,
-				pmem_fd, kernel_vaddr, buffer_index);
+				pmem_fd, kernel_vaddr, buffer_index,
+				&buff_handle);
+		*buff_ion_handle = buff_handle;
 		return ion_flag;
 	} else if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
 		false, &user_vaddr, &kernel_vaddr, &phy_addr, &pmem_fd, &file,
 		&buffer_index)) {
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
-				pmem_fd, kernel_vaddr, buffer_index);
+				pmem_fd, kernel_vaddr, buffer_index,
+				&buff_handle);
+		*buff_ion_handle = buff_handle;
 		return ion_flag;
 	} else {
 		VCD_MSG_ERROR("Couldn't get ion flag");
@@ -554,6 +594,7 @@
 	struct vcd_buffer_entry *buf_entry;
 	u8 *physical;
 	u32 ion_flag = 0;
+	struct ion_handle *buff_handle = NULL;
 
 	buf_entry = vcd_find_buffer_pool_entry(buf_pool, buffer);
 	if (buf_entry) {
@@ -566,8 +607,8 @@
 		cctxt->client_data, (unsigned long)buffer);
 
 	ion_flag = vcd_get_ion_flag(cctxt->client_data,
-				(unsigned long)buffer);
-
+				(unsigned long)buffer,
+				&buff_handle);
 	if (!physical) {
 		VCD_MSG_ERROR("Couldn't get physical address");
 		return VCD_ERR_BAD_POINTER;
@@ -591,6 +632,7 @@
 	buf_entry->frame.virtual = buf_entry->virtual;
 	buf_entry->frame.physical = buf_entry->physical;
 	buf_entry->frame.ion_flag = ion_flag;
+	buf_entry->frame.buff_ion_handle = buff_handle;
 
 	buf_pool->validated++;
 
@@ -1845,6 +1887,7 @@
 	struct vcd_transc *transc;
 	struct ddl_frame_data_tag *frame =
 		(struct ddl_frame_data_tag *) payload;
+	struct vcd_buffer_entry *orig_frame = NULL;
 	u32 rc;
 
 	if (!cctxt->status.frame_submitted &&
@@ -1859,6 +1902,8 @@
 	VCD_FAILED_RETURN(rc, "Bad input done payload");
 
 	transc = (struct vcd_transc *)frame->vcd_frm.ip_frm_tag;
+	orig_frame = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
+					 transc->ip_buf_entry->virtual);
 
 	if ((transc->ip_buf_entry->frame.virtual !=
 		 frame->vcd_frm.virtual)
@@ -1877,8 +1922,17 @@
 			sizeof(struct vcd_frame_data),
 			cctxt, cctxt->client_data);
 
-	transc->ip_buf_entry->in_use = false;
+	orig_frame->in_use--;
 	VCD_BUFFERPOOL_INUSE_DECREMENT(cctxt->in_buf_pool.in_use);
+
+	if (cctxt->decoding && orig_frame->in_use) {
+		VCD_MSG_ERROR("When decoding same input buffer not "
+				"supposed to be queued multiple times");
+		return VCD_ERR_FAIL;
+	}
+
+	if (orig_frame != transc->ip_buf_entry)
+		kfree(transc->ip_buf_entry);
 	transc->ip_buf_entry = NULL;
 	transc->input_done = true;
 
@@ -2598,7 +2652,7 @@
 	 struct vcd_frame_data *input_frame)
 {
 	struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
-	struct vcd_buffer_entry *buf_entry;
+	struct vcd_buffer_entry *buf_entry, *orig_frame;
 	struct vcd_frame_data *frm_entry;
 	u32 rc = VCD_S_SUCCESS;
 	u32 eos_handled = false;
@@ -2644,18 +2698,49 @@
 	}
 	VCD_FAILED_RETURN(rc, "Failed: First frame handling");
 
-	buf_entry = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
+	orig_frame = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
 						 input_frame->virtual);
-	if (!buf_entry) {
+	if (!orig_frame) {
 		VCD_MSG_ERROR("Bad buffer addr: %p", input_frame->virtual);
 		return VCD_ERR_FAIL;
 	}
 
-	if (buf_entry->in_use) {
-		VCD_MSG_ERROR("An inuse input frame is being"
-			"re-queued to scheduler");
-		return VCD_ERR_FAIL;
-	}
+	if (orig_frame->in_use) {
+		/*
+		 * This path only allowed for enc., dec. not allowed
+		 * to queue same buffer multiple times
+		 */
+		if (cctxt->decoding) {
+			VCD_MSG_ERROR("An inuse input frame is being "
+					"re-queued to scheduler");
+			return VCD_ERR_FAIL;
+		}
+
+		buf_entry = kzalloc(sizeof(*buf_entry), GFP_KERNEL);
+		if (!buf_entry) {
+			VCD_MSG_ERROR("Unable to alloc memory");
+			return VCD_ERR_FAIL;
+		}
+
+		INIT_LIST_HEAD(&buf_entry->sched_list);
+		/*
+		 * Pre-emptively poisoning this, as these dupe entries
+		 * shouldn't get added to any list
+		 */
+		INIT_LIST_HEAD(&buf_entry->list);
+		buf_entry->list.next = LIST_POISON1;
+		buf_entry->list.prev = LIST_POISON2;
+
+		buf_entry->valid = orig_frame->valid;
+		buf_entry->alloc = orig_frame->alloc;
+		buf_entry->virtual = orig_frame->virtual;
+		buf_entry->physical = orig_frame->physical;
+		buf_entry->sz = orig_frame->sz;
+		buf_entry->allocated = orig_frame->allocated;
+		buf_entry->in_use = 1; /* meaningless for the dupe buffers */
+		buf_entry->frame = orig_frame->frame;
+	} else
+		buf_entry = orig_frame;
 
 	if (input_frame->alloc_len > buf_entry->sz) {
 		VCD_MSG_ERROR("Bad buffer Alloc_len %d, Actual sz=%d",
@@ -2684,7 +2769,7 @@
 		cctxt->sched_clnt_hdl, buf_entry, true);
 	VCD_FAILED_RETURN(rc, "Failed: vcd_sched_queue_buffer");
 
-	buf_entry->in_use = true;
+	orig_frame->in_use++;
 	cctxt->in_buf_pool.in_use++;
 	vcd_try_submit_frame(dev_ctxt);
 	return rc;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_util.h b/drivers/video/msm/vidc/common/vcd/vcd_util.h
index 07ad651..7164029 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_util.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_util.h
@@ -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
@@ -12,8 +12,8 @@
  */
 #ifndef _VCD_UTIL_H_
 #define _VCD_UTIL_H_
-#include "vidc_type.h"
-#include "vcd_api.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
 
 #if DEBUG
 
diff --git a/drivers/video/msm/vidc/common/vcd/vidc_type.h b/drivers/video/msm/vidc/common/vcd/vidc_type.h
deleted file mode 100644
index bd87c0d..0000000
--- a/drivers/video/msm/vidc/common/vcd/vidc_type.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (c) 2010-2011, 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 VIDC_TYPE_H
-#define VIDC_TYPE_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/time.h>
-#include <linux/dma-mapping.h>
-#include <linux/android_pmem.h>
-
-#define DEBUG   0
-#define VIDC_ENABLE_DBGFS
-
-#define USE_RES_TRACKER
-#endif
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index cb163a5..3251a02 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -100,36 +100,32 @@
 			  u_int transp, struct fb_info *info)
 {
 	struct offb_par *par = (struct offb_par *) info->par;
-	int i, depth;
-	u32 *pal = info->pseudo_palette;
 
-	depth = info->var.bits_per_pixel;
-	if (depth == 16)
-		depth = (info->var.green.length == 5) ? 15 : 16;
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 *pal = info->pseudo_palette;
+		u32 cr = red >> (16 - info->var.red.length);
+		u32 cg = green >> (16 - info->var.green.length);
+		u32 cb = blue >> (16 - info->var.blue.length);
+		u32 value;
 
-	if (regno > 255 ||
-	    (depth == 16 && regno > 63) ||
-	    (depth == 15 && regno > 31))
-		return 1;
+		if (regno >= 16)
+			return -EINVAL;
 
-	if (regno < 16) {
-		switch (depth) {
-		case 15:
-			pal[regno] = (regno << 10) | (regno << 5) | regno;
-			break;
-		case 16:
-			pal[regno] = (regno << 11) | (regno << 5) | regno;
-			break;
-		case 24:
-			pal[regno] = (regno << 16) | (regno << 8) | regno;
-			break;
-		case 32:
-			i = (regno << 8) | regno;
-			pal[regno] = (i << 16) | i;
-			break;
+		value = (cr << info->var.red.offset) |
+			(cg << info->var.green.offset) |
+			(cb << info->var.blue.offset);
+		if (info->var.transp.length > 0) {
+			u32 mask = (1 << info->var.transp.length) - 1;
+			mask <<= info->var.transp.offset;
+			value |= mask;
 		}
+		pal[regno] = value;
+		return 0;
 	}
 
+	if (regno > 255)
+		return -EINVAL;
+
 	red >>= 8;
 	green >>= 8;
 	blue >>= 8;
@@ -381,7 +377,7 @@
 				int pitch, unsigned long address,
 				int foreign_endian, struct device_node *dp)
 {
-	unsigned long res_size = pitch * height * (depth + 7) / 8;
+	unsigned long res_size = pitch * height;
 	struct offb_par *par = &default_par;
 	unsigned long res_start = address;
 	struct fb_fix_screeninfo *fix;
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 7d54e2c..647ba98 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -1111,6 +1111,7 @@
 static void sh_hdmi_edid_work_fn(struct work_struct *work)
 {
 	struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
+	struct fb_info *info;
 	struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
 	struct sh_mobile_lcdc_chan *ch;
 	int ret;
@@ -1123,8 +1124,9 @@
 
 	mutex_lock(&hdmi->mutex);
 
+	info = hdmi->info;
+
 	if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
-		struct fb_info *info = hdmi->info;
 		unsigned long parent_rate = 0, hdmi_rate;
 
 		ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
@@ -1148,42 +1150,45 @@
 
 		ch = info->par;
 
-		console_lock();
+		if (lock_fb_info(info)) {
+			console_lock();
 
-		/* HDMI plug in */
-		if (!sh_hdmi_must_reconfigure(hdmi) &&
-		    info->state == FBINFO_STATE_RUNNING) {
-			/*
-			 * First activation with the default monitor - just turn
-			 * on, if we run a resume here, the logo disappears
-			 */
-			if (lock_fb_info(info)) {
+			/* HDMI plug in */
+			if (!sh_hdmi_must_reconfigure(hdmi) &&
+			    info->state == FBINFO_STATE_RUNNING) {
+				/*
+				 * First activation with the default monitor - just turn
+				 * on, if we run a resume here, the logo disappears
+				 */
 				info->var.width = hdmi->var.width;
 				info->var.height = hdmi->var.height;
 				sh_hdmi_display_on(hdmi, info);
-				unlock_fb_info(info);
+			} else {
+				/* New monitor or have to wake up */
+				fb_set_suspend(info, 0);
 			}
-		} else {
-			/* New monitor or have to wake up */
-			fb_set_suspend(info, 0);
-		}
 
-		console_unlock();
+			console_unlock();
+			unlock_fb_info(info);
+		}
 	} else {
 		ret = 0;
-		if (!hdmi->info)
+		if (!info)
 			goto out;
 
 		hdmi->monspec.modedb_len = 0;
 		fb_destroy_modedb(hdmi->monspec.modedb);
 		hdmi->monspec.modedb = NULL;
 
-		console_lock();
+		if (lock_fb_info(info)) {
+			console_lock();
 
-		/* HDMI disconnect */
-		fb_set_suspend(hdmi->info, 1);
+			/* HDMI disconnect */
+			fb_set_suspend(info, 1);
 
-		console_unlock();
+			console_unlock();
+			unlock_fb_info(info);
+		}
 	}
 
 out:
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
index 61b0bd5..1603023 100644
--- a/drivers/video/via/share.h
+++ b/drivers/video/via/share.h
@@ -557,8 +557,8 @@
 #define M1200X720_R60_VSP       POSITIVE
 
 /* 1200x900@60 Sync Polarity (DCON) */
-#define M1200X900_R60_HSP       NEGATIVE
-#define M1200X900_R60_VSP       NEGATIVE
+#define M1200X900_R60_HSP       POSITIVE
+#define M1200X900_R60_VSP       POSITIVE
 
 /* 1280x600@60 Sync Polarity (GTF Mode) */
 #define M1280x600_R60_HSP       NEGATIVE
diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h
index ae35cfd..0138845 100644
--- a/drivers/video/via/via_modesetting.h
+++ b/drivers/video/via/via_modesetting.h
@@ -28,6 +28,11 @@
 
 #include <linux/types.h>
 
+
+#define VIA_PITCH_SIZE	(1<<3)
+#define VIA_PITCH_MAX	0x3FF8
+
+
 void via_set_primary_address(u32 addr);
 void via_set_secondary_address(u32 addr);
 void via_set_primary_pitch(u32 pitch);
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index cf43c80..dd1276e 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -151,7 +151,8 @@
 
 	info->fix.visual =
 		bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-	info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
+	info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
+		VIA_PITCH_SIZE);
 }
 
 static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
@@ -238,8 +239,12 @@
 		depth = 24;
 
 	viafb_fill_var_color_info(var, depth);
-	line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
-	if (line * var->yres_virtual > ppar->memsize)
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
+		VIA_PITCH_SIZE);
+	if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
 		return -EINVAL;
 
 	/* Based on var passed in to calculate the refresh,
@@ -348,8 +353,9 @@
 	struct fb_info *info)
 {
 	struct viafb_par *viapar = info->par;
-	u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset)
-		* (var->bits_per_pixel / 8) + viapar->vram_addr;
+	u32 vram_addr = viapar->vram_addr
+		+ var->yoffset * info->fix.line_length
+		+ var->xoffset * info->var.bits_per_pixel / 8;
 
 	DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
 	if (!viafb_dual_fb) {
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index 4bcc8b8..ecb9254 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -590,11 +590,11 @@
 
 static void virtio_pci_release_dev(struct device *_d)
 {
-	struct virtio_device *dev = container_of(_d, struct virtio_device,
-						 dev);
-	struct virtio_pci_device *vp_dev = to_vp_device(dev);
-
-	kfree(vp_dev);
+	/*
+	 * No need for a release method as we allocate/free
+	 * all devices together with the pci devices.
+	 * Provide an empty one to avoid getting a warning from core.
+	 */
 }
 
 /* the PCI probing function */
@@ -682,6 +682,7 @@
 	pci_iounmap(pci_dev, vp_dev->ioaddr);
 	pci_release_regions(pci_dev);
 	pci_disable_device(pci_dev);
+	kfree(vp_dev);
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
index 274c8f3..505b17d 100644
--- a/drivers/w1/slaves/w1_ds2780.c
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -26,20 +26,14 @@
 #include "../w1_family.h"
 #include "w1_ds2780.h"
 
-int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
-			int io)
+static int w1_ds2780_do_io(struct device *dev, char *buf, int addr,
+			size_t count, int io)
 {
 	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
 
-	if (!dev)
-		return -ENODEV;
+	if (addr > DS2780_DATA_SIZE || addr < 0)
+		return 0;
 
-	mutex_lock(&sl->master->mutex);
-
-	if (addr > DS2780_DATA_SIZE || addr < 0) {
-		count = 0;
-		goto out;
-	}
 	count = min_t(int, count, DS2780_DATA_SIZE - addr);
 
 	if (w1_reset_select_slave(sl) == 0) {
@@ -47,7 +41,6 @@
 			w1_write_8(sl->master, W1_DS2780_WRITE_DATA);
 			w1_write_8(sl->master, addr);
 			w1_write_block(sl->master, buf, count);
-			/* XXX w1_write_block returns void, not n_written */
 		} else {
 			w1_write_8(sl->master, W1_DS2780_READ_DATA);
 			w1_write_8(sl->master, addr);
@@ -55,13 +48,42 @@
 		}
 	}
 
-out:
-	mutex_unlock(&sl->master->mutex);
-
 	return count;
 }
+
+int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
+			int io)
+{
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&sl->master->mutex);
+
+	ret = w1_ds2780_do_io(dev, buf, addr, count, io);
+
+	mutex_unlock(&sl->master->mutex);
+
+	return ret;
+}
 EXPORT_SYMBOL(w1_ds2780_io);
 
+int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr, size_t count,
+			int io)
+{
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	ret = w1_ds2780_do_io(dev, buf, addr, count, io);
+
+	return ret;
+}
+EXPORT_SYMBOL(w1_ds2780_io_nolock);
+
 int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
 {
 	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h
index a1fba79..7373793 100644
--- a/drivers/w1/slaves/w1_ds2780.h
+++ b/drivers/w1/slaves/w1_ds2780.h
@@ -124,6 +124,8 @@
 
 extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
 			int io);
+extern int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr,
+			size_t count, int io);
 extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd);
 
 #endif /* !_W1_DS2780_H */
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 8cb2685..9cb60df 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -216,6 +216,7 @@
 
 	cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE;
 
+	set_memory_x((unsigned long)bios32_entrypoint, (2 * PAGE_SIZE));
 	asminline_call(&cmn_regs, bios32_entrypoint);
 
 	if (cmn_regs.u1.ral != 0) {
@@ -233,8 +234,10 @@
 		if ((physical_bios_base + physical_bios_offset)) {
 			cru_rom_addr =
 				ioremap(cru_physical_address, cru_length);
-			if (cru_rom_addr)
+			if (cru_rom_addr) {
+				set_memory_x((unsigned long)cru_rom_addr, cru_length);
 				retval = 0;
+			}
 		}
 
 		printk(KERN_DEBUG "hpwdt: CRU Base Address:   0x%lx\n",
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 30df85d..a5493f8 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -1026,7 +1026,7 @@
 	if (irq < 0)
 		return irq;
 
-	irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME;
+	irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME | IRQF_EARLY_RESUME;
 	retval = request_irq(irq, handler, irqflags, devname, dev_id);
 	if (retval != 0) {
 		unbind_from_irq(irq);
diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
index f6832f4..e1c4c6e 100644
--- a/drivers/xen/gntalloc.c
+++ b/drivers/xen/gntalloc.c
@@ -135,7 +135,7 @@
 		/* Grant foreign access to the page. */
 		gref->gref_id = gnttab_grant_foreign_access(op->domid,
 			pfn_to_mfn(page_to_pfn(gref->page)), readonly);
-		if (gref->gref_id < 0) {
+		if ((int)gref->gref_id < 0) {
 			rc = gref->gref_id;
 			goto undo;
 		}
@@ -280,7 +280,7 @@
 		goto out;
 	}
 
-	gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY);
+	gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_TEMPORARY);
 	if (!gref_ids) {
 		rc = -ENOMEM;
 		goto out;
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 6e8c15a..fd60dff 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -162,7 +162,7 @@
 	/*
 	 * Get IO TLB memory from any location.
 	 */
-	xen_io_tlb_start = alloc_bootmem(bytes);
+	xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
 	if (!xen_io_tlb_start)
 		panic("Cannot allocate SWIOTLB buffer");
 
@@ -278,9 +278,10 @@
 	/*
 	 * Ensure that the address returned is DMA'ble
 	 */
-	if (!dma_capable(dev, dev_addr, size))
-		panic("map_single: bounce buffer is not DMA'ble");
-
+	if (!dma_capable(dev, dev_addr, size)) {
+		swiotlb_tbl_unmap_single(dev, map, size, dir);
+		dev_addr = 0;
+	}
 	return dev_addr;
 }
 EXPORT_SYMBOL_GPL(xen_swiotlb_map_page);
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 5534690..daee5db 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -801,6 +801,12 @@
 		goto out;
 	}
 
+	if (msg->hdr.len > XENSTORE_PAYLOAD_MAX) {
+		kfree(msg);
+		err = -EINVAL;
+		goto out;
+	}
+
 	body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH);
 	if (body == NULL) {
 		kfree(msg);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 303983f..9ba2ac7 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -796,7 +796,16 @@
 			 * might try to exec.  This is because the brk will
 			 * follow the loader, and is not movable.  */
 #if defined(CONFIG_X86) || defined(CONFIG_ARM)
-			load_bias = 0;
+			/* Memory randomization might have been switched off
+			 * in runtime via sysctl.
+			 * If that is the case, retain the original non-zero
+			 * load_bias value in order to establish proper
+			 * non-randomized mappings.
+			 */
+			if (current->flags & PF_RANDOMIZE)
+				load_bias = 0;
+			else
+				load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
 #else
 			load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
 #endif
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 194cf66..34503ba 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1075,6 +1075,7 @@
 static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
 {
 	struct gendisk *disk;
+	struct module *owner;
 	int ret;
 	int partno;
 	int perm = 0;
@@ -1100,6 +1101,7 @@
 	disk = get_gendisk(bdev->bd_dev, &partno);
 	if (!disk)
 		goto out;
+	owner = disk->fops->owner;
 
 	disk_block_events(disk);
 	mutex_lock_nested(&bdev->bd_mutex, for_part);
@@ -1127,8 +1129,8 @@
 					bdev->bd_disk = NULL;
 					mutex_unlock(&bdev->bd_mutex);
 					disk_unblock_events(disk);
-					module_put(disk->fops->owner);
 					put_disk(disk);
+					module_put(owner);
 					goto restart;
 				}
 			}
@@ -1184,8 +1186,8 @@
 				goto out_unlock_bdev;
 		}
 		/* only one opener holds refs to the module and disk */
-		module_put(disk->fops->owner);
 		put_disk(disk);
+		module_put(owner);
 	}
 	bdev->bd_openers++;
 	if (for_part)
@@ -1205,8 +1207,8 @@
  out_unlock_bdev:
 	mutex_unlock(&bdev->bd_mutex);
 	disk_unblock_events(disk);
-	module_put(disk->fops->owner);
 	put_disk(disk);
+	module_put(owner);
  out:
 	bdput(bdev);
 
@@ -1432,14 +1434,15 @@
 	if (!bdev->bd_openers) {
 		struct module *owner = disk->fops->owner;
 
-		put_disk(disk);
-		module_put(owner);
 		disk_put_part(bdev->bd_part);
 		bdev->bd_part = NULL;
 		bdev->bd_disk = NULL;
 		if (bdev != bdev->bd_contains)
 			victim = bdev->bd_contains;
 		bdev->bd_contains = NULL;
+
+		put_disk(disk);
+		module_put(owner);
 	}
 	mutex_unlock(&bdev->bd_mutex);
 	bdput(bdev);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 2451627..cb85825 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2767,10 +2767,10 @@
 
 /*
  * When the server doesn't allow large posix writes, only allow a wsize of
- * 128k minus the size of the WRITE_AND_X header. That allows for a write up
+ * 2^17-1 minus the size of the WRITE_AND_X header. That allows for a write up
  * to the maximum size described by RFC1002.
  */
-#define CIFS_MAX_RFC1002_WSIZE (128 * 1024 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
 
 /*
  * The default wsize is 1M. find_get_pages seems to return a maximum of 256
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a7b2dcd..745e5cd 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -562,7 +562,16 @@
 
 	xid = GetXid();
 	rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
-	if (rc == -EOPNOTSUPP || rc == -EINVAL) {
+	switch (rc) {
+	case 0:
+		cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
+		break;
+	case -EREMOTE:
+		cifs_create_dfs_fattr(&fattr, inode->i_sb);
+		rc = 0;
+		break;
+	case -EOPNOTSUPP:
+	case -EINVAL:
 		/*
 		 * FIXME: legacy server -- fall back to path-based call?
 		 * for now, just skip revalidating and mark inode for
@@ -570,18 +579,14 @@
 		 */
 		rc = 0;
 		CIFS_I(inode)->time = 0;
+	default:
 		goto cgfi_exit;
-	} else if (rc == -EREMOTE) {
-		cifs_create_dfs_fattr(&fattr, inode->i_sb);
-		rc = 0;
-	} else if (rc)
-		goto cgfi_exit;
+	}
 
 	/*
 	 * don't bother with SFU junk here -- just mark inode as needing
 	 * revalidation.
 	 */
-	cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
 	fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
 	fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
 	cifs_fattr_to_inode(inode, &fattr);
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index d3e6196..0cfae19 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -244,16 +244,15 @@
 	/* copy user */
 	/* BB what about null user mounts - check that we do this BB */
 	/* copy user */
-	if (ses->user_name != NULL)
+	if (ses->user_name != NULL) {
 		strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE);
+		bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE);
+	}
 	/* else null user mount */
-
-	bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE);
 	*bcc_ptr = 0;
 	bcc_ptr++; /* account for null termination */
 
 	/* copy domain */
-
 	if (ses->domainName != NULL) {
 		strncpy(bcc_ptr, ses->domainName, 256);
 		bcc_ptr += strnlen(ses->domainName, 256);
diff --git a/fs/dcache.c b/fs/dcache.c
index fbdcbca..f598b98 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -241,6 +241,7 @@
 static void __dentry_lru_del(struct dentry *dentry)
 {
 	list_del_init(&dentry->d_lru);
+	dentry->d_flags &= ~DCACHE_SHRINK_LIST;
 	dentry->d_sb->s_nr_dentry_unused--;
 	dentry_stat.nr_unused--;
 }
@@ -753,6 +754,7 @@
 			spin_unlock(&dentry->d_lock);
 		} else {
 			list_move_tail(&dentry->d_lru, &tmp);
+			dentry->d_flags |= DCACHE_SHRINK_LIST;
 			spin_unlock(&dentry->d_lock);
 			if (!--cnt)
 				break;
@@ -1144,14 +1146,18 @@
 		/* 
 		 * move only zero ref count dentries to the end 
 		 * of the unused list for prune_dcache
+		 *
+		 * Those which are presently on the shrink list, being processed
+		 * by shrink_dentry_list(), shouldn't be moved.  Otherwise the
+		 * loop in shrink_dcache_parent() might not make any progress
+		 * and loop forever.
 		 */
-		if (!dentry->d_count) {
+		if (dentry->d_count) {
+			dentry_lru_del(dentry);
+		} else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
 			dentry_lru_move_tail(dentry);
 			found++;
-		} else {
-			dentry_lru_del(dentry);
 		}
-
 		/*
 		 * We can return to the caller if we have found some (this
 		 * ensures forward progress). We'll be coming back to find
@@ -2487,16 +2493,14 @@
 /**
  * prepend_path - Prepend path string to a buffer
  * @path: the dentry/vfsmount to report
- * @root: root vfsmnt/dentry (may be modified by this function)
+ * @root: root vfsmnt/dentry
  * @buffer: pointer to the end of the buffer
  * @buflen: pointer to buffer length
  *
  * Caller holds the rename_lock.
- *
- * If path is not reachable from the supplied root, then the value of
- * root is changed (without modifying refcounts).
  */
-static int prepend_path(const struct path *path, struct path *root,
+static int prepend_path(const struct path *path,
+			const struct path *root,
 			char **buffer, int *buflen)
 {
 	struct dentry *dentry = path->dentry;
@@ -2531,10 +2535,10 @@
 		dentry = parent;
 	}
 
-out:
 	if (!error && !slash)
 		error = prepend(buffer, buflen, "/", 1);
 
+out:
 	br_read_unlock(vfsmount_lock);
 	return error;
 
@@ -2548,15 +2552,17 @@
 		WARN(1, "Root dentry has weird name <%.*s>\n",
 		     (int) dentry->d_name.len, dentry->d_name.name);
 	}
-	root->mnt = vfsmnt;
-	root->dentry = dentry;
+	if (!slash)
+		error = prepend(buffer, buflen, "/", 1);
+	if (!error)
+		error = vfsmnt->mnt_ns ? 1 : 2;
 	goto out;
 }
 
 /**
  * __d_path - return the path of a dentry
  * @path: the dentry/vfsmount to report
- * @root: root vfsmnt/dentry (may be modified by this function)
+ * @root: root vfsmnt/dentry
  * @buf: buffer to return value in
  * @buflen: buffer length
  *
@@ -2567,10 +2573,10 @@
  *
  * "buflen" should be positive.
  *
- * If path is not reachable from the supplied root, then the value of
- * root is changed (without modifying refcounts).
+ * If the path is not reachable from the supplied root, return %NULL.
  */
-char *__d_path(const struct path *path, struct path *root,
+char *__d_path(const struct path *path,
+	       const struct path *root,
 	       char *buf, int buflen)
 {
 	char *res = buf + buflen;
@@ -2581,7 +2587,28 @@
 	error = prepend_path(path, root, &res, &buflen);
 	write_sequnlock(&rename_lock);
 
-	if (error)
+	if (error < 0)
+		return ERR_PTR(error);
+	if (error > 0)
+		return NULL;
+	return res;
+}
+
+char *d_absolute_path(const struct path *path,
+	       char *buf, int buflen)
+{
+	struct path root = {};
+	char *res = buf + buflen;
+	int error;
+
+	prepend(&res, &buflen, "\0", 1);
+	write_seqlock(&rename_lock);
+	error = prepend_path(path, &root, &res, &buflen);
+	write_sequnlock(&rename_lock);
+
+	if (error > 1)
+		error = -EINVAL;
+	if (error < 0)
 		return ERR_PTR(error);
 	return res;
 }
@@ -2589,8 +2616,9 @@
 /*
  * same as __d_path but appends "(deleted)" for unlinked files.
  */
-static int path_with_deleted(const struct path *path, struct path *root,
-				 char **buf, int *buflen)
+static int path_with_deleted(const struct path *path,
+			     const struct path *root,
+			     char **buf, int *buflen)
 {
 	prepend(buf, buflen, "\0", 1);
 	if (d_unlinked(path->dentry)) {
@@ -2627,7 +2655,6 @@
 {
 	char *res = buf + buflen;
 	struct path root;
-	struct path tmp;
 	int error;
 
 	/*
@@ -2642,9 +2669,8 @@
 
 	get_fs_root(current->fs, &root);
 	write_seqlock(&rename_lock);
-	tmp = root;
-	error = path_with_deleted(path, &tmp, &res, &buflen);
-	if (error)
+	error = path_with_deleted(path, &root, &res, &buflen);
+	if (error < 0)
 		res = ERR_PTR(error);
 	write_sequnlock(&rename_lock);
 	path_put(&root);
@@ -2665,7 +2691,6 @@
 {
 	char *res = buf + buflen;
 	struct path root;
-	struct path tmp;
 	int error;
 
 	if (path->dentry->d_op && path->dentry->d_op->d_dname)
@@ -2673,9 +2698,8 @@
 
 	get_fs_root(current->fs, &root);
 	write_seqlock(&rename_lock);
-	tmp = root;
-	error = path_with_deleted(path, &tmp, &res, &buflen);
-	if (!error && !path_equal(&tmp, &root))
+	error = path_with_deleted(path, &root, &res, &buflen);
+	if (error > 0)
 		error = prepend_unreachable(&res, &buflen);
 	write_sequnlock(&rename_lock);
 	path_put(&root);
@@ -2806,19 +2830,18 @@
 	write_seqlock(&rename_lock);
 	if (!d_unlinked(pwd.dentry)) {
 		unsigned long len;
-		struct path tmp = root;
 		char *cwd = page + PAGE_SIZE;
 		int buflen = PAGE_SIZE;
 
 		prepend(&cwd, &buflen, "\0", 1);
-		error = prepend_path(&pwd, &tmp, &cwd, &buflen);
+		error = prepend_path(&pwd, &root, &cwd, &buflen);
 		write_sequnlock(&rename_lock);
 
-		if (error)
+		if (error < 0)
 			goto out;
 
 		/* Unreachable from current root */
-		if (!path_equal(&tmp, &root)) {
+		if (error > 0) {
 			error = prepend_unreachable(&cwd, &buflen);
 			if (error)
 				goto out;
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 58609bd..c6602d2 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -417,17 +417,6 @@
 			(unsigned long long)(extent_base + extent_offset), rc);
 		goto out;
 	}
-	if (unlikely(ecryptfs_verbosity > 0)) {
-		ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
-				"with iv:\n");
-		ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
-		ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
-				"encryption:\n");
-		ecryptfs_dump_hex((char *)
-				  (page_address(page)
-				   + (extent_offset * crypt_stat->extent_size)),
-				  8);
-	}
 	rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0,
 					  page, (extent_offset
 						 * crypt_stat->extent_size),
@@ -440,14 +429,6 @@
 		goto out;
 	}
 	rc = 0;
-	if (unlikely(ecryptfs_verbosity > 0)) {
-		ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16llx]; "
-			"rc = [%d]\n",
-			(unsigned long long)(extent_base + extent_offset), rc);
-		ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
-				"encryption:\n");
-		ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8);
-	}
 out:
 	return rc;
 }
@@ -543,17 +524,6 @@
 			(unsigned long long)(extent_base + extent_offset), rc);
 		goto out;
 	}
-	if (unlikely(ecryptfs_verbosity > 0)) {
-		ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
-				"with iv:\n");
-		ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
-		ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
-				"decryption:\n");
-		ecryptfs_dump_hex((char *)
-				  (page_address(enc_extent_page)
-				   + (extent_offset * crypt_stat->extent_size)),
-				  8);
-	}
 	rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
 					  (extent_offset
 					   * crypt_stat->extent_size),
@@ -567,16 +537,6 @@
 		goto out;
 	}
 	rc = 0;
-	if (unlikely(ecryptfs_verbosity > 0)) {
-		ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16llx]; "
-			"rc = [%d]\n",
-			(unsigned long long)(extent_base + extent_offset), rc);
-		ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
-				"decryption:\n");
-		ecryptfs_dump_hex((char *)(page_address(page)
-					   + (extent_offset
-					      * crypt_stat->extent_size)), 8);
-	}
 out:
 	return rc;
 }
@@ -1618,7 +1578,8 @@
 		rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode);
 		if (rc) {
 			printk(KERN_DEBUG "Valid eCryptfs headers not found in "
-			       "file header region or xattr region\n");
+			       "file header region or xattr region, inode %lu\n",
+				ecryptfs_inode->i_ino);
 			rc = -EINVAL;
 			goto out;
 		}
@@ -1627,7 +1588,8 @@
 						ECRYPTFS_DONT_VALIDATE_HEADER_SIZE);
 		if (rc) {
 			printk(KERN_DEBUG "Valid eCryptfs headers not found in "
-			       "file xattr region either\n");
+			       "file xattr region either, inode %lu\n",
+				ecryptfs_inode->i_ino);
 			rc = -EINVAL;
 		}
 		if (crypt_stat->mount_crypt_stat->flags
@@ -1638,7 +1600,8 @@
 			       "crypto metadata only in the extended attribute "
 			       "region, but eCryptfs was mounted without "
 			       "xattr support enabled. eCryptfs will not treat "
-			       "this like an encrypted file.\n");
+			       "this like an encrypted file, inode %lu\n",
+				ecryptfs_inode->i_ino);
 			rc = -EINVAL;
 		}
 	}
@@ -1943,7 +1906,7 @@
 
 /* We could either offset on every reverse map or just pad some 0x00's
  * at the front here */
-static const unsigned char filename_rev_map[] = {
+static const unsigned char filename_rev_map[256] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 15 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */
@@ -1959,7 +1922,7 @@
 	0x00, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, /* 103 */
 	0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, /* 111 */
 	0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, /* 119 */
-	0x3D, 0x3E, 0x3F
+	0x3D, 0x3E, 0x3F /* 123 - 255 initialized to 0x00 */
 };
 
 /**
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 4ec9eb0..0c1a652 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -139,6 +139,27 @@
 	return rc;
 }
 
+static void ecryptfs_vma_close(struct vm_area_struct *vma)
+{
+	filemap_write_and_wait(vma->vm_file->f_mapping);
+}
+
+static const struct vm_operations_struct ecryptfs_file_vm_ops = {
+	.close		= ecryptfs_vma_close,
+	.fault		= filemap_fault,
+};
+
+static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int rc;
+
+	rc = generic_file_mmap(file, vma);
+	if (!rc)
+		vma->vm_ops = &ecryptfs_file_vm_ops;
+
+	return rc;
+}
+
 struct kmem_cache *ecryptfs_file_info_cache;
 
 /**
@@ -348,7 +369,7 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl = ecryptfs_compat_ioctl,
 #endif
-	.mmap = generic_file_mmap,
+	.mmap = ecryptfs_file_mmap,
 	.open = ecryptfs_open,
 	.flush = ecryptfs_flush,
 	.release = ecryptfs_release,
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 4a4fad7f..e3562f2 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -854,18 +854,6 @@
 		size_t num_zeros = (PAGE_CACHE_SIZE
 				    - (ia->ia_size & ~PAGE_CACHE_MASK));
 
-
-		/*
-		 * XXX(truncate) this should really happen at the begginning
-		 * of ->setattr.  But the code is too messy to that as part
-		 * of a larger patch.  ecryptfs is also totally missing out
-		 * on the inode_change_ok check at the beginning of
-		 * ->setattr while would include this.
-		 */
-		rc = inode_newsize_ok(inode, ia->ia_size);
-		if (rc)
-			goto out;
-
 		if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
 			truncate_setsize(inode, ia->ia_size);
 			lower_ia->ia_size = ia->ia_size;
@@ -915,6 +903,28 @@
 	return rc;
 }
 
+static int ecryptfs_inode_newsize_ok(struct inode *inode, loff_t offset)
+{
+	struct ecryptfs_crypt_stat *crypt_stat;
+	loff_t lower_oldsize, lower_newsize;
+
+	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+	lower_oldsize = upper_size_to_lower_size(crypt_stat,
+						 i_size_read(inode));
+	lower_newsize = upper_size_to_lower_size(crypt_stat, offset);
+	if (lower_newsize > lower_oldsize) {
+		/*
+		 * The eCryptfs inode and the new *lower* size are mixed here
+		 * because we may not have the lower i_mutex held and/or it may
+		 * not be appropriate to call inode_newsize_ok() with inodes
+		 * from other filesystems.
+		 */
+		return inode_newsize_ok(inode, lower_newsize);
+	}
+
+	return 0;
+}
+
 /**
  * ecryptfs_truncate
  * @dentry: The ecryptfs layer dentry
@@ -931,6 +941,10 @@
 	struct iattr lower_ia = { .ia_valid = 0 };
 	int rc;
 
+	rc = ecryptfs_inode_newsize_ok(dentry->d_inode, new_length);
+	if (rc)
+		return rc;
+
 	rc = truncate_upper(dentry, &ia, &lower_ia);
 	if (!rc && lower_ia.ia_valid & ATTR_SIZE) {
 		struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
@@ -1012,6 +1026,16 @@
 		}
 	}
 	mutex_unlock(&crypt_stat->cs_mutex);
+
+	rc = inode_change_ok(inode, ia);
+	if (rc)
+		goto out;
+	if (ia->ia_valid & ATTR_SIZE) {
+		rc = ecryptfs_inode_newsize_ok(inode, ia->ia_size);
+		if (rc)
+			goto out;
+	}
+
 	if (S_ISREG(inode->i_mode)) {
 		rc = filemap_write_and_wait(inode->i_mapping);
 		if (rc)
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
index 940a82e..0dc5a3d 100644
--- a/fs/ecryptfs/miscdev.c
+++ b/fs/ecryptfs/miscdev.c
@@ -409,11 +409,47 @@
 	ssize_t sz = 0;
 	char *data;
 	uid_t euid = current_euid();
+	unsigned char packet_size_peek[3];
 	int rc;
 
-	if (count == 0)
+	if (count == 0) {
 		goto out;
+	} else if (count == (1 + 4)) {
+		/* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */
+		goto memdup;
+	} else if (count < (1 + 4 + 1)
+		   || count > (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4
+			       + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)) {
+		printk(KERN_WARNING "%s: Acceptable packet size range is "
+		       "[%d-%lu], but amount of data written is [%zu].",
+		       __func__, (1 + 4 + 1),
+		       (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4
+			+ ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES), count);
+		return -EINVAL;
+	}
 
+	if (copy_from_user(packet_size_peek, (buf + 1 + 4),
+			   sizeof(packet_size_peek))) {
+		printk(KERN_WARNING "%s: Error while inspecting packet size\n",
+		       __func__);
+		return -EFAULT;
+	}
+
+	rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size,
+					  &packet_size_length);
+	if (rc) {
+		printk(KERN_WARNING "%s: Error parsing packet length; "
+		       "rc = [%d]\n", __func__, rc);
+		return rc;
+	}
+
+	if ((1 + 4 + packet_size_length + packet_size) != count) {
+		printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__,
+		       packet_size);
+		return -EINVAL;
+	}
+
+memdup:
 	data = memdup_user(buf, count);
 	if (IS_ERR(data)) {
 		printk(KERN_ERR "%s: memdup_user returned error [%ld]\n",
@@ -435,23 +471,7 @@
 		}
 		memcpy(&counter_nbo, &data[i], 4);
 		seq = be32_to_cpu(counter_nbo);
-		i += 4;
-		rc = ecryptfs_parse_packet_length(&data[i], &packet_size,
-						  &packet_size_length);
-		if (rc) {
-			printk(KERN_WARNING "%s: Error parsing packet length; "
-			       "rc = [%d]\n", __func__, rc);
-			goto out_free;
-		}
-		i += packet_size_length;
-		if ((1 + 4 + packet_size_length + packet_size) != count) {
-			printk(KERN_WARNING "%s: (1 + packet_size_length([%zd])"
-			       " + packet_size([%zd]))([%zd]) != "
-			       "count([%zd]). Invalid packet format.\n",
-			       __func__, packet_size_length, packet_size,
-			       (1 + packet_size_length + packet_size), count);
-			goto out_free;
-		}
+		i += 4 + packet_size_length;
 		rc = ecryptfs_miscdev_response(&data[i], packet_size,
 					       euid, current_user_ns(),
 					       task_pid(current), seq);
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index 3745f7c..608c1c3 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -130,13 +130,18 @@
 		pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);
 		size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);
 		size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);
-		size_t total_remaining_bytes = ((offset + size) - pos);
+		loff_t total_remaining_bytes = ((offset + size) - pos);
+
+		if (fatal_signal_pending(current)) {
+			rc = -EINTR;
+			break;
+		}
 
 		if (num_bytes > total_remaining_bytes)
 			num_bytes = total_remaining_bytes;
 		if (pos < offset) {
 			/* remaining zeros to write, up to destination offset */
-			size_t total_remaining_zeros = (offset - pos);
+			loff_t total_remaining_zeros = (offset - pos);
 
 			if (num_bytes > total_remaining_zeros)
 				num_bytes = total_remaining_zeros;
@@ -193,15 +198,19 @@
 		}
 		pos += num_bytes;
 	}
-	if ((offset + size) > ecryptfs_file_size) {
-		i_size_write(ecryptfs_inode, (offset + size));
+	if (pos > ecryptfs_file_size) {
+		i_size_write(ecryptfs_inode, pos);
 		if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) {
-			rc = ecryptfs_write_inode_size_to_metadata(
+			int rc2;
+
+			rc2 = ecryptfs_write_inode_size_to_metadata(
 								ecryptfs_inode);
-			if (rc) {
+			if (rc2) {
 				printk(KERN_ERR	"Problem with "
 				       "ecryptfs_write_inode_size_to_metadata; "
-				       "rc = [%d]\n", rc);
+				       "rc = [%d]\n", rc2);
+				if (!rc)
+					rc = rc2;
 				goto out;
 			}
 		}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index f9cfd16..2acaf60 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -70,6 +70,15 @@
  * simultaneous inserts (A into B and B into A) from racing and
  * constructing a cycle without either insert observing that it is
  * going to.
+ * It is necessary to acquire multiple "ep->mtx"es at once in the
+ * case when one epoll fd is added to another. In this case, we
+ * always acquire the locks in the order of nesting (i.e. after
+ * epoll_ctl(e1, EPOLL_CTL_ADD, e2), e1->mtx will always be acquired
+ * before e2->mtx). Since we disallow cycles of epoll file
+ * descriptors, this ensures that the mutexes are well-ordered. In
+ * order to communicate this nesting to lockdep, when walking a tree
+ * of epoll file descriptors, we use the current recursion depth as
+ * the lockdep subkey.
  * It is possible to drop the "ep->mtx" and to use the global
  * mutex "epmutex" (together with "ep->lock") to have it working,
  * but having "ep->mtx" will make the interface more scalable.
@@ -464,13 +473,15 @@
  * @ep: Pointer to the epoll private data structure.
  * @sproc: Pointer to the scan callback.
  * @priv: Private opaque data passed to the @sproc callback.
+ * @depth: The current depth of recursive f_op->poll calls.
  *
  * Returns: The same integer error code returned by the @sproc callback.
  */
 static int ep_scan_ready_list(struct eventpoll *ep,
 			      int (*sproc)(struct eventpoll *,
 					   struct list_head *, void *),
-			      void *priv)
+			      void *priv,
+			      int depth)
 {
 	int error, pwake = 0;
 	unsigned long flags;
@@ -481,7 +492,7 @@
 	 * We need to lock this because we could be hit by
 	 * eventpoll_release_file() and epoll_ctl().
 	 */
-	mutex_lock(&ep->mtx);
+	mutex_lock_nested(&ep->mtx, depth);
 
 	/*
 	 * Steal the ready list, and re-init the original one to the
@@ -670,7 +681,7 @@
 
 static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests)
 {
-	return ep_scan_ready_list(priv, ep_read_events_proc, NULL);
+	return ep_scan_ready_list(priv, ep_read_events_proc, NULL, call_nests + 1);
 }
 
 static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
@@ -737,7 +748,7 @@
 
 		ep = epi->ep;
 		list_del_init(&epi->fllink);
-		mutex_lock(&ep->mtx);
+		mutex_lock_nested(&ep->mtx, 0);
 		ep_remove(ep, epi);
 		mutex_unlock(&ep->mtx);
 	}
@@ -1134,7 +1145,7 @@
 	esed.maxevents = maxevents;
 	esed.events = events;
 
-	return ep_scan_ready_list(ep, ep_send_events_proc, &esed);
+	return ep_scan_ready_list(ep, ep_send_events_proc, &esed, 0);
 }
 
 static inline struct timespec ep_set_mstimeout(long ms)
@@ -1267,7 +1278,7 @@
 	struct rb_node *rbp;
 	struct epitem *epi;
 
-	mutex_lock(&ep->mtx);
+	mutex_lock_nested(&ep->mtx, call_nests + 1);
 	for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
 		epi = rb_entry(rbp, struct epitem, rbn);
 		if (unlikely(is_file_epoll(epi->ffd.file))) {
@@ -1409,7 +1420,7 @@
 	}
 
 
-	mutex_lock(&ep->mtx);
+	mutex_lock_nested(&ep->mtx, 0);
 
 	/*
 	 * Try to lookup the file inside our RB tree, Since we grabbed "mtx"
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 3451d23..db9ba1a 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1568,7 +1568,13 @@
 	int err;
 
 	J_ASSERT(PageLocked(page));
-	WARN_ON_ONCE(IS_RDONLY(inode));
+	/*
+	 * We don't want to warn for emergency remount. The condition is
+	 * ordered to avoid dereferencing inode->i_sb in non-error case to
+	 * avoid slow-downs.
+	 */
+	WARN_ON_ONCE(IS_RDONLY(inode) &&
+		     !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS));
 
 	/*
 	 * We give up here if we're reentered, because it might be for a
@@ -1642,7 +1648,13 @@
 	int err;
 
 	J_ASSERT(PageLocked(page));
-	WARN_ON_ONCE(IS_RDONLY(inode));
+	/*
+	 * We don't want to warn for emergency remount. The condition is
+	 * ordered to avoid dereferencing inode->i_sb in non-error case to
+	 * avoid slow-downs.
+	 */
+	WARN_ON_ONCE(IS_RDONLY(inode) &&
+		     !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS));
 
 	if (ext3_journal_current_handle())
 		goto out_fail;
@@ -1684,7 +1696,13 @@
 	int err;
 
 	J_ASSERT(PageLocked(page));
-	WARN_ON_ONCE(IS_RDONLY(inode));
+	/*
+	 * We don't want to warn for emergency remount. The condition is
+	 * ordered to avoid dereferencing inode->i_sb in non-error case to
+	 * avoid slow-downs.
+	 */
+	WARN_ON_ONCE(IS_RDONLY(inode) &&
+		     !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS));
 
 	if (ext3_journal_current_handle())
 		goto no_write;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 354619a..1a34c1c 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -175,6 +175,7 @@
  */
 #define	EXT4_IO_END_UNWRITTEN	0x0001
 #define EXT4_IO_END_ERROR	0x0002
+#define EXT4_IO_END_QUEUED	0x0004
 
 struct ext4_io_page {
 	struct page	*p_page;
@@ -357,8 +358,7 @@
 
 /* Flags that should be inherited by new inodes from their parent. */
 #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
-			   EXT4_SYNC_FL | EXT4_IMMUTABLE_FL | EXT4_APPEND_FL |\
-			   EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
+			   EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
 			   EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
 			   EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
 
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c94774c..af09060 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -190,9 +190,6 @@
 
 	trace_ext4_evict_inode(inode);
 
-	mutex_lock(&inode->i_mutex);
-	ext4_flush_completed_IO(inode);
-	mutex_unlock(&inode->i_mutex);
 	ext4_ioend_wait(inode);
 
 	if (inode->i_nlink) {
@@ -2129,8 +2126,11 @@
 					clear_buffer_unwritten(bh);
 				}
 
-				/* skip page if block allocation undone */
-				if (buffer_delay(bh) || buffer_unwritten(bh))
+				/*
+				 * skip page if block allocation undone and
+				 * block is dirty
+				 */
+				if (ext4_bh_delay_or_unwritten(NULL, bh))
 					skip_page = 1;
 				bh = bh->b_this_page;
 				block_start += bh->b_size;
@@ -3234,7 +3234,7 @@
 	 */
 
 	new_i_size = pos + copied;
-	if (new_i_size > EXT4_I(inode)->i_disksize) {
+	if (copied && new_i_size > EXT4_I(inode)->i_disksize) {
 		if (ext4_da_should_update_i_disksize(page, end)) {
 			down_write(&EXT4_I(inode)->i_data_sem);
 			if (new_i_size > EXT4_I(inode)->i_disksize) {
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 458a394..3d36d5a 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1589,7 +1589,7 @@
 			dxtrace(dx_show_index("node", frames[1].entries));
 			dxtrace(dx_show_index("node",
 			       ((struct dx_node *) bh2->b_data)->entries));
-			err = ext4_handle_dirty_metadata(handle, inode, bh2);
+			err = ext4_handle_dirty_metadata(handle, dir, bh2);
 			if (err)
 				goto journal_error;
 			brelse (bh2);
@@ -1615,7 +1615,7 @@
 			if (err)
 				goto journal_error;
 		}
-		err = ext4_handle_dirty_metadata(handle, inode, frames[0].bh);
+		err = ext4_handle_dirty_metadata(handle, dir, frames[0].bh);
 		if (err) {
 			ext4_std_error(inode->i_sb, err);
 			goto cleanup;
@@ -1866,7 +1866,7 @@
 	ext4_set_de_type(dir->i_sb, de, S_IFDIR);
 	inode->i_nlink = 2;
 	BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
-	err = ext4_handle_dirty_metadata(handle, dir, dir_block);
+	err = ext4_handle_dirty_metadata(handle, inode, dir_block);
 	if (err)
 		goto out_clear_inode;
 	err = ext4_mark_inode_dirty(handle, inode);
@@ -2540,7 +2540,7 @@
 		PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) =
 						cpu_to_le32(new_dir->i_ino);
 		BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
-		retval = ext4_handle_dirty_metadata(handle, old_dir, dir_bh);
+		retval = ext4_handle_dirty_metadata(handle, old_inode, dir_bh);
 		if (retval) {
 			ext4_std_error(old_dir->i_sb, retval);
 			goto end_rename;
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 97e5e98..d99d74a 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -142,7 +142,23 @@
 	unsigned long		flags;
 	int			ret;
 
-	mutex_lock(&inode->i_mutex);
+	if (!mutex_trylock(&inode->i_mutex)) {
+		/*
+		 * Requeue the work instead of waiting so that the work
+		 * items queued after this can be processed.
+		 */
+		queue_work(EXT4_SB(inode->i_sb)->dio_unwritten_wq, &io->work);
+		/*
+		 * To prevent the ext4-dio-unwritten thread from keeping
+		 * requeueing end_io requests and occupying cpu for too long,
+		 * yield the cpu if it sees an end_io request that has already
+		 * been requeued.
+		 */
+		if (io->flag & EXT4_IO_END_QUEUED)
+			yield();
+		io->flag |= EXT4_IO_END_QUEUED;
+		return;
+	}
 	ret = ext4_end_io_nolock(io);
 	if (ret < 0) {
 		mutex_unlock(&inode->i_mutex);
@@ -389,6 +405,18 @@
 
 		block_end = block_start + blocksize;
 		if (block_start >= len) {
+			/*
+			 * Comments copied from block_write_full_page_endio:
+			 *
+			 * The page straddles i_size.  It must be zeroed out on
+			 * each and every writepage invocation because it may
+			 * be mmapped.  "A file is mapped in multiples of the
+			 * page size.  For a file that is not a multiple of
+			 * the  page size, the remaining memory is zeroed when
+			 * mapped, and writes to that region are not written
+			 * out to the file."
+			 */
+			zero_user_segment(page, block_start, block_end);
 			clear_buffer_dirty(bh);
 			set_buffer_uptodate(bh);
 			continue;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 111ed9d..df121b2 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1113,9 +1113,9 @@
 		seq_puts(seq, ",block_validity");
 
 	if (!test_opt(sb, INIT_INODE_TABLE))
-		seq_puts(seq, ",noinit_inode_table");
+		seq_puts(seq, ",noinit_itable");
 	else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)
-		seq_printf(seq, ",init_inode_table=%u",
+		seq_printf(seq, ",init_itable=%u",
 			   (unsigned) sbi->s_li_wait_mult);
 
 	ext4_show_quota_options(seq, sb);
@@ -1291,8 +1291,7 @@
 	Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
 	Opt_inode_readahead_blks, Opt_journal_ioprio,
 	Opt_dioread_nolock, Opt_dioread_lock,
-	Opt_discard, Opt_nodiscard,
-	Opt_init_inode_table, Opt_noinit_inode_table,
+	Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
 };
 
 static const match_table_t tokens = {
@@ -1365,9 +1364,9 @@
 	{Opt_dioread_lock, "dioread_lock"},
 	{Opt_discard, "discard"},
 	{Opt_nodiscard, "nodiscard"},
-	{Opt_init_inode_table, "init_itable=%u"},
-	{Opt_init_inode_table, "init_itable"},
-	{Opt_noinit_inode_table, "noinit_itable"},
+	{Opt_init_itable, "init_itable=%u"},
+	{Opt_init_itable, "init_itable"},
+	{Opt_noinit_itable, "noinit_itable"},
 	{Opt_err, NULL},
 };
 
@@ -1844,7 +1843,7 @@
 		case Opt_dioread_lock:
 			clear_opt(sb, DIOREAD_NOLOCK);
 			break;
-		case Opt_init_inode_table:
+		case Opt_init_itable:
 			set_opt(sb, INIT_INODE_TABLE);
 			if (args[0].from) {
 				if (match_int(&args[0], &option))
@@ -1855,7 +1854,7 @@
 				return 0;
 			sbi->s_li_wait_mult = option;
 			break;
-		case Opt_noinit_inode_table:
+		case Opt_noinit_itable:
 			clear_opt(sb, INIT_INODE_TABLE);
 			break;
 		default:
@@ -1958,17 +1957,16 @@
 	struct ext4_group_desc *gdp = NULL;
 	ext4_group_t flex_group_count;
 	ext4_group_t flex_group;
-	int groups_per_flex = 0;
+	unsigned int groups_per_flex = 0;
 	size_t size;
 	int i;
 
 	sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
-	groups_per_flex = 1 << sbi->s_log_groups_per_flex;
-
-	if (groups_per_flex < 2) {
+	if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) {
 		sbi->s_log_groups_per_flex = 0;
 		return 1;
 	}
+	groups_per_flex = 1 << sbi->s_log_groups_per_flex;
 
 	/* We allocate both existing and potentially added groups */
 	flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) +
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index c757adc..19fe4e3 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -820,8 +820,14 @@
 			if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
 				goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
 
+			/*
+			 * take i_data_sem because we will test
+			 * i_delalloc_reserved_flag in ext4_mb_new_blocks
+			 */
+			down_read((&EXT4_I(inode)->i_data_sem));
 			block = ext4_new_meta_blocks(handle, inode, goal, 0,
 						     NULL, &error);
+			up_read((&EXT4_I(inode)->i_data_sem));
 			if (error)
 				goto cleanup;
 
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index fb6fc95..c858b5c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1516,7 +1516,7 @@
 	else if (outarg->offset + num > file_size)
 		num = file_size - outarg->offset;
 
-	while (num) {
+	while (num && req->num_pages < FUSE_MAX_PAGES_PER_REQ) {
 		struct page *page;
 		unsigned int this_num;
 
@@ -1530,6 +1530,7 @@
 
 		num -= this_num;
 		total_len += this_num;
+		index++;
 	}
 	req->misc.retrieve_in.offset = outarg->offset;
 	req->misc.retrieve_in.size = total_len;
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 3ebc437..1cbdeea 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -46,11 +46,26 @@
 	case HFS_EXT_CNID:
 		hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize,
 				    mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz));
+		if (HFS_I(tree->inode)->alloc_blocks >
+					HFS_I(tree->inode)->first_blocks) {
+			printk(KERN_ERR "hfs: invalid btree extent records\n");
+			unlock_new_inode(tree->inode);
+			goto free_inode;
+		}
+
 		tree->inode->i_mapping->a_ops = &hfs_btree_aops;
 		break;
 	case HFS_CAT_CNID:
 		hfs_inode_read_fork(tree->inode, mdb->drCTExtRec, mdb->drCTFlSize,
 				    mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz));
+
+		if (!HFS_I(tree->inode)->first_blocks) {
+			printk(KERN_ERR "hfs: invalid btree extent records "
+								"(0 size).\n");
+			unlock_new_inode(tree->inode);
+			goto free_inode;
+		}
+
 		tree->inode->i_mapping->a_ops = &hfs_btree_aops;
 		break;
 	default:
@@ -59,11 +74,6 @@
 	}
 	unlock_new_inode(tree->inode);
 
-	if (!HFS_I(tree->inode)->first_blocks) {
-		printk(KERN_ERR "hfs: invalid btree extent records (0 size).\n");
-		goto free_inode;
-	}
-
 	mapping = tree->inode->i_mapping;
 	page = read_mapping_page(mapping, 0, NULL);
 	if (IS_ERR(page))
diff --git a/fs/hfs/trans.c b/fs/hfs/trans.c
index e673a88..b1ce4c7 100644
--- a/fs/hfs/trans.c
+++ b/fs/hfs/trans.c
@@ -40,6 +40,8 @@
 
 	src = in->name;
 	srclen = in->len;
+	if (srclen > HFS_NAMELEN)
+		srclen = HFS_NAMELEN;
 	dst = out;
 	dstlen = HFS_MAX_NAMELEN;
 	if (nls_io) {
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 85c098a..9d71c95 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -16,6 +16,7 @@
 #include <linux/statfs.h>
 #include <linux/types.h>
 #include <linux/pid_namespace.h>
+#include <linux/namei.h>
 #include <asm/uaccess.h>
 #include "os.h"
 
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index e2d4285..9f36384 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1131,6 +1131,14 @@
 		goto out;
 	}
 
+	if (be32_to_cpu(sb->s_first) == 0 ||
+	    be32_to_cpu(sb->s_first) >= journal->j_maxlen) {
+		printk(KERN_WARNING
+			"JBD: Invalid start block of journal: %u\n",
+			be32_to_cpu(sb->s_first));
+		goto out;
+	}
+
 	return 0;
 
 out:
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 0dfa5b5..40c5fb7 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1251,6 +1251,14 @@
 		goto out;
 	}
 
+	if (be32_to_cpu(sb->s_first) == 0 ||
+	    be32_to_cpu(sb->s_first) >= journal->j_maxlen) {
+		printk(KERN_WARNING
+			"JBD2: Invalid start block of journal: %u\n",
+			be32_to_cpu(sb->s_first));
+		goto out;
+	}
+
 	return 0;
 
 out:
diff --git a/fs/namei.c b/fs/namei.c
index b456c7a..f7593c0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -136,7 +136,7 @@
 	return retval;
 }
 
-static char *getname_flags(const char __user * filename, int flags)
+static char *getname_flags(const char __user *filename, int flags, int *empty)
 {
 	char *tmp, *result;
 
@@ -147,6 +147,8 @@
 
 		result = tmp;
 		if (retval < 0) {
+			if (retval == -ENOENT && empty)
+				*empty = 1;
 			if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
 				__putname(tmp);
 				result = ERR_PTR(retval);
@@ -159,7 +161,7 @@
 
 char *getname(const char __user * filename)
 {
-	return getname_flags(filename, 0);
+	return getname_flags(filename, 0, 0);
 }
 
 #ifdef CONFIG_AUDITSYSCALL
@@ -779,17 +781,20 @@
 	if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE))
 		return -EISDIR; /* we actually want to stop here */
 
-	/* We want to mount if someone is trying to open/create a file of any
-	 * type under the mountpoint, wants to traverse through the mountpoint
-	 * or wants to open the mounted directory.
+	/* We don't want to mount if someone's just doing a stat -
+	 * unless they're stat'ing a directory and appended a '/' to
+	 * the name.
 	 *
-	 * We don't want to mount if someone's just doing a stat and they've
-	 * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
-	 * appended a '/' to the name.
+	 * We do, however, want to mount if someone wants to open or
+	 * create a file of any type under the mountpoint, wants to
+	 * traverse through the mountpoint or wants to open the
+	 * mounted directory.  Also, autofs may mark negative dentries
+	 * as being automount points.  These will need the attentions
+	 * of the daemon to instantiate them before they can be used.
 	 */
-	if (!(flags & LOOKUP_FOLLOW) &&
-	    !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
-		       LOOKUP_OPEN | LOOKUP_CREATE)))
+	if (!(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
+		     LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
+	    path->dentry->d_inode)
 		return -EISDIR;
 
 	current->total_link_count++;
@@ -905,7 +910,7 @@
 		mntput(path->mnt);
 	if (ret == -EISDIR)
 		ret = 0;
-	return ret;
+	return ret < 0 ? ret : need_mntput;
 }
 
 int follow_down_one(struct path *path)
@@ -953,6 +958,7 @@
 			break;
 		path->mnt = mounted;
 		path->dentry = mounted->mnt_root;
+		nd->flags |= LOOKUP_JUMPED;
 		nd->seq = read_seqcount_begin(&path->dentry->d_seq);
 		/*
 		 * Update the inode too. We don't need to re-check the
@@ -1227,6 +1233,8 @@
 		path_put_conditional(path, nd);
 		return err;
 	}
+	if (err)
+		nd->flags |= LOOKUP_JUMPED;
 	*inode = path->dentry->d_inode;
 	return 0;
 }
@@ -1747,11 +1755,11 @@
 	return __lookup_hash(&this, base, NULL);
 }
 
-int user_path_at(int dfd, const char __user *name, unsigned flags,
-		 struct path *path)
+int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
+		 struct path *path, int *empty)
 {
 	struct nameidata nd;
-	char *tmp = getname_flags(name, flags);
+	char *tmp = getname_flags(name, flags, empty);
 	int err = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
 
@@ -1765,6 +1773,12 @@
 	return err;
 }
 
+int user_path_at(int dfd, const char __user *name, unsigned flags,
+		 struct path *path)
+{
+	return user_path_at_empty(dfd, name, flags, path, 0);
+}
+
 static int user_path_parent(int dfd, const char __user *path,
 			struct nameidata *nd, char **name)
 {
@@ -2107,6 +2121,10 @@
 	}
 
 	/* create side of things */
+	/*
+	 * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been
+	 * cleared when we got to the last component we are about to look up
+	 */
 	error = complete_walk(nd);
 	if (error)
 		return ERR_PTR(error);
@@ -2175,6 +2193,9 @@
 	if (error < 0)
 		goto exit_dput;
 
+	if (error)
+		nd->flags |= LOOKUP_JUMPED;
+
 	error = -ENOENT;
 	if (!path->dentry->d_inode)
 		goto exit_dput;
@@ -2184,6 +2205,10 @@
 
 	path_to_nameidata(path, nd);
 	nd->inode = path->dentry->d_inode;
+	/* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
+	error = complete_walk(nd);
+	if (error)
+		goto exit;
 	error = -EISDIR;
 	if (S_ISDIR(nd->inode->i_mode))
 		goto exit;
diff --git a/fs/namespace.c b/fs/namespace.c
index 7b4fa8f..3e09445 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1048,15 +1048,12 @@
 	if (err)
 		goto out;
 	seq_putc(m, ' ');
-	seq_path_root(m, &mnt_path, &root, " \t\n\\");
-	if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) {
-		/*
-		 * Mountpoint is outside root, discard that one.  Ugly,
-		 * but less so than trying to do that in iterator in a
-		 * race-free way (due to renames).
-		 */
-		return SEQ_SKIP;
-	}
+
+	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
+	err = seq_path_root(m, &mnt_path, &root, " \t\n\\");
+	if (err)
+		goto out;
+
 	seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
 	show_mnt_opts(m, mnt);
 
@@ -1109,6 +1106,7 @@
 
 	/* device */
 	if (mnt->mnt_sb->s_op->show_devname) {
+		seq_puts(m, "device ");
 		err = mnt->mnt_sb->s_op->show_devname(m, mnt);
 	} else {
 		if (mnt->mnt_devname) {
@@ -1757,7 +1755,7 @@
 		return err;
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
+	err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
 	if (err)
 		return err;
 
@@ -2743,3 +2741,8 @@
 	}
 }
 EXPORT_SYMBOL(kern_unmount);
+
+bool our_mnt(struct vfsmount *mnt)
+{
+	return check_mnt(mnt);
+}
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index aaa09e9..b5c826e 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -324,7 +324,7 @@
 	dprintk("%s enter. slotid %d seqid %d\n",
 		__func__, args->csa_slotid, args->csa_sequenceid);
 
-	if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS)
+	if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS)
 		return htonl(NFS4ERR_BADSLOT);
 
 	slot = tbl->slots + args->csa_slotid;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f91c62d..462a006 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1458,12 +1458,12 @@
 				res = NULL;
 				goto out;
 			/* This turned out not to be a regular file */
+			case -EISDIR:
 			case -ENOTDIR:
 				goto no_open;
 			case -ELOOP:
 				if (!(nd->intent.open.flags & O_NOFOLLOW))
 					goto no_open;
-			/* case -EISDIR: */
 			/* case -EINVAL: */
 			default:
 				res = ERR_CAST(inode);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 2f093ed..dd2f130 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -887,3 +887,35 @@
 			file->f_path.dentry->d_name.name, arg);
 	return -EINVAL;
 }
+
+#ifdef CONFIG_NFS_V4
+static int
+nfs4_file_open(struct inode *inode, struct file *filp)
+{
+	/*
+	 * NFSv4 opens are handled in d_lookup and d_revalidate. If we get to
+	 * this point, then something is very wrong
+	 */
+	dprintk("NFS: %s called! inode=%p filp=%p\n", __func__, inode, filp);
+	return -ENOTDIR;
+}
+
+const struct file_operations nfs4_file_operations = {
+	.llseek		= nfs_file_llseek,
+	.read		= do_sync_read,
+	.write		= do_sync_write,
+	.aio_read	= nfs_file_read,
+	.aio_write	= nfs_file_write,
+	.mmap		= nfs_file_mmap,
+	.open		= nfs4_file_open,
+	.flush		= nfs_file_flush,
+	.release	= nfs_file_release,
+	.fsync		= nfs_file_fsync,
+	.lock		= nfs_lock,
+	.flock		= nfs_flock,
+	.splice_read	= nfs_file_splice_read,
+	.splice_write	= nfs_file_splice_write,
+	.check_flags	= nfs_check_flags,
+	.setlease	= nfs_setlease,
+};
+#endif /* CONFIG_NFS_V4 */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 6f4850d..c48f9f6 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -291,7 +291,7 @@
 		 */
 		inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
 		if (S_ISREG(inode->i_mode)) {
-			inode->i_fop = &nfs_file_operations;
+			inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops;
 			inode->i_data.a_ops = &nfs_file_aops;
 			inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
 		} else if (S_ISDIR(inode->i_mode)) {
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 38053d8..771741f 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -853,6 +853,7 @@
 	.dentry_ops	= &nfs_dentry_operations,
 	.dir_inode_ops	= &nfs3_dir_inode_operations,
 	.file_inode_ops	= &nfs3_file_inode_operations,
+	.file_ops	= &nfs_file_operations,
 	.getroot	= nfs3_proc_get_root,
 	.getattr	= nfs3_proc_getattr,
 	.setattr	= nfs3_proc_setattr,
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 614c4d2..75af812 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -428,6 +428,14 @@
 
 	dprintk("--> %s\n", __func__);
 
+	/* FIXME: remove this check when layout segment support is added */
+	if (lgr->range.offset != 0 ||
+	    lgr->range.length != NFS4_MAX_UINT64) {
+		dprintk("%s Only whole file layouts supported. Use MDS i/o\n",
+			__func__);
+		goto out;
+	}
+
 	if (fl->pattern_offset > lgr->range.offset) {
 		dprintk("%s pattern_offset %lld too large\n",
 				__func__, fl->pattern_offset);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 92cfd2e..a2a7d0a 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6008,6 +6008,7 @@
 	.dentry_ops	= &nfs4_dentry_operations,
 	.dir_inode_ops	= &nfs4_dir_inode_operations,
 	.file_inode_ops	= &nfs4_file_inode_operations,
+	.file_ops	= &nfs4_file_operations,
 	.getroot	= nfs4_proc_get_root,
 	.getattr	= nfs4_proc_getattr,
 	.setattr	= nfs4_proc_setattr,
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index e97dd21..87822a3 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1519,16 +1519,16 @@
 {
 	if (!flags)
 		return;
-	else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
+	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
 		nfs41_handle_server_reboot(clp);
-	else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
+	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
 			    SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
 			    SEQ4_STATUS_ADMIN_STATE_REVOKED |
 			    SEQ4_STATUS_LEASE_MOVED))
 		nfs41_handle_state_revoked(clp);
-	else if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
+	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
 		nfs41_handle_recallable_state_revoked(clp);
-	else if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
+	if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
 			    SEQ4_STATUS_BACKCHANNEL_FAULT |
 			    SEQ4_STATUS_CB_PATH_DOWN_SESSION))
 		nfs41_handle_cb_path_down(clp);
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
index 1d1dc1e..75fe694 100644
--- a/fs/nfs/objlayout/objio_osd.c
+++ b/fs/nfs/objlayout/objio_osd.c
@@ -1006,7 +1006,8 @@
 static struct pnfs_layoutdriver_type objlayout_type = {
 	.id = LAYOUT_OSD2_OBJECTS,
 	.name = "LAYOUT_OSD2_OBJECTS",
-	.flags                   = PNFS_LAYOUTRET_ON_SETATTR,
+	.flags                   = PNFS_LAYOUTRET_ON_SETATTR |
+				   PNFS_LAYOUTRET_ON_ERROR,
 
 	.alloc_layout_hdr        = objlayout_alloc_layout_hdr,
 	.free_layout_hdr         = objlayout_free_layout_hdr,
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c
index 1d06f8e..fefa122 100644
--- a/fs/nfs/objlayout/objlayout.c
+++ b/fs/nfs/objlayout/objlayout.c
@@ -294,9 +294,11 @@
 	dprintk("%s: Begin status=%zd eof=%d\n", __func__, status, eof);
 	rdata = state->rpcdata;
 	rdata->task.tk_status = status;
-	if (status >= 0) {
+	if (likely(status >= 0)) {
 		rdata->res.count = status;
 		rdata->res.eof = eof;
+	} else {
+		rdata->pnfs_error = status;
 	}
 	objlayout_iodone(state);
 	/* must not use state after this point */
@@ -380,15 +382,17 @@
 	wdata = state->rpcdata;
 	state->status = status;
 	wdata->task.tk_status = status;
-	if (status >= 0) {
+	if (likely(status >= 0)) {
 		wdata->res.count = status;
 		wdata->verf.committed = state->committed;
 		dprintk("%s: Return status %d committed %d\n",
 			__func__, wdata->task.tk_status,
 			wdata->verf.committed);
-	} else
+	} else {
+		wdata->pnfs_error = status;
 		dprintk("%s: Return status %d\n",
 			__func__, wdata->task.tk_status);
+	}
 	objlayout_iodone(state);
 	/* must not use state after this point */
 
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index a726c0a..9951887 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -980,7 +980,8 @@
 		arg.offset -= pg_offset;
 		arg.length += pg_offset;
 	}
-	arg.length = PAGE_CACHE_ALIGN(arg.length);
+	if (arg.length != NFS4_MAX_UINT64)
+		arg.length = PAGE_CACHE_ALIGN(arg.length);
 
 	lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
 	if (!lseg && first) {
@@ -1118,6 +1119,14 @@
 		data->mds_ops->rpc_release(data);
 		return 0;
 	}
+	if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
+					PNFS_LAYOUTRET_ON_ERROR) {
+		/* Don't lo_commit on error, Server will needs to
+		 * preform a file recovery.
+		 */
+		clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(data->inode)->flags);
+		pnfs_return_layout(data->inode);
+	}
 
 	dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
 		data->pnfs_error);
@@ -1166,6 +1175,10 @@
 		return 0;
 	}
 
+	if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
+						PNFS_LAYOUTRET_ON_ERROR)
+		pnfs_return_layout(data->inode);
+
 	dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
 		data->pnfs_error);
 	status = nfs_initiate_read(data, NFS_CLIENT(data->inode),
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 9d147d9..bb8b324 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -68,6 +68,7 @@
 enum layoutdriver_policy_flags {
 	/* Should the pNFS client commit and return the layout upon a setattr */
 	PNFS_LAYOUTRET_ON_SETATTR	= 1 << 0,
+	PNFS_LAYOUTRET_ON_ERROR		= 1 << 1,
 };
 
 struct nfs4_deviceid_node;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index ac40b85..f48125d 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -710,6 +710,7 @@
 	.dentry_ops	= &nfs_dentry_operations,
 	.dir_inode_ops	= &nfs_dir_inode_operations,
 	.file_inode_ops	= &nfs_file_inode_operations,
+	.file_ops	= &nfs_file_operations,
 	.getroot	= nfs_proc_get_root,
 	.getattr	= nfs_proc_getattr,
 	.setattr	= nfs_proc_setattr,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ce40e5c..7e8b07d 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -904,10 +904,24 @@
 		data->auth_flavor_len	= 1;
 		data->version		= version;
 		data->minorversion	= 0;
+		security_init_mnt_opts(&data->lsm_opts);
 	}
 	return data;
 }
 
+static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
+{
+	if (data) {
+		kfree(data->client_address);
+		kfree(data->mount_server.hostname);
+		kfree(data->nfs_server.export_path);
+		kfree(data->nfs_server.hostname);
+		kfree(data->fscache_uniq);
+		security_free_mnt_opts(&data->lsm_opts);
+		kfree(data);
+	}
+}
+
 /*
  * Sanity-check a server address provided by the mount command.
  *
@@ -2218,9 +2232,7 @@
 	data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
 	mntfh = nfs_alloc_fhandle();
 	if (data == NULL || mntfh == NULL)
-		goto out_free_fh;
-
-	security_init_mnt_opts(&data->lsm_opts);
+		goto out;
 
 	/* Validate the mount data */
 	error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
@@ -2232,8 +2244,6 @@
 #ifdef CONFIG_NFS_V4
 	if (data->version == 4) {
 		mntroot = nfs4_try_mount(flags, dev_name, data);
-		kfree(data->client_address);
-		kfree(data->nfs_server.export_path);
 		goto out;
 	}
 #endif	/* CONFIG_NFS_V4 */
@@ -2284,13 +2294,8 @@
 	s->s_flags |= MS_ACTIVE;
 
 out:
-	kfree(data->nfs_server.hostname);
-	kfree(data->mount_server.hostname);
-	kfree(data->fscache_uniq);
-	security_free_mnt_opts(&data->lsm_opts);
-out_free_fh:
+	nfs_free_parsed_mount_data(data);
 	nfs_free_fhandle(mntfh);
-	kfree(data);
 	return mntroot;
 
 out_err_nosb:
@@ -2613,9 +2618,7 @@
 
 	mntfh = nfs_alloc_fhandle();
 	if (data == NULL || mntfh == NULL)
-		goto out_free_fh;
-
-	security_init_mnt_opts(&data->lsm_opts);
+		goto out;
 
 	/* Get a volume representation */
 	server = nfs4_create_server(data, mntfh);
@@ -2663,13 +2666,10 @@
 
 	s->s_flags |= MS_ACTIVE;
 
-	security_free_mnt_opts(&data->lsm_opts);
 	nfs_free_fhandle(mntfh);
 	return mntroot;
 
 out:
-	security_free_mnt_opts(&data->lsm_opts);
-out_free_fh:
 	nfs_free_fhandle(mntfh);
 	return ERR_PTR(error);
 
@@ -2793,7 +2793,7 @@
 		goto out_put_mnt_ns;
 
 	ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
-			export_path, LOOKUP_FOLLOW, nd);
+			export_path, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, nd);
 
 	nfs_referral_loop_unprotect();
 	put_mnt_ns(ns_private);
@@ -2855,7 +2855,7 @@
 
 	data = nfs_alloc_parsed_mount_data(4);
 	if (data == NULL)
-		goto out_free_data;
+		goto out;
 
 	/* Validate the mount data */
 	error = nfs4_validate_mount_data(raw_data, data, dev_name);
@@ -2869,12 +2869,7 @@
 		error = PTR_ERR(res);
 
 out:
-	kfree(data->client_address);
-	kfree(data->nfs_server.export_path);
-	kfree(data->nfs_server.hostname);
-	kfree(data->fscache_uniq);
-out_free_data:
-	kfree(data);
+	nfs_free_parsed_mount_data(data);
 	dprintk("<-- nfs4_mount() = %d%s\n", error,
 			error != 0 ? " [error]" : "");
 	return res;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 7271680..f2f80c0 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -428,7 +428,6 @@
 nfs_mark_request_dirty(struct nfs_page *req)
 {
 	__set_page_dirty_nobuffers(req->wb_page);
-	__mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC);
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
@@ -762,6 +761,8 @@
 	status = nfs_writepage_setup(ctx, page, offset, count);
 	if (status < 0)
 		nfs_set_pageerror(page);
+	else
+		__set_page_dirty_nobuffers(page);
 
 	dprintk("NFS:       nfs_updatepage returns %d (isize %lld)\n",
 			status, (long long)i_size_read(inode));
@@ -1525,6 +1526,10 @@
 	int flags = FLUSH_SYNC;
 	int ret = 0;
 
+	/* no commits means nothing needs to be done */
+	if (!nfsi->ncommit)
+		return ret;
+
 	if (wbc->sync_mode == WB_SYNC_NONE) {
 		/* Don't commit yet if this is a non-blocking flush and there
 		 * are a lot of outstanding writes for this mapping.
@@ -1659,34 +1664,20 @@
 int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
 		struct page *page)
 {
-	struct nfs_page *req;
-	int ret;
+	/*
+	 * If PagePrivate is set, then the page is currently associated with
+	 * an in-progress read or write request. Don't try to migrate it.
+	 *
+	 * FIXME: we could do this in principle, but we'll need a way to ensure
+	 *        that we can safely release the inode reference while holding
+	 *        the page lock.
+	 */
+	if (PagePrivate(page))
+		return -EBUSY;
 
 	nfs_fscache_release_page(page, GFP_KERNEL);
 
-	req = nfs_find_and_lock_request(page, false);
-	ret = PTR_ERR(req);
-	if (IS_ERR(req))
-		goto out;
-
-	ret = migrate_page(mapping, newpage, page);
-	if (!req)
-		goto out;
-	if (ret)
-		goto out_unlock;
-	page_cache_get(newpage);
-	spin_lock(&mapping->host->i_lock);
-	req->wb_page = newpage;
-	SetPagePrivate(newpage);
-	set_page_private(newpage, (unsigned long)req);
-	ClearPagePrivate(page);
-	set_page_private(page, 0);
-	spin_unlock(&mapping->host->i_lock);
-	page_cache_release(page);
-out_unlock:
-	nfs_clear_page_tag_locked(req);
-out:
-	return ret;
+	return migrate_page(mapping, newpage, page);
 }
 #endif
 
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index b9566e4..4b470f6 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -88,7 +88,7 @@
 	struct svc_expkey key;
 	struct svc_expkey *ek = NULL;
 
-	if (mesg[mlen-1] != '\n')
+	if (mlen < 1 || mesg[mlen-1] != '\n')
 		return -EINVAL;
 	mesg[mlen-1] = 0;
 
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 3a6dbd7..0b8830c 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -156,6 +156,8 @@
 		!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
 		return nfserr_inval;
 
+	accmode |= NFSD_MAY_READ_IF_EXEC;
+
 	if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
 		accmode |= NFSD_MAY_READ;
 	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
@@ -682,7 +684,7 @@
 	readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
 	readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
 
-	if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
+	if ((cookie == 1) || (cookie == 2) ||
 	    (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
 		return nfserr_bad_cookie;
 
@@ -921,7 +923,7 @@
 	count = 4 + (verify->ve_attrlen >> 2);
 	buf = kmalloc(count << 2, GFP_KERNEL);
 	if (!buf)
-		return nfserr_resource;
+		return nfserr_jukebox;
 
 	status = nfsd4_encode_fattr(&cstate->current_fh,
 				    cstate->current_fh.fh_export,
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index ffb59ef..be26814 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -88,7 +88,7 @@
 	struct xdr_netobj cksum;
 	struct hash_desc desc;
 	struct scatterlist sg;
-	__be32 status = nfserr_resource;
+	__be32 status = nfserr_jukebox;
 
 	dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
 			clname->len, clname->data);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3b8ad35..ecd8152 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -188,8 +188,15 @@
 static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
 {
 	if (atomic_dec_and_test(&fp->fi_access[oflag])) {
-		nfs4_file_put_fd(fp, O_RDWR);
 		nfs4_file_put_fd(fp, oflag);
+		/*
+		 * It's also safe to get rid of the RDWR open *if*
+		 * we no longer have need of the other kind of access
+		 * or if we already have the other kind of open:
+		 */
+		if (fp->fi_fds[1-oflag]
+			|| atomic_read(&fp->fi_access[1 - oflag]) == 0)
+			nfs4_file_put_fd(fp, O_RDWR);
 	}
 }
 
@@ -1903,7 +1910,7 @@
 	 * of 5 bullet points, labeled as CASE0 - CASE4 below.
 	 */
 	unconf = find_unconfirmed_client_by_str(dname, strhashval);
-	status = nfserr_resource;
+	status = nfserr_jukebox;
 	if (!conf) {
 		/*
 		 * RFC 3530 14.2.33 CASE 4:
@@ -2440,7 +2447,7 @@
 	if (open->op_stateowner == NULL) {
 		sop = alloc_init_open_stateowner(strhashval, clp, open);
 		if (sop == NULL)
-			return nfserr_resource;
+			return nfserr_jukebox;
 		open->op_stateowner = sop;
 	}
 	list_del_init(&sop->so_close_lru);
@@ -2576,7 +2583,7 @@
 
 	stp = nfs4_alloc_stateid();
 	if (stp == NULL)
-		return nfserr_resource;
+		return nfserr_jukebox;
 
 	status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
 	if (status) {
@@ -2807,7 +2814,7 @@
 		status = nfserr_bad_stateid;
 		if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
 			goto out;
-		status = nfserr_resource;
+		status = nfserr_jukebox;
 		fp = alloc_init_file(ino);
 		if (fp == NULL)
 			goto out;
@@ -3381,8 +3388,9 @@
 	int i;
 
 	for (i = 1; i < 4; i++) {
-		if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) {
-			nfs4_file_put_access(stp->st_file, i);
+		if (test_bit(i, &stp->st_access_bmap)
+					&& ((i & to_access) != i)) {
+			nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(i));
 			__clear_bit(i, &stp->st_access_bmap);
 		}
 	}
@@ -3413,6 +3421,8 @@
 	if (!access_valid(od->od_share_access, cstate->minorversion)
 			|| !deny_valid(od->od_share_deny))
 		return nfserr_inval;
+	/* We don't yet support WANT bits: */
+	od->od_share_access &= NFS4_SHARE_ACCESS_MASK;
 
 	nfs4_lock_state();
 	if ((status = nfs4_preprocess_seqid_op(cstate,
@@ -3840,7 +3850,7 @@
 		/* XXX: Do we need to check for duplicate stateowners on
 		 * the same file, or should they just be allowed (and
 		 * create new stateids)? */
-		status = nfserr_resource;
+		status = nfserr_jukebox;
 		lock_sop = alloc_init_lock_stateowner(strhashval,
 				open_sop->so_client, open_stp, lock);
 		if (lock_sop == NULL)
@@ -3924,9 +3934,9 @@
 	case (EDEADLK):
 		status = nfserr_deadlock;
 		break;
-	default:        
+	default:
 		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
-		status = nfserr_resource;
+		status = nfserrno(err);
 		break;
 	}
 out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 9901811..6c74097 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1548,6 +1548,18 @@
 								\
 	save = resp->p;
 
+static bool seqid_mutating_err(__be32 err)
+{
+	/* rfc 3530 section 8.1.5: */
+	return	err != nfserr_stale_clientid &&
+		err != nfserr_stale_stateid &&
+		err != nfserr_bad_stateid &&
+		err != nfserr_bad_seqid &&
+		err != nfserr_bad_xdr &&
+		err != nfserr_resource &&
+		err != nfserr_nofilehandle;
+}
+
 /*
  * Routine for encoding the result of a "seqid-mutating" NFSv4 operation.  This
  * is where sequence id's are incremented, and the replay cache is filled.
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 6bd2f3c..858c7ba 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -447,12 +447,6 @@
 #define WR_STATE	        0x00000020
 #define CLOSE_STATE             0x00000040
 
-#define seqid_mutating_err(err)                       \
-	(((err) != nfserr_stale_clientid) &&    \
-	((err) != nfserr_bad_seqid) &&          \
-	((err) != nfserr_stale_stateid) &&      \
-	((err) != nfserr_bad_stateid))
-
 struct nfsd4_compound_state;
 
 extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index fd0acca..acf88ae 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -2114,7 +2114,8 @@
 
 	/* Allow read access to binaries even when mode 111 */
 	if (err == -EACCES && S_ISREG(inode->i_mode) &&
-	    acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
+	     (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) ||
+	      acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC)))
 		err = inode_permission(inode, MAY_EXEC);
 
 	return err? nfserrno(err) : 0;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index e0bbac0..a22e40e 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -25,6 +25,7 @@
 #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
 #define NFSD_MAY_NOT_BREAK_LEASE 512
 #define NFSD_MAY_BYPASS_GSS	1024
+#define NFSD_MAY_READ_IF_EXEC	2048
 
 #define NFSD_MAY_CREATE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE)
 #define NFSD_MAY_REMOVE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index 41d6743..3e65427 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -842,6 +842,19 @@
 	case FS_IOC32_GETVERSION:
 		cmd = FS_IOC_GETVERSION;
 		break;
+	case NILFS_IOCTL_CHANGE_CPMODE:
+	case NILFS_IOCTL_DELETE_CHECKPOINT:
+	case NILFS_IOCTL_GET_CPINFO:
+	case NILFS_IOCTL_GET_CPSTAT:
+	case NILFS_IOCTL_GET_SUINFO:
+	case NILFS_IOCTL_GET_SUSTAT:
+	case NILFS_IOCTL_GET_VINFO:
+	case NILFS_IOCTL_GET_BDESCS:
+	case NILFS_IOCTL_CLEAN_SEGMENTS:
+	case NILFS_IOCTL_SYNC:
+	case NILFS_IOCTL_RESIZE:
+	case NILFS_IOCTL_SET_ALLOC_RANGE:
+		break;
 	default:
 		return -ENOIOCTLCMD;
 	}
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 252ab1f..42ed195 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -135,9 +135,6 @@
 
 	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
 
-	/* 1 from caller and 1 for being on i_list/g_list */
-	BUG_ON(atomic_read(&mark->refcnt) < 2);
-
 	spin_lock(&group->mark_lock);
 
 	if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
@@ -182,6 +179,11 @@
 		iput(inode);
 
 	/*
+	 * We don't necessarily have a ref on mark from caller so the above iput
+	 * may have already destroyed it.  Don't touch from now on.
+	 */
+
+	/*
 	 * it's possible that this group tried to destroy itself, but this
 	 * this mark was simultaneously being freed by inode.  If that's the
 	 * case, we finish freeing the group here.
diff --git a/fs/proc/base.c b/fs/proc/base.c
index efb3048..0da2379 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -200,65 +200,7 @@
 	return result;
 }
 
-static struct mm_struct *__check_mem_permission(struct task_struct *task)
-{
-	struct mm_struct *mm;
-
-	mm = get_task_mm(task);
-	if (!mm)
-		return ERR_PTR(-EINVAL);
-
-	/*
-	 * A task can always look at itself, in case it chooses
-	 * to use system calls instead of load instructions.
-	 */
-	if (task == current)
-		return mm;
-
-	/*
-	 * If current is actively ptrace'ing, and would also be
-	 * permitted to freshly attach with ptrace now, permit it.
-	 */
-	if (task_is_stopped_or_traced(task)) {
-		int match;
-		rcu_read_lock();
-		match = (tracehook_tracer_task(task) == current);
-		rcu_read_unlock();
-		if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
-			return mm;
-	}
-
-	/*
-	 * No one else is allowed.
-	 */
-	mmput(mm);
-	return ERR_PTR(-EPERM);
-}
-
-/*
- * If current may access user memory in @task return a reference to the
- * corresponding mm, otherwise ERR_PTR.
- */
-static struct mm_struct *check_mem_permission(struct task_struct *task)
-{
-	struct mm_struct *mm;
-	int err;
-
-	/*
-	 * Avoid racing if task exec's as we might get a new mm but validate
-	 * against old credentials.
-	 */
-	err = mutex_lock_killable(&task->signal->cred_guard_mutex);
-	if (err)
-		return ERR_PTR(err);
-
-	mm = __check_mem_permission(task);
-	mutex_unlock(&task->signal->cred_guard_mutex);
-
-	return mm;
-}
-
-struct mm_struct *mm_for_maps(struct task_struct *task)
+static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
 {
 	struct mm_struct *mm;
 	int err;
@@ -269,7 +211,7 @@
 
 	mm = get_task_mm(task);
 	if (mm && mm != current->mm &&
-			!ptrace_may_access(task, PTRACE_MODE_READ) &&
+			!ptrace_may_access(task, mode) &&
 			!capable(CAP_SYS_RESOURCE)) {
 		mmput(mm);
 		mm = ERR_PTR(-EACCES);
@@ -279,6 +221,11 @@
 	return mm;
 }
 
+struct mm_struct *mm_for_maps(struct task_struct *task)
+{
+	return mm_access(task, PTRACE_MODE_READ);
+}
+
 static int proc_pid_cmdline(struct task_struct *task, char * buffer)
 {
 	int res = 0;
@@ -823,133 +770,96 @@
 
 static int mem_open(struct inode* inode, struct file* file)
 {
-	file->private_data = (void*)((long)current->self_exec_id);
+	struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+	struct mm_struct *mm;
+
+	if (!task)
+		return -ESRCH;
+
+	mm = mm_access(task, PTRACE_MODE_ATTACH);
+	put_task_struct(task);
+
+	if (IS_ERR(mm))
+		return PTR_ERR(mm);
+
+	if (mm) {
+		/* ensure this mm_struct can't be freed */
+		atomic_inc(&mm->mm_count);
+		/* but do not pin its memory */
+		mmput(mm);
+	}
+
 	/* OK to pass negative loff_t, we can catch out-of-range */
 	file->f_mode |= FMODE_UNSIGNED_OFFSET;
+	file->private_data = mm;
+
 	return 0;
 }
 
-static ssize_t mem_read(struct file * file, char __user * buf,
-			size_t count, loff_t *ppos)
+static ssize_t mem_rw(struct file *file, char __user *buf,
+			size_t count, loff_t *ppos, int write)
 {
-	struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+	struct mm_struct *mm = file->private_data;
+	unsigned long addr = *ppos;
+	ssize_t copied;
 	char *page;
-	unsigned long src = *ppos;
-	int ret = -ESRCH;
-	struct mm_struct *mm;
 
-	if (!task)
-		goto out_no_task;
+	if (!mm)
+		return 0;
 
-	ret = -ENOMEM;
 	page = (char *)__get_free_page(GFP_TEMPORARY);
 	if (!page)
-		goto out;
-
-	mm = check_mem_permission(task);
-	ret = PTR_ERR(mm);
-	if (IS_ERR(mm))
-		goto out_free;
-
-	ret = -EIO;
- 
-	if (file->private_data != (void*)((long)current->self_exec_id))
-		goto out_put;
-
-	ret = 0;
- 
-	while (count > 0) {
-		int this_len, retval;
-
-		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-		retval = access_remote_vm(mm, src, page, this_len, 0);
-		if (!retval) {
-			if (!ret)
-				ret = -EIO;
-			break;
-		}
-
-		if (copy_to_user(buf, page, retval)) {
-			ret = -EFAULT;
-			break;
-		}
- 
-		ret += retval;
-		src += retval;
-		buf += retval;
-		count -= retval;
-	}
-	*ppos = src;
-
-out_put:
-	mmput(mm);
-out_free:
-	free_page((unsigned long) page);
-out:
-	put_task_struct(task);
-out_no_task:
-	return ret;
-}
-
-static ssize_t mem_write(struct file * file, const char __user *buf,
-			 size_t count, loff_t *ppos)
-{
-	int copied;
-	char *page;
-	struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
-	unsigned long dst = *ppos;
-	struct mm_struct *mm;
-
-	copied = -ESRCH;
-	if (!task)
-		goto out_no_task;
-
-	copied = -ENOMEM;
-	page = (char *)__get_free_page(GFP_TEMPORARY);
-	if (!page)
-		goto out_task;
-
-	mm = check_mem_permission(task);
-	copied = PTR_ERR(mm);
-	if (IS_ERR(mm))
-		goto out_free;
-
-	copied = -EIO;
-	if (file->private_data != (void *)((long)current->self_exec_id))
-		goto out_mm;
+		return -ENOMEM;
 
 	copied = 0;
-	while (count > 0) {
-		int this_len, retval;
+	if (!atomic_inc_not_zero(&mm->mm_users))
+		goto free;
 
-		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-		if (copy_from_user(page, buf, this_len)) {
+	while (count > 0) {
+		int this_len = min_t(int, count, PAGE_SIZE);
+
+		if (write && copy_from_user(page, buf, this_len)) {
 			copied = -EFAULT;
 			break;
 		}
-		retval = access_remote_vm(mm, dst, page, this_len, 1);
-		if (!retval) {
+
+		this_len = access_remote_vm(mm, addr, page, this_len, write);
+		if (!this_len) {
 			if (!copied)
 				copied = -EIO;
 			break;
 		}
-		copied += retval;
-		buf += retval;
-		dst += retval;
-		count -= retval;			
-	}
-	*ppos = dst;
 
-out_mm:
+		if (!write && copy_to_user(buf, page, this_len)) {
+			copied = -EFAULT;
+			break;
+		}
+
+		buf += this_len;
+		addr += this_len;
+		copied += this_len;
+		count -= this_len;
+	}
+	*ppos = addr;
+
 	mmput(mm);
-out_free:
+free:
 	free_page((unsigned long) page);
-out_task:
-	put_task_struct(task);
-out_no_task:
 	return copied;
 }
 
+static ssize_t mem_read(struct file *file, char __user *buf,
+			size_t count, loff_t *ppos)
+{
+	return mem_rw(file, buf, count, ppos, 0);
+}
+
+static ssize_t mem_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	return mem_rw(file, (char __user*)buf, count, ppos, 1);
+}
+
 loff_t mem_lseek(struct file *file, loff_t offset, int orig)
 {
 	switch (orig) {
@@ -966,11 +876,20 @@
 	return file->f_pos;
 }
 
+static int mem_release(struct inode *inode, struct file *file)
+{
+	struct mm_struct *mm = file->private_data;
+	if (mm)
+		mmdrop(mm);
+	return 0;
+}
+
 static const struct file_operations proc_mem_operations = {
 	.llseek		= mem_lseek,
 	.read		= mem_read,
 	.write		= mem_write,
 	.open		= mem_open,
+	.release	= mem_release,
 };
 
 static ssize_t environ_read(struct file *file, char __user *buf,
@@ -1960,6 +1879,14 @@
 		spin_lock(&files->file_lock);
 		file = fcheck_files(files, fd);
 		if (file) {
+			unsigned int f_flags;
+			struct fdtable *fdt;
+
+			fdt = files_fdtable(files);
+			f_flags = file->f_flags & ~O_CLOEXEC;
+			if (FD_ISSET(fd, fdt->close_on_exec))
+				f_flags |= O_CLOEXEC;
+
 			if (path) {
 				*path = file->f_path;
 				path_get(&file->f_path);
@@ -1969,7 +1896,7 @@
 					 "pos:\t%lli\n"
 					 "flags:\t0%o\n",
 					 (long long) file->f_pos,
-					 file->f_flags);
+					 f_flags);
 			spin_unlock(&files->file_lock);
 			put_files_struct(files);
 			return 0;
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index ed257d1..a962827 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -131,12 +131,13 @@
 		K(i.freeswap),
 		K(global_page_state(NR_FILE_DIRTY)),
 		K(global_page_state(NR_WRITEBACK)),
-		K(global_page_state(NR_ANON_PAGES)
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+		K(global_page_state(NR_ANON_PAGES)
 		  + global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) *
-		  HPAGE_PMD_NR
+		  HPAGE_PMD_NR),
+#else
+		K(global_page_state(NR_ANON_PAGES)),
 #endif
-		  ),
 		K(global_page_state(NR_FILE_MAPPED)),
 		K(global_page_state(NR_SHMEM)),
 		K(global_page_state(NR_SLAB_RECLAIMABLE) +
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 5afaa58..3487b06 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -516,6 +516,9 @@
 		if (!page)
 			continue;
 
+		if (PageReserved(page))
+			continue;
+
 		/* Clear accessed and referenced bits. */
 		ptep_test_and_clear_young(vma, addr, pte);
 		ClearPageReferenced(page);
@@ -1039,6 +1042,9 @@
 		seq_printf(m, " stack");
 	}
 
+	if (is_vm_hugetlb_page(vma))
+		seq_printf(m, " huge");
+
 	walk_page_range(vma->vm_start, vma->vm_end, &walk);
 
 	if (!md->pages)
diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c
index 766b1d4..29166ec 100644
--- a/fs/proc/uptime.c
+++ b/fs/proc/uptime.c
@@ -11,15 +11,20 @@
 {
 	struct timespec uptime;
 	struct timespec idle;
+	cputime64_t idletime;
+	u64 nsec;
+	u32 rem;
 	int i;
-	cputime_t idletime = cputime_zero;
 
+	idletime = 0;
 	for_each_possible_cpu(i)
 		idletime = cputime64_add(idletime, kstat_cpu(i).cpustat.idle);
 
 	do_posix_clock_monotonic_gettime(&uptime);
 	monotonic_to_bootbased(&uptime);
-	cputime_to_timespec(idletime, &idle);
+	nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC;
+	idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
+	idle.tv_nsec = rem;
 	seq_printf(m, "%lu.%02lu %lu.%02lu\n",
 			(unsigned long) uptime.tv_sec,
 			(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index b34bdb2..10b6be3 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -355,7 +355,7 @@
 	 * resolution (think about autofs) and thus deadlocks could arise.
 	 */
 	if (cmds == Q_QUOTAON) {
-		ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW, &path);
+		ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
 		if (ret)
 			pathp = ERR_PTR(ret);
 		else
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index aa91089..f19dfbf 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -453,16 +453,20 @@
 static void reiserfs_kill_sb(struct super_block *s)
 {
 	if (REISERFS_SB(s)) {
-		if (REISERFS_SB(s)->xattr_root) {
-			d_invalidate(REISERFS_SB(s)->xattr_root);
-			dput(REISERFS_SB(s)->xattr_root);
-			REISERFS_SB(s)->xattr_root = NULL;
-		}
-		if (REISERFS_SB(s)->priv_root) {
-			d_invalidate(REISERFS_SB(s)->priv_root);
-			dput(REISERFS_SB(s)->priv_root);
-			REISERFS_SB(s)->priv_root = NULL;
-		}
+		/*
+		 * Force any pending inode evictions to occur now. Any
+		 * inodes to be removed that have extended attributes
+		 * associated with them need to clean them up before
+		 * we can release the extended attribute root dentries.
+		 * shrink_dcache_for_umount will BUG if we don't release
+		 * those before it's called so ->put_super is too late.
+		 */
+		shrink_dcache_sb(s);
+
+		dput(REISERFS_SB(s)->xattr_root);
+		REISERFS_SB(s)->xattr_root = NULL;
+		dput(REISERFS_SB(s)->priv_root);
+		REISERFS_SB(s)->priv_root = NULL;
 	}
 
 	kill_block_super(s);
@@ -1164,7 +1168,8 @@
 			kfree(REISERFS_SB(s)->s_qf_names[i]);
 		REISERFS_SB(s)->s_qf_names[i] = qf_names[i];
 	}
-	REISERFS_SB(s)->s_jquota_fmt = *qfmt;
+	if (*qfmt)
+		REISERFS_SB(s)->s_jquota_fmt = *qfmt;
 }
 #endif
 
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 05d6b0e..dba43c3 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -449,8 +449,6 @@
 
 /*
  * Same as seq_path, but relative to supplied root.
- *
- * root may be changed, see __d_path().
  */
 int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
 		  char *esc)
@@ -463,6 +461,8 @@
 		char *p;
 
 		p = __d_path(path, root, buf, size);
+		if (!p)
+			return SEQ_SKIP;
 		res = PTR_ERR(p);
 		if (!IS_ERR(p)) {
 			char *end = mangle_path(buf, p, esc);
@@ -474,7 +474,7 @@
 	}
 	seq_commit(m, res);
 
-	return res < 0 ? res : 0;
+	return res < 0 && res != -ENAMETOOLONG ? res : 0;
 }
 
 /*
diff --git a/fs/stat.c b/fs/stat.c
index 9610391..02a6061 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -296,15 +296,16 @@
 {
 	struct path path;
 	int error;
+	int empty = 0;
 
 	if (bufsiz <= 0)
 		return -EINVAL;
 
-	error = user_path_at(dfd, pathname, LOOKUP_EMPTY, &path);
+	error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty);
 	if (!error) {
 		struct inode *inode = path.dentry->d_inode;
 
-		error = -EINVAL;
+		error = empty ? -ENOENT : -EINVAL;
 		if (inode->i_op->readlink) {
 			error = security_inode_readlink(path.dentry);
 			if (!error) {
diff --git a/fs/statfs.c b/fs/statfs.c
index 8244924..9cf04a1 100644
--- a/fs/statfs.c
+++ b/fs/statfs.c
@@ -76,7 +76,7 @@
 int user_statfs(const char __user *pathname, struct kstatfs *st)
 {
 	struct path path;
-	int error = user_path(pathname, &path);
+	int error = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
 	if (!error) {
 		error = vfs_statfs(&path, st);
 		path_put(&path);
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index a811ac4..fd75b635 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -121,20 +121,21 @@
 			 const union ubifs_key *key);
 
 /*
- * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
- * macros.
+ * TODO: these macros are now broken because there is no locking around them
+ * and we use a global buffer for the key string. This means that in case of
+ * concurrent execution we will end up with incorrect and messy key strings.
  */
 #define DBGKEY(key) dbg_key_str0(c, (key))
 #define DBGKEY1(key) dbg_key_str1(c, (key))
 
-#define ubifs_dbg_msg(type, fmt, ...) do {                        \
-	spin_lock(&dbg_lock);                                     \
-	pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
-	spin_unlock(&dbg_lock);                                   \
-} while (0)
+#define ubifs_dbg_msg(type, fmt, ...) \
+	pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
 
 /* Just a debugging messages not related to any specific UBIFS subsystem */
-#define dbg_msg(fmt, ...)   ubifs_dbg_msg("msg", fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                                     \
+	printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,  \
+	       __func__, ##__VA_ARGS__)
+
 /* General messages */
 #define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Additional journal messages */
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 2a346bb..0c0c9d3 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -125,7 +125,6 @@
 			err = udf_expand_file_adinicb(inode);
 			if (err) {
 				udf_debug("udf_expand_adinicb: err=%d\n", err);
-				up_write(&iinfo->i_data_sem);
 				return err;
 			}
 		} else {
@@ -133,9 +132,10 @@
 				iinfo->i_lenAlloc = pos + count;
 			else
 				iinfo->i_lenAlloc = inode->i_size;
+			up_write(&iinfo->i_data_sem);
 		}
-	}
-	up_write(&iinfo->i_data_sem);
+	} else
+		up_write(&iinfo->i_data_sem);
 
 	retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
 	if (retval > 0)
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 1d1358e..262050f 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -145,6 +145,12 @@
 	.bmap		= udf_bmap,
 };
 
+/*
+ * Expand file stored in ICB to a normal one-block-file
+ *
+ * This function requires i_data_sem for writing and releases it.
+ * This function requires i_mutex held
+ */
 int udf_expand_file_adinicb(struct inode *inode)
 {
 	struct page *page;
@@ -163,9 +169,15 @@
 			iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
 		/* from now on we have normal address_space methods */
 		inode->i_data.a_ops = &udf_aops;
+		up_write(&iinfo->i_data_sem);
 		mark_inode_dirty(inode);
 		return 0;
 	}
+	/*
+	 * Release i_data_sem so that we can lock a page - page lock ranks
+	 * above i_data_sem. i_mutex still protects us against file changes.
+	 */
+	up_write(&iinfo->i_data_sem);
 
 	page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
 	if (!page)
@@ -181,6 +193,7 @@
 		SetPageUptodate(page);
 		kunmap(page);
 	}
+	down_write(&iinfo->i_data_sem);
 	memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr, 0x00,
 	       iinfo->i_lenAlloc);
 	iinfo->i_lenAlloc = 0;
@@ -190,17 +203,20 @@
 		iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
 	/* from now on we have normal address_space methods */
 	inode->i_data.a_ops = &udf_aops;
+	up_write(&iinfo->i_data_sem);
 	err = inode->i_data.a_ops->writepage(page, &udf_wbc);
 	if (err) {
 		/* Restore everything back so that we don't lose data... */
 		lock_page(page);
 		kaddr = kmap(page);
+		down_write(&iinfo->i_data_sem);
 		memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr,
 		       inode->i_size);
 		kunmap(page);
 		unlock_page(page);
 		iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
 		inode->i_data.a_ops = &udf_adinicb_aops;
+		up_write(&iinfo->i_data_sem);
 	}
 	page_cache_release(page);
 	mark_inode_dirty(inode);
@@ -1105,10 +1121,9 @@
 			if (bsize <
 			    (udf_file_entry_alloc_offset(inode) + newsize)) {
 				err = udf_expand_file_adinicb(inode);
-				if (err) {
-					up_write(&iinfo->i_data_sem);
+				if (err)
 					return err;
-				}
+				down_write(&iinfo->i_data_sem);
 			} else
 				iinfo->i_lenAlloc = newsize;
 		}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 7b27b06..7f0e18a 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1830,6 +1830,12 @@
 				le16_to_cpu(lvid->descTag.descCRCLength)));
 
 	lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
+	/*
+	 * We set buffer uptodate unconditionally here to avoid spurious
+	 * warnings from mark_buffer_dirty() when previous EIO has marked
+	 * the buffer as !uptodate
+	 */
+	set_buffer_uptodate(bh);
 	mark_buffer_dirty(bh);
 	sbi->s_lvid_dirty = 0;
 	mutex_unlock(&sbi->s_alloc_mutex);
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c
index 39f4f80..f86e034 100644
--- a/fs/xfs/linux-2.6/xfs_acl.c
+++ b/fs/xfs/linux-2.6/xfs_acl.c
@@ -39,9 +39,11 @@
 	struct posix_acl_entry *acl_e;
 	struct posix_acl *acl;
 	struct xfs_acl_entry *ace;
-	int count, i;
+	unsigned int count, i;
 
 	count = be32_to_cpu(aclp->acl_cnt);
+	if (count > XFS_ACL_MAX_ENTRIES)
+		return ERR_PTR(-EFSCORRUPTED);
 
 	acl = posix_acl_alloc(count, GFP_KERNEL);
 	if (!acl)
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index 50a7d5f..36d6ee4 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -346,7 +346,6 @@
 #define xfs_getsize_buftarg(buftarg)	block_size((buftarg)->bt_bdev)
 #define xfs_readonly_buftarg(buftarg)	bdev_read_only((buftarg)->bt_bdev)
 
-#define xfs_binval(buftarg)		xfs_flush_buftarg(buftarg, 1)
 #define XFS_bflush(buftarg)		xfs_flush_buftarg(buftarg, 1)
 
 #endif	/* __XFS_BUF_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_discard.c b/fs/xfs/linux-2.6/xfs_discard.c
index 244e797..572494f 100644
--- a/fs/xfs/linux-2.6/xfs_discard.c
+++ b/fs/xfs/linux-2.6/xfs_discard.c
@@ -68,7 +68,7 @@
 	 * Look up the longest btree in the AGF and start with it.
 	 */
 	error = xfs_alloc_lookup_le(cur, 0,
-				    XFS_BUF_TO_AGF(agbp)->agf_longest, &i);
+			    be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest), &i);
 	if (error)
 		goto out_del_cursor;
 
@@ -84,7 +84,7 @@
 		if (error)
 			goto out_del_cursor;
 		XFS_WANT_CORRUPTED_GOTO(i == 1, out_del_cursor);
-		ASSERT(flen <= XFS_BUF_TO_AGF(agbp)->agf_longest);
+		ASSERT(flen <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest));
 
 		/*
 		 * Too small?  Give up.
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index f4f878f..fed3f3c 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -98,22 +98,22 @@
 	switch (fileid_type) {
 	case FILEID_INO32_GEN_PARENT:
 		spin_lock(&dentry->d_lock);
-		fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino;
+		fid->i32.parent_ino = XFS_I(dentry->d_parent->d_inode)->i_ino;
 		fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation;
 		spin_unlock(&dentry->d_lock);
 		/*FALLTHRU*/
 	case FILEID_INO32_GEN:
-		fid->i32.ino = inode->i_ino;
+		fid->i32.ino = XFS_I(inode)->i_ino;
 		fid->i32.gen = inode->i_generation;
 		break;
 	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
 		spin_lock(&dentry->d_lock);
-		fid64->parent_ino = dentry->d_parent->d_inode->i_ino;
+		fid64->parent_ino = XFS_I(dentry->d_parent->d_inode)->i_ino;
 		fid64->parent_gen = dentry->d_parent->d_inode->i_generation;
 		spin_unlock(&dentry->d_lock);
 		/*FALLTHRU*/
 	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		fid64->ino = inode->i_ino;
+		fid64->ino = XFS_I(inode)->i_ino;
 		fid64->gen = inode->i_generation;
 		break;
 	}
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 7f782af..b679198 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -309,7 +309,19 @@
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return -EIO;
 
-	if (unlikely(ioflags & IO_ISDIRECT)) {
+	/*
+	 * Locking is a bit tricky here. If we take an exclusive lock
+	 * for direct IO, we effectively serialise all new concurrent
+	 * read IO to this file and block it behind IO that is currently in
+	 * progress because IO in progress holds the IO lock shared. We only
+	 * need to hold the lock exclusive to blow away the page cache, so
+	 * only take lock exclusively if the page cache needs invalidation.
+	 * This allows the normal direct IO case of no page cache pages to
+	 * proceeed concurrently without serialisation.
+	 */
+	xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
+	if ((ioflags & IO_ISDIRECT) && inode->i_mapping->nrpages) {
+		xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
 		xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);
 
 		if (inode->i_mapping->nrpages) {
@@ -322,8 +334,7 @@
 			}
 		}
 		xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
-	} else
-		xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
+	}
 
 	trace_xfs_file_read(ip, size, iocb->ki_pos, ioflags);
 
@@ -658,6 +669,7 @@
 	xfs_fsize_t		new_size;
 	int			error = 0;
 
+	xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
 	error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode));
 	if (error) {
 		xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
@@ -749,14 +761,24 @@
 		*iolock = XFS_IOLOCK_EXCL;
 	else
 		*iolock = XFS_IOLOCK_SHARED;
-	xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+	xfs_rw_ilock(ip, *iolock);
 
 	ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
 	if (ret)
 		return ret;
 
+	/*
+	 * Recheck if there are cached pages that need invalidate after we got
+	 * the iolock to protect against other threads adding new pages while
+	 * we were waiting for the iolock.
+	 */
+	if (mapping->nrpages && *iolock == XFS_IOLOCK_SHARED) {
+		xfs_rw_iunlock(ip, *iolock);
+		*iolock = XFS_IOLOCK_EXCL;
+		xfs_rw_ilock(ip, *iolock);
+	}
+
 	if (mapping->nrpages) {
-		WARN_ON(*iolock != XFS_IOLOCK_EXCL);
 		ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1,
 							FI_REMAPF_LOCKED);
 		if (ret)
@@ -801,7 +823,7 @@
 	size_t			count = ocount;
 
 	*iolock = XFS_IOLOCK_EXCL;
-	xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+	xfs_rw_ilock(ip, *iolock);
 
 	ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
 	if (ret)
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index d44d92c..f5b697b 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -69,9 +69,8 @@
 }
 
 /*
- * If the linux inode is valid, mark it dirty.
- * Used when committing a dirty inode into a transaction so that
- * the inode will get written back by the linux code
+ * If the linux inode is valid, mark it dirty, else mark the dirty state
+ * in the XFS inode to make sure we pick it up when reclaiming the inode.
  */
 void
 xfs_mark_inode_dirty_sync(
@@ -81,6 +80,10 @@
 
 	if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
 		mark_inode_dirty_sync(inode);
+	else {
+		barrier();
+		ip->i_update_core = 1;
+	}
 }
 
 void
@@ -91,6 +94,11 @@
 
 	if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
 		mark_inode_dirty(inode);
+	else {
+		barrier();
+		ip->i_update_core = 1;
+	}
+
 }
 
 /*
@@ -456,7 +464,7 @@
 	trace_xfs_getattr(ip);
 
 	if (XFS_FORCED_SHUTDOWN(mp))
-		return XFS_ERROR(EIO);
+		return -XFS_ERROR(EIO);
 
 	stat->size = XFS_ISIZE(ip);
 	stat->dev = inode->i_sb->s_dev;
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 347cae9..e6ac98c 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -871,43 +871,6 @@
 }
 
 STATIC int
-xfs_log_inode(
-	struct xfs_inode	*ip)
-{
-	struct xfs_mount	*mp = ip->i_mount;
-	struct xfs_trans	*tp;
-	int			error;
-
-	xfs_iunlock(ip, XFS_ILOCK_SHARED);
-	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
-	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-
-	if (error) {
-		xfs_trans_cancel(tp, 0);
-		/* we need to return with the lock hold shared */
-		xfs_ilock(ip, XFS_ILOCK_SHARED);
-		return error;
-	}
-
-	xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-	/*
-	 * Note - it's possible that we might have pushed ourselves out of the
-	 * way during trans_reserve which would flush the inode.  But there's
-	 * no guarantee that the inode buffer has actually gone out yet (it's
-	 * delwri).  Plus the buffer could be pinned anyway if it's part of
-	 * an inode in another recent transaction.  So we play it safe and
-	 * fire off the transaction anyway.
-	 */
-	xfs_trans_ijoin(tp, ip);
-	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-	error = xfs_trans_commit(tp, 0);
-	xfs_ilock_demote(ip, XFS_ILOCK_EXCL);
-
-	return error;
-}
-
-STATIC int
 xfs_fs_write_inode(
 	struct inode		*inode,
 	struct writeback_control *wbc)
@@ -919,9 +882,9 @@
 	trace_xfs_write_inode(ip);
 
 	if (XFS_FORCED_SHUTDOWN(mp))
-		return XFS_ERROR(EIO);
+		return -XFS_ERROR(EIO);
 
-	if (wbc->sync_mode == WB_SYNC_ALL) {
+	if (wbc->sync_mode == WB_SYNC_ALL || wbc->for_kupdate) {
 		/*
 		 * Make sure the inode has made it it into the log.  Instead
 		 * of forcing it all the way to stable storage using a
@@ -930,13 +893,14 @@
 		 * of synchronous log foces dramatically.
 		 */
 		xfs_ioend_wait(ip);
-		xfs_ilock(ip, XFS_ILOCK_SHARED);
-		if (ip->i_update_core) {
-			error = xfs_log_inode(ip);
-			if (error)
-				goto out_unlock;
-		}
+		error = xfs_log_dirty_inode(ip, NULL, 0);
+		if (error)
+			goto out;
+		return 0;
 	} else {
+		if (!ip->i_update_core)
+			return 0;
+
 		/*
 		 * We make this non-blocking if the inode is contended, return
 		 * EAGAIN to indicate to the caller that they did not succeed.
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 8ecad5f..2f277a0 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -336,6 +336,32 @@
 	return xfs_bwrite(mp, bp);
 }
 
+int
+xfs_log_dirty_inode(
+	struct xfs_inode	*ip,
+	struct xfs_perag	*pag,
+	int			flags)
+{
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_trans	*tp;
+	int			error;
+
+	if (!ip->i_update_core)
+		return 0;
+
+	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
+	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
+	if (error) {
+		xfs_trans_cancel(tp, 0);
+		return error;
+	}
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+	return xfs_trans_commit(tp, 0);
+}
+
 /*
  * When remounting a filesystem read-only or freezing the filesystem, we have
  * two phases to execute. This first phase is syncing the data before we
@@ -365,6 +391,17 @@
 
 	/* push and block till complete */
 	xfs_sync_data(mp, SYNC_WAIT);
+
+	/*
+	 * Log all pending size and timestamp updates.  The vfs writeback
+	 * code is supposed to do this, but due to its overagressive
+	 * livelock detection it will skip inodes where appending writes
+	 * were written out in the first non-blocking sync phase if their
+	 * completion took long enough that it happened after taking the
+	 * timestamp for the cut-off in the blocking phase.
+	 */
+	xfs_inode_ag_iterator(mp, xfs_log_dirty_inode, 0);
+
 	xfs_qm_sync(mp, SYNC_WAIT);
 
 	/* write superblock and hoover up shutdown errors */
@@ -772,6 +809,17 @@
 	if (!xfs_iflock_nowait(ip)) {
 		if (!(sync_mode & SYNC_WAIT))
 			goto out;
+
+		/*
+		 * If we only have a single dirty inode in a cluster there is
+		 * a fair chance that the AIL push may have pushed it into
+		 * the buffer, but xfsbufd won't touch it until 30 seconds
+		 * from now, and thus we will lock up here.
+		 *
+		 * Promote the inode buffer to the front of the delwri list
+		 * and wake up xfsbufd now.
+		 */
+		xfs_promote_inode(ip);
 		xfs_iflock(ip);
 	}
 
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h
index e3a6ad2..ef5b2ce 100644
--- a/fs/xfs/linux-2.6/xfs_sync.h
+++ b/fs/xfs/linux-2.6/xfs_sync.h
@@ -42,6 +42,8 @@
 
 void xfs_flush_inodes(struct xfs_inode *ip);
 
+int xfs_log_dirty_inode(struct xfs_inode *ip, struct xfs_perag *pag, int flags);
+
 int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
 
 void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index b94dace..e70c7fc 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -714,7 +714,8 @@
 	 * disk and we didn't ask it to allocate;
 	 * ESRCH if quotas got turned off suddenly.
 	 */
-	error = xfs_qm_dqget(ip->i_mount, ip, id, type, XFS_QMOPT_DOWARN, &dqp);
+	error = xfs_qm_dqget(ip->i_mount, ip, id, type,
+			     doalloc | XFS_QMOPT_DOWARN, &dqp);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 01d2072..99d4011 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -822,17 +822,9 @@
 	error = xfs_attr_root_inactive(&trans, dp);
 	if (error)
 		goto out;
-	/*
-	 * signal synchronous inactive transactions unless this
-	 * is a synchronous mount filesystem in which case we
-	 * know that we're here because we've been called out of
-	 * xfs_inactive which means that the last reference is gone
-	 * and the unlink transaction has already hit the disk so
-	 * async inactive transactions are safe.
-	 */
-	if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK,
-				(!(mp->m_flags & XFS_MOUNT_WSYNC)
-				 ? 1 : 0))))
+
+	error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, 0);
+	if (error)
 		goto out;
 
 	/*
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 71e90dc2..f49ecf2 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -110,6 +110,7 @@
 /*
  * Query whether the requested number of additional bytes of extended
  * attribute space will be able to fit inline.
+ *
  * Returns zero if not, else the di_forkoff fork offset to be used in the
  * literal area for attribute data once the new bytes have been added.
  *
@@ -122,7 +123,7 @@
 	int offset;
 	int minforkoff;	/* lower limit on valid forkoff locations */
 	int maxforkoff;	/* upper limit on valid forkoff locations */
-	int dsize;	
+	int dsize;
 	xfs_mount_t *mp = dp->i_mount;
 
 	offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */
@@ -136,47 +137,60 @@
 		return (offset >= minforkoff) ? minforkoff : 0;
 	}
 
-	if (!(mp->m_flags & XFS_MOUNT_ATTR2)) {
-		if (bytes <= XFS_IFORK_ASIZE(dp))
-			return dp->i_d.di_forkoff;
+	/*
+	 * If the requested numbers of bytes is smaller or equal to the
+	 * current attribute fork size we can always proceed.
+	 *
+	 * Note that if_bytes in the data fork might actually be larger than
+	 * the current data fork size is due to delalloc extents. In that
+	 * case either the extent count will go down when they are converted
+	 * to real extents, or the delalloc conversion will take care of the
+	 * literal area rebalancing.
+	 */
+	if (bytes <= XFS_IFORK_ASIZE(dp))
+		return dp->i_d.di_forkoff;
+
+	/*
+	 * For attr2 we can try to move the forkoff if there is space in the
+	 * literal area, but for the old format we are done if there is no
+	 * space in the fixed attribute fork.
+	 */
+	if (!(mp->m_flags & XFS_MOUNT_ATTR2))
 		return 0;
-	}
 
 	dsize = dp->i_df.if_bytes;
-	
+
 	switch (dp->i_d.di_format) {
 	case XFS_DINODE_FMT_EXTENTS:
-		/* 
+		/*
 		 * If there is no attr fork and the data fork is extents, 
-		 * determine if creating the default attr fork will result 
-		 * in the extents form migrating to btree. If so, the 
-		 * minimum offset only needs to be the space required for 
+		 * determine if creating the default attr fork will result
+		 * in the extents form migrating to btree. If so, the
+		 * minimum offset only needs to be the space required for
 		 * the btree root.
-		 */ 
+		 */
 		if (!dp->i_d.di_forkoff && dp->i_df.if_bytes >
 		    xfs_default_attroffset(dp))
 			dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
 		break;
-		
 	case XFS_DINODE_FMT_BTREE:
 		/*
-		 * If have data btree then keep forkoff if we have one,
-		 * otherwise we are adding a new attr, so then we set 
-		 * minforkoff to where the btree root can finish so we have 
+		 * If we have a data btree then keep forkoff if we have one,
+		 * otherwise we are adding a new attr, so then we set
+		 * minforkoff to where the btree root can finish so we have
 		 * plenty of room for attrs
 		 */
 		if (dp->i_d.di_forkoff) {
-			if (offset < dp->i_d.di_forkoff) 
+			if (offset < dp->i_d.di_forkoff)
 				return 0;
-			else 
-				return dp->i_d.di_forkoff;
-		} else
-			dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);
+			return dp->i_d.di_forkoff;
+		}
+		dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);
 		break;
 	}
-	
-	/* 
-	 * A data fork btree root must have space for at least 
+
+	/*
+	 * A data fork btree root must have space for at least
 	 * MINDBTPTRS key/ptr pairs if the data fork is small or empty.
 	 */
 	minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
@@ -186,10 +200,10 @@
 	maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
 	maxforkoff = maxforkoff >> 3;	/* rounded down */
 
-	if (offset >= minforkoff && offset < maxforkoff)
-		return offset;
 	if (offset >= maxforkoff)
 		return maxforkoff;
+	if (offset >= minforkoff)
+		return offset;
 	return 0;
 }
 
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index e546a33..a175933 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -3785,19 +3785,11 @@
  * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
  * caller.  Frees all the extents that need freeing, which must be done
  * last due to locking considerations.  We never free any extents in
- * the first transaction.  This is to allow the caller to make the first
- * transaction a synchronous one so that the pointers to the data being
- * broken in this transaction will be permanent before the data is actually
- * freed.  This is necessary to prevent blocks from being reallocated
- * and written to before the free and reallocation are actually permanent.
- * We do not just make the first transaction synchronous here, because
- * there are more efficient ways to gain the same protection in some cases
- * (see the file truncation code).
+ * the first transaction.
  *
  * Return 1 if the given transaction was committed and a new one
  * started, and 0 otherwise in the committed parameter.
  */
-/*ARGSUSED*/
 int						/* error */
 xfs_bmap_finish(
 	xfs_trans_t		**tp,		/* transaction pointer addr */
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index a7342e8..7888a75 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -1023,7 +1023,6 @@
 	XFS_BUF_UNDELAYWRITE(bp);
 
 	trace_xfs_buf_error_relse(bp, _RET_IP_);
-	xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
 
 do_callbacks:
 	xfs_buf_do_callbacks(bp);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a098a20..5715279 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1528,15 +1528,7 @@
 				xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
 			}
 		}
-	} else if (sync) {
-		ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC));
-		if (ip->i_d.di_anextents > 0)
-			xfs_trans_set_sync(ntp);
 	}
-	ASSERT(fork == XFS_DATA_FORK ||
-		(fork == XFS_ATTR_FORK &&
-			((sync && !(mp->m_flags & XFS_MOUNT_WSYNC)) ||
-			 (sync == 0 && (mp->m_flags & XFS_MOUNT_WSYNC)))));
 
 	/*
 	 * Since it is possible for space to become allocated beyond
@@ -3099,6 +3091,27 @@
 	return XFS_ERROR(EFSCORRUPTED);
 }
 
+void
+xfs_promote_inode(
+	struct xfs_inode	*ip)
+{
+	struct xfs_buf		*bp;
+
+	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
+
+	bp = xfs_incore(ip->i_mount->m_ddev_targp, ip->i_imap.im_blkno,
+			ip->i_imap.im_len, XBF_TRYLOCK);
+	if (!bp)
+		return;
+
+	if (XFS_BUF_ISDELAYWRITE(bp)) {
+		xfs_buf_delwri_promote(bp);
+		wake_up_process(ip->i_mount->m_ddev_targp->bt_task);
+	}
+
+	xfs_buf_relse(bp);
+}
+
 /*
  * Return a pointer to the extent record at file index idx.
  */
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 964cfea..28b3596 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -509,6 +509,7 @@
 void		xfs_iext_realloc(xfs_inode_t *, int, int);
 void		xfs_iunpin_wait(xfs_inode_t *);
 int		xfs_iflush(xfs_inode_t *, uint);
+void		xfs_promote_inode(struct xfs_inode *);
 void		xfs_lock_inodes(xfs_inode_t **, int, uint);
 void		xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
 
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index b49b823..9afdd49 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -44,9 +44,6 @@
 #include "xfs_trace.h"
 
 
-STATIC void	xfs_unmountfs_wait(xfs_mount_t *);
-
-
 #ifdef HAVE_PERCPU_SB
 STATIC void	xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
 						int);
@@ -1507,11 +1504,6 @@
 	 */
 	xfs_log_force(mp, XFS_LOG_SYNC);
 
-	xfs_binval(mp->m_ddev_targp);
-	if (mp->m_rtdev_targp) {
-		xfs_binval(mp->m_rtdev_targp);
-	}
-
 	/*
 	 * Unreserve any blocks we have so that when we unmount we don't account
 	 * the reserved free space as used. This is really only necessary for
@@ -1537,7 +1529,16 @@
 		xfs_warn(mp, "Unable to update superblock counters. "
 				"Freespace may not be correct on next mount.");
 	xfs_unmountfs_writesb(mp);
-	xfs_unmountfs_wait(mp); 		/* wait for async bufs */
+
+	/*
+	 * Make sure all buffers have been flushed and completed before
+	 * unmounting the log.
+	 */
+	error = xfs_flush_buftarg(mp->m_ddev_targp, 1);
+	if (error)
+		xfs_warn(mp, "%d busy buffers during unmount.", error);
+	xfs_wait_buftarg(mp->m_ddev_targp);
+
 	xfs_log_unmount_write(mp);
 	xfs_log_unmount(mp);
 	xfs_uuid_unmount(mp);
@@ -1548,16 +1549,6 @@
 	xfs_free_perag(mp);
 }
 
-STATIC void
-xfs_unmountfs_wait(xfs_mount_t *mp)
-{
-	if (mp->m_logdev_targp != mp->m_ddev_targp)
-		xfs_wait_buftarg(mp->m_logdev_targp);
-	if (mp->m_rtdev_targp)
-		xfs_wait_buftarg(mp->m_rtdev_targp);
-	xfs_wait_buftarg(mp->m_ddev_targp);
-}
-
 int
 xfs_fs_writable(xfs_mount_t *mp)
 {
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 6197207..59509ae 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -535,7 +535,7 @@
 	char		*link)
 {
 	xfs_mount_t	*mp = ip->i_mount;
-	int		pathlen;
+	xfs_fsize_t	pathlen;
 	int		error = 0;
 
 	trace_xfs_readlink(ip);
@@ -545,13 +545,20 @@
 
 	xfs_ilock(ip, XFS_ILOCK_SHARED);
 
-	ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);
-	ASSERT(ip->i_d.di_size <= MAXPATHLEN);
-
 	pathlen = ip->i_d.di_size;
 	if (!pathlen)
 		goto out;
 
+	if (pathlen < 0 || pathlen > MAXPATHLEN) {
+		xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
+			 __func__, (unsigned long long) ip->i_ino,
+			 (long long) pathlen);
+		ASSERT(0);
+		error = XFS_ERROR(EFSCORRUPTED);
+		goto out;
+	}
+
+
 	if (ip->i_df.if_flags & XFS_IFINLINE) {
 		memcpy(link, ip->i_df.if_u1.if_data, pathlen);
 		link[pathlen] = '\0';
diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h
index 1739726..451823c 100644
--- a/include/acpi/acpi_numa.h
+++ b/include/acpi/acpi_numa.h
@@ -15,6 +15,7 @@
 extern int node_to_pxm(int);
 extern void __acpi_map_pxm_to_node(int, int);
 extern int acpi_map_pxm_to_node(int);
+extern unsigned char acpi_srat_revision;
 
 #endif				/* CONFIG_ACPI_NUMA */
 #endif				/* __ACP_NUMA_H */
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 738b3a5..40aaebf 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1323,6 +1323,7 @@
 			struct drm_file *file_priv);
 extern int drm_authmagic(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv);
+extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
 
 /* Cache management (drm_cache.c) */
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 91567bb..03eb1d6 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -72,6 +72,7 @@
 
 #define DP_MAIN_LINK_CHANNEL_CODING         0x006
 
+#define DP_EDP_CONFIGURATION_CAP            0x00d
 #define DP_TRAINING_AUX_RD_INTERVAL         0x00e
 
 /* link configuration */
@@ -133,6 +134,8 @@
 #define DP_MAIN_LINK_CHANNEL_CODING_SET	    0x108
 # define DP_SET_ANSI_8B10B		    (1 << 0)
 
+#define DP_EDP_CONFIGURATION_SET            0x10a
+
 #define DP_LANE0_1_STATUS		    0x202
 #define DP_LANE2_3_STATUS		    0x203
 # define DP_LANE_CR_DONE		    (1 << 0)
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index c4961ea..53dfa109 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -233,6 +233,8 @@
 #define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02
 #define DRM_MODE_FB_DIRTY_FLAGS         0x03
 
+#define DRM_MODE_FB_DIRTY_MAX_CLIPS     256
+
 /*
  * Mark a region of a framebuffer as dirty.
  *
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 3d53efd..14b6cd0 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -4,6 +4,7 @@
 */
 #define radeon_PCI_IDS \
 	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x3151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x3155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@@ -55,6 +56,7 @@
 	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
@@ -180,8 +182,11 @@
 	{0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6759, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x675B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x675D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x675F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6761, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@@ -193,8 +198,18 @@
 	{0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x677B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6842, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6843, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6849, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6889, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
@@ -236,6 +251,7 @@
 	{0x1002, 0x68f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x68f8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x68f9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x68fa, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x68fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x7100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x7101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@@ -478,6 +494,8 @@
 	{0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
 	{0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
 	{0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x964e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
 	{0x1002, 0x964f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
 	{0x1002, 0x9710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
@@ -492,6 +510,8 @@
 	{0x1002, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0, 0, 0}
 
 #define r128_PCI_IDS \
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 9c43f56..79f7874 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -428,6 +428,7 @@
 header-y += msm_ipc.h
 header-y += msm_charm.h
 header-y += tzcom.h
+header-y += qseecom.h
 header-y += qcedev.h
 header-y += idle_stats_device.h
 header-y += genlock.h
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 1a23722..1b13021 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -670,6 +670,9 @@
 				     struct request *rq);
 extern void blk_delay_queue(struct request_queue *, unsigned long);
 extern void blk_recount_segments(struct request_queue *, struct bio *);
+extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int);
+extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t,
+			      unsigned int, void __user *);
 extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
 			  unsigned int, void __user *);
 extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
@@ -798,9 +801,6 @@
  */
 extern struct request_queue *blk_init_queue_node(request_fn_proc *rfn,
 					spinlock_t *lock, int node_id);
-extern struct request_queue *blk_init_allocated_queue_node(struct request_queue *,
-							   request_fn_proc *,
-							   spinlock_t *, int node_id);
 extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *);
 extern struct request_queue *blk_init_allocated_queue(struct request_queue *,
 						      request_fn_proc *, spinlock_t *);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 19d90a5..f13bb6d 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -207,6 +207,7 @@
 
 #define DCACHE_CANT_MOUNT	0x0100
 #define DCACHE_GENOCIDE		0x0200
+#define DCACHE_SHRINK_LIST	0x0400
 
 #define DCACHE_OP_HASH		0x1000
 #define DCACHE_OP_COMPARE	0x2000
@@ -340,7 +341,8 @@
  */
 extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
 
-extern char *__d_path(const struct path *path, struct path *root, char *, int);
+extern char *__d_path(const struct path *, const struct path *, char *, int);
+extern char *d_absolute_path(const struct path *, char *, int);
 extern char *d_path(const struct path *, char *, int);
 extern char *d_path_with_unreachable(const struct path *, char *, int);
 extern char *dentry_path_raw(struct dentry *, char *, int);
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 1cb5401..15737d6 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,10 +635,51 @@
 	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
-#define LOG_1	0x1520
+#define LOG_1	0x15A7
 #define LOG_2	0x0
 #define LOG_3	0x0
 #define LOG_4	0x4910
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
new file mode 100644
index 0000000..1af97fe
--- /dev/null
+++ b/include/linux/epm_adc.h
@@ -0,0 +1,55 @@
+/*
+ * 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 __EPM_ADC_H
+#define __EPM_ADC_H
+
+#include <linux/i2c.h>
+
+struct epm_chan_request {
+	/* EPM ADC device index. 0 - ADC1, 1 - ADC2 */
+	uint32_t device_idx;
+	/* Channel number within the EPM ADC device  */
+	uint32_t channel_idx;
+	/* The data meaningful for each individual channel whether it is
+	 * voltage, current etc. */
+	int32_t physical;
+};
+
+struct epm_chan_properties {
+	uint32_t resistorValue;
+	uint32_t gain;
+};
+
+struct epm_adc_platform_data {
+	struct epm_chan_properties *channel;
+	uint32_t num_channels;
+	uint32_t num_adc;
+	uint32_t chan_per_adc;
+	uint32_t chan_per_mux;
+	struct i2c_board_info epm_i2c_board_info;
+	uint32_t bus_id;
+	uint32_t gpio_expander_base_addr;
+};
+
+#define EPM_ADC_IOCTL_CODE		0x91
+
+#define EPM_ADC_REQUEST		_IOWR(EPM_ADC_IOCTL_CODE, 1,	\
+					struct epm_chan_request)
+
+#define EPM_ADC_INIT		_IOR(EPM_ADC_IOCTL_CODE, 2,	\
+					     uint32_t)
+
+#define EPM_ADC_DEINIT		_IOR(EPM_ADC_IOCTL_CODE, 3,	\
+					     uint32_t)
+#endif /* __EPM_ADC_H */
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 2dfa707..0bfcb76 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -196,8 +196,8 @@
 
 /* Flags that should be inherited by new inodes from their parent. */
 #define EXT2_FL_INHERITED (EXT2_SECRM_FL | EXT2_UNRM_FL | EXT2_COMPR_FL |\
-			   EXT2_SYNC_FL | EXT2_IMMUTABLE_FL | EXT2_APPEND_FL |\
-			   EXT2_NODUMP_FL | EXT2_NOATIME_FL | EXT2_COMPRBLK_FL|\
+			   EXT2_SYNC_FL | EXT2_NODUMP_FL |\
+			   EXT2_NOATIME_FL | EXT2_COMPRBLK_FL |\
 			   EXT2_NOCOMP_FL | EXT2_JOURNAL_DATA_FL |\
 			   EXT2_NOTAIL_FL | EXT2_DIRSYNC_FL)
 
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 5e06acf..7b14d25 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -180,8 +180,8 @@
 
 /* Flags that should be inherited by new inodes from their parent. */
 #define EXT3_FL_INHERITED (EXT3_SECRM_FL | EXT3_UNRM_FL | EXT3_COMPR_FL |\
-			   EXT3_SYNC_FL | EXT3_IMMUTABLE_FL | EXT3_APPEND_FL |\
-			   EXT3_NODUMP_FL | EXT3_NOATIME_FL | EXT3_COMPRBLK_FL|\
+			   EXT3_SYNC_FL | EXT3_NODUMP_FL |\
+			   EXT3_NOATIME_FL | EXT3_COMPRBLK_FL |\
 			   EXT3_NOCOMPR_FL | EXT3_JOURNAL_DATA_FL |\
 			   EXT3_NOTAIL_FL | EXT3_DIRSYNC_FL)
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d10b5b5..35e4edf 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1883,6 +1883,7 @@
 extern int statfs_by_dentry(struct dentry *, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
 extern int thaw_super(struct super_block *super);
+extern bool our_mnt(struct vfsmount *mnt);
 
 extern int current_umask(void);
 
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 500ee6b..b54fcb4 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 */
@@ -44,10 +53,18 @@
 	const struct mxt_config_info *config_array;
 	size_t config_array_size;
 
-	unsigned int x_size;
-	unsigned int y_size;
-	unsigned int touch_x_size;
-	unsigned int touch_y_size;
+	/* touch panel's minimum and maximum coordinates */
+	u32 panel_minx;
+	u32 panel_maxx;
+	u32 panel_miny;
+	u32 panel_maxy;
+
+	/* display's minimum and maximum coordinates */
+	u32 disp_minx;
+	u32 disp_maxx;
+	u32 disp_miny;
+	u32 disp_maxy;
+
 	unsigned long irqflags;
 	bool	i2c_pull_up;
 	bool	digital_pwr_regulator;
diff --git a/include/linux/i2c/smb349.h b/include/linux/i2c/smb349.h
new file mode 100644
index 0000000..2adacb3
--- /dev/null
+++ b/include/linux/i2c/smb349.h
@@ -0,0 +1,31 @@
+/* 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 __SMB349_H__
+#define __SMB349_H__
+
+#define SMB349_NAME		"smb349"
+
+/**
+ * struct smb349_platform_data
+ * structure to pass board specific information to the smb137b charger driver
+ * @chg_current_ma:		maximum fast charge current in mA
+ * @en_n_gpio:		gpio to enable or disable charging
+ * @chg_susp_gpio:	put active low to allow chip to suspend and disable I2C
+ */
+struct smb349_platform_data {
+	int en_n_gpio;
+	int chg_susp_gpio;
+	int chg_current_ma;
+};
+
+#endif
diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
index 6427d29..530e11b 100644
--- a/include/linux/i2c/twl4030-madc.h
+++ b/include/linux/i2c/twl4030-madc.h
@@ -129,6 +129,10 @@
 #define REG_BCICTL2             0x024
 #define TWL4030_BCI_ITHSENS	0x007
 
+/* Register and bits for GPBR1 register */
+#define TWL4030_REG_GPBR1		0x0c
+#define TWL4030_GPBR1_MADC_HFCLK_EN	(1 << 7)
+
 struct twl4030_madc_user_parms {
 	int channel;
 	int average;
diff --git a/include/linux/input.h b/include/linux/input.h
index b1f7161..6e7d6d9 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -129,6 +129,9 @@
 
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
 
+#define EVIOCGSUSPENDBLOCK	_IOR('E', 0x91, int)			/* get suspend block enable */
+#define EVIOCSSUSPENDBLOCK	_IOW('E', 0x91, int)			/* set suspend block enable */
+
 /*
  * Device properties and quirks
  */
diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h
new file mode 100644
index 0000000..b2fb3c4
--- /dev/null
+++ b/include/linux/input/ft5x06_ts.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * FocalTech ft5x06 TouchScreen driver header file.
+ *
+ * Copyright (c) 2010  Focal tech Ltd.
+ * Copyright (c) 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_FT5X06_TS_H__
+#define __LINUX_FT5X06_TS_H__
+
+struct ft5x06_ts_platform_data {
+	unsigned long irqflags;
+	u32 x_max;
+	u32 y_max;
+	u32 irq_gpio;
+	u32 reset_gpio;
+	int (*power_init) (bool);
+	int (*power_on) (bool);
+};
+
+#endif
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index c22f9b0..d75eb51 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -59,6 +59,8 @@
  * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
  * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
  * IRQF_NO_THREAD - Interrupt cannot be threaded
+ * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
+ *                resume time.
  */
 #define IRQF_DISABLED		0x00000020
 #define IRQF_SAMPLE_RANDOM	0x00000040
@@ -72,6 +74,7 @@
 #define IRQF_NO_SUSPEND		0x00004000
 #define IRQF_FORCE_RESUME	0x00008000
 #define IRQF_NO_THREAD		0x00010000
+#define IRQF_EARLY_RESUME	0x00020000
 
 #define IRQF_TIMER		(__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index 8cdcc2a1..1feeb52 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -117,6 +117,8 @@
 
 #else
 
+#include <linux/uaccess.h>
+
 /* this struct isn't actually defined anywhere */
 struct io_mapping;
 
@@ -138,12 +140,14 @@
 io_mapping_map_atomic_wc(struct io_mapping *mapping,
 			 unsigned long offset)
 {
+	pagefault_disable();
 	return ((char __force __iomem *) mapping) + offset;
 }
 
 static inline void
 io_mapping_unmap_atomic(void __iomem *vaddr)
 {
+	pagefault_enable();
 }
 
 /* Non-atomic map/unmap */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 3256fba..d761e1e 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -110,6 +110,12 @@
 
 #define ION_IS_CACHED(__flags)	((__flags) & (1 << ION_CACHE_SHIFT))
 
+/*
+ * This flag allows clients when mapping into the IOMMU to specify to
+ * defer un-mapping from the IOMMU until the buffer memory is freed.
+ */
+#define ION_IOMMU_UNMAP_DELAYED 1
+
 #ifdef __KERNEL__
 #include <linux/err.h>
 #include <mach/ion.h>
@@ -407,6 +413,7 @@
  * @iova - pointer to store the iova address
  * @buffer_size - pointer to store the size of the buffer
  * @flags - flags for options to map
+ * @iommu_flags - flags specific to the iommu.
  *
  * Maps the handle into the iova space specified via domain number. Iova
  * will be allocated from the partition specified via partition_num.
@@ -416,7 +423,7 @@
 			int domain_num, int partition_num, unsigned long align,
 			unsigned long iova_length, unsigned long *iova,
 			unsigned long *buffer_size,
-			unsigned long flags);
+			unsigned long flags, unsigned long iommu_flags);
 
 
 /**
@@ -493,6 +500,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)
@@ -570,7 +594,9 @@
 			struct ion_handle *handle, int domain_num,
 			int partition_num, unsigned long align,
 			unsigned long iova_length, unsigned long *iova,
-			unsigned long flags)
+			unsigned long *buffer_size,
+			unsigned long flags,
+			unsigned long iommu_flags)
 {
 	return -ENODEV;
 }
@@ -603,6 +629,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/jiffies.h b/include/linux/jiffies.h
index f97672a..265e2c3 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -303,7 +303,7 @@
 extern unsigned long timeval_to_jiffies(const struct timeval *value);
 extern void jiffies_to_timeval(const unsigned long jiffies,
 			       struct timeval *value);
-extern clock_t jiffies_to_clock_t(long x);
+extern clock_t jiffies_to_clock_t(unsigned long x);
 extern unsigned long clock_t_to_jiffies(unsigned long x);
 extern u64 jiffies_64_to_clock_t(u64 x);
 extern u64 nsec_to_clock_t(u64 x);
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index dd7c12e..dce6e4d 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -181,7 +181,7 @@
 	int nmissed;
 	size_t data_size;
 	struct hlist_head free_instances;
-	spinlock_t lock;
+	raw_spinlock_t lock;
 };
 
 struct kretprobe_instance {
diff --git a/include/linux/leds-pm8xxx.h b/include/linux/leds-pm8xxx.h
index 18e6398..60755de 100644
--- a/include/linux/leds-pm8xxx.h
+++ b/include/linux/leds-pm8xxx.h
@@ -35,6 +35,9 @@
 	PM8XXX_ID_FLASH_LED_0,
 	PM8XXX_ID_FLASH_LED_1,
 	PM8XXX_ID_WLED,
+	PM8XXX_ID_RGB_LED_RED,
+	PM8XXX_ID_RGB_LED_GREEN,
+	PM8XXX_ID_RGB_LED_BLUE,
 	PM8XXX_ID_MAX,
 };
 
diff --git a/include/linux/libra_sdioif.h b/include/linux/libra_sdioif.h
index 965e2b5..99b7d04 100644
--- a/include/linux/libra_sdioif.h
+++ b/include/linux/libra_sdioif.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
@@ -34,7 +34,10 @@
 
 typedef int (suspend_handler_t)(struct sdio_func *);
 typedef void (resume_handler_t)(struct sdio_func *);
+typedef void (notify_card_removal_t)(void);
+typedef void (shutdown_handler_t)(void);
 
+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);
@@ -73,5 +76,8 @@
 int libra_enable_sdio_irq(struct sdio_func *func, u8 enable);
 void libra_sdio_disable_func(struct sdio_func *func);
 int libra_disable_sdio_irq_capability(struct sdio_func *func, u8 disable);
-
+int libra_sdio_notify_card_removal(
+		notify_card_removal_t *libra_sdio_notify_card_removal_hdlr);
+int libra_sdio_register_shutdown_hdlr(
+		shutdown_handler_t *libra_shutdown_hdlr);
 #endif /* __LIBRA_SDIOIF_H__ */
diff --git a/include/linux/log2.h b/include/linux/log2.h
index 25b8086..fd7ff3d 100644
--- a/include/linux/log2.h
+++ b/include/linux/log2.h
@@ -185,7 +185,6 @@
 #define rounddown_pow_of_two(n)			\
 (						\
 	__builtin_constant_p(n) ? (		\
-		(n == 1) ? 0 :			\
 		(1UL << ilog2(n))) :		\
 	__rounddown_pow_of_two(n)		\
  )
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 50940da..313a00e 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -119,6 +119,8 @@
 mem_cgroup_get_reclaim_stat_from_page(struct page *page);
 extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
 					struct task_struct *p);
+extern void mem_cgroup_replace_page_cache(struct page *oldpage,
+					struct page *newpage);
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 extern int do_swap_account;
@@ -370,6 +372,10 @@
 void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
 {
 }
+static inline void mem_cgroup_replace_page_cache(struct page *oldpage,
+				struct page *newpage)
+{
+}
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
diff --git a/include/linux/mfd/Kbuild b/include/linux/mfd/Kbuild
index 1acc78f..bba647c 100644
--- a/include/linux/mfd/Kbuild
+++ b/include/linux/mfd/Kbuild
@@ -1,3 +1,3 @@
 header-y += timpani-audio.h
 header-y += msm-adie-codec.h
-header-y += wcd9310/
+header-y += wcd9xxx/
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index e7bf820..b907219 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -42,6 +42,8 @@
 #define PM8XXX_REVISION_8901_1p1	2
 #define PM8XXX_REVISION_8901_2p0	3
 #define PM8XXX_REVISION_8901_2p1	4
+#define PM8XXX_REVISION_8901_2p2	5
+#define PM8XXX_REVISION_8901_2p3	6
 
 #define PM8XXX_REVISION_8921_TEST	0
 #define PM8XXX_REVISION_8921_1p0	1
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/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
index c90d8d1..77683ce 100644
--- a/include/linux/mfd/pm8xxx/misc.h
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -79,7 +79,7 @@
 };
 
 enum pm8xxx_aux_clk_div {
-	X0_DIV_NONE,
+	XO_DIV_NONE,
 	XO_DIV_1,
 	XO_DIV_2,
 	XO_DIV_4,
diff --git a/include/linux/mfd/pm8xxx/pm8018.h b/include/linux/mfd/pm8xxx/pm8018.h
index 20c9d26..daacdd4 100644
--- a/include/linux/mfd/pm8xxx/pm8018.h
+++ b/include/linux/mfd/pm8xxx/pm8018.h
@@ -23,6 +23,7 @@
 #include <linux/mfd/pm8xxx/gpio.h>
 #include <linux/mfd/pm8xxx/mpp.h>
 #include <linux/mfd/pm8xxx/rtc.h>
+#include <linux/mfd/pm8xxx/tm.h>
 #include <linux/input/pmic8xxx-pwrkey.h>
 #include <linux/mfd/pm8xxx/misc.h>
 #include <linux/regulator/pm8xxx-regulator.h>
@@ -57,6 +58,9 @@
 #define PM8018_ADC_BATT_TEMP_WARM_IRQ	PM8018_IRQ_BLOCK_BIT(9, 1)
 #define PM8018_ADC_BATT_TEMP_COLD_IRQ	PM8018_IRQ_BLOCK_BIT(9, 0)
 
+#define PM8018_OVERTEMP_IRQ		PM8018_IRQ_BLOCK_BIT(4, 2)
+#define PM8018_TEMPSTAT_IRQ		PM8018_IRQ_BLOCK_BIT(6, 7)
+
 #define PM8018_LVS1_OCP_IRQ		PM8921_IRQ_BLOCK_BIT(13, 0)
 
 struct pm8018_platform_data {
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 82db9a4..d4aaa4b 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.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,8 +20,8 @@
 #define FCC_CC_COLS		5
 #define FCC_TEMP_COLS		8
 
-#define PC_CC_ROWS		10
-#define PC_CC_COLS		5
+#define PC_CC_ROWS             29
+#define PC_CC_COLS             13
 
 #define PC_TEMP_ROWS		29
 #define PC_TEMP_COLS		8
@@ -35,19 +35,20 @@
 };
 
 /**
- * struct pc_sf_lut -
+ * struct sf_lut -
  * @rows:	number of percent charge entries should be <= PC_CC_ROWS
  * @cols:	number of charge cycle entries should be <= PC_CC_COLS
- * @cycles:	the charge cycles at which sf data is available in the table.
+ * @row_entries:	the charge cycles/temperature at which sf data
+ *			is available in the table.
  *		The charge cycles must be in increasing order from 0 to rows.
  * @percent:	the percent charge at which sf data is available in the table
  *		The  percentcharge must be in decreasing order from 0 to cols.
  * @sf:		the scaling factor data
  */
-struct pc_sf_lut {
+struct sf_lut {
 	int rows;
 	int cols;
-	int cycles[PC_CC_COLS];
+	int row_entries[PC_CC_COLS];
 	int percent[PC_CC_ROWS];
 	int sf[PC_CC_ROWS][PC_CC_COLS];
 };
@@ -74,17 +75,22 @@
  * struct pm8921_bms_battery_data -
  * @fcc:		full charge capacity (mAmpHour)
  * @fcc_temp_lut:	table to get fcc at a given temp
- * @fcc_sf_lut:		table to get fcc scaling factor for given charge cycles
  * @pc_temp_ocv_lut:	table to get percent charge given batt temp and cycles
  * @pc_sf_lut:		table to get percent charge scaling factor given cycles
  *			and percent charge
+ * @rbatt_sf_lut:	table to get battery resistance scaling factor given
+ *			temperature and percent charge
+ * default_rbatt_mohm:	the default value of battery resistance to use when
+ *			readings from bms are not available.
  */
 struct pm8921_bms_battery_data {
-	unsigned int			fcc;
-	struct single_row_lut		*fcc_temp_lut;
-	struct single_row_lut		*fcc_sf_lut;
-	struct pc_temp_ocv_lut		*pc_temp_ocv_lut;
-	struct pc_sf_lut		*pc_sf_lut;
+	unsigned int		fcc;
+	struct single_row_lut	*fcc_temp_lut;
+	struct single_row_lut	*fcc_sf_lut;
+	struct pc_temp_ocv_lut	*pc_temp_ocv_lut;
+	struct sf_lut		*pc_sf_lut;
+	struct sf_lut		*rbatt_sf_lut;
+	int			default_rbatt_mohm;
 };
 
 struct pm8xxx_bms_core_data {
@@ -95,8 +101,15 @@
 	unsigned int	batt_id_channel;
 };
 
+enum battery_type {
+	BATT_UNKNOWN = 0,
+	BATT_PALLADIUM,
+	BATT_DESAY,
+};
+
 /**
  * struct pm8921_bms_platform_data -
+ * @batt_type:		allows to force chose battery calibration data
  * @r_sense:		sense resistor value in (mOhms)
  * @i_test:		current at which the unusable charger cutoff is to be
  *			calculated or the peak system current (mA)
@@ -105,6 +118,7 @@
  */
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
+	enum battery_type		battery_type;
 	unsigned int			r_sense;
 	unsigned int			i_test;
 	unsigned int			v_failure;
@@ -114,6 +128,7 @@
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
 extern struct pm8921_bms_battery_data  palladium_1500_data;
+extern struct pm8921_bms_battery_data  desay_5200_data;
 /**
  * pm8921_bms_get_vsense_avg - return the voltage across the sense
  *				resitor in microvolts
@@ -166,6 +181,20 @@
  *				track of chargecycles
  */
 void pm8921_bms_charging_end(int is_battery_full);
+
+void pm8921_bms_calibrate_hkadc(void);
+/**
+ * pm8921_bms_get_simultaneous_battery_voltage_and_current
+ *		- function to take simultaneous vbat and vsense readings
+ *		  this puts the bms in override mode but keeps coulumb couting
+ *		  on. Useful when ir compensation needs to be implemented
+ */
+int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+								int *vbat_uv);
+/**
+ * pm8921_bms_get_rbatt - function to get the battery resistance in mOhm.
+ */
+int pm8921_bms_get_rbatt(void);
 #else
 static inline int pm8921_bms_get_vsense_avg(int *result)
 {
@@ -189,6 +218,18 @@
 static inline void pm8921_bms_charging_end(int is_battery_full)
 {
 }
+static inline void pm8921_bms_calibrate_hkadc(void)
+{
+}
+static inline int pm8921_bms_get_simultaneous_battery_voltage_and_current(
+						int *ibat_ua, int *vbat_uv)
+{
+	return -ENXIO;
+}
+static inline int pm8921_bms_get_rbatt(void)
+{
+	return -EINVAL;
+}
 #endif
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 31af535..2186903 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -48,6 +48,14 @@
 	PM_USB_DEBOUNCE_80P5MS,
 };
 
+enum pm8921_chg_led_src_config {
+	LED_SRC_GND,
+	LED_SRC_VPH_PWR,
+	LED_SRC_5V,
+	LED_SRC_MIN_VPH_5V,
+	LED_SRC_BYPASS,
+};
+
 /**
  * struct pm8921_charger_platform_data -
  * @safety_time:	max charging time in minutes incl. fast and trkl
@@ -100,6 +108,11 @@
  *			VBAT_THERM goes below 35% of VREF_THERM, if low the
  *			battery will be considered hot when VBAT_THERM goes
  *			below 25% of VREF_THERM. Hardware defaults to low.
+ * @rconn_mohm:		resistance in milliOhm from the vbat sense to ground
+ *			with the battery terminals shorted. This indicates
+ *			resistance of the pads, connectors, battery terminals
+ *			and rsense.
+ * @led_src_config:	Power source for anode of charger indicator LED.
  */
 struct pm8921_charger_platform_data {
 	struct pm8xxx_charger_core_data	charger_cdata;
@@ -131,6 +144,8 @@
 	int				thermal_levels;
 	enum pm8921_chg_cold_thr	cold_thr;
 	enum pm8921_chg_hot_thr		hot_thr;
+	int				rconn_mohm;
+	enum pm8921_chg_led_src_config	led_src_config;
 };
 
 enum pm8921_charger_source {
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 22293fe..bdaee74 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -142,6 +142,7 @@
 	struct pm8xxx_led_platform_data		*leds_pdata;
 	struct pm8xxx_vibrator_platform_data	*vibrator_pdata;
 	struct pm8xxx_ccadc_platform_data	*ccadc_pdata;
+	struct pm8xxx_pwm_platform_data		*pwm_pdata;
 };
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/pm8xxx-adc.h b/include/linux/mfd/pm8xxx/pm8xxx-adc.h
index a572ae3..d2b1cfc 100644
--- a/include/linux/mfd/pm8xxx/pm8xxx-adc.h
+++ b/include/linux/mfd/pm8xxx/pm8xxx-adc.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -75,7 +75,6 @@
 	ADC_MPP_1_ATEST_5,
 	ADC_MPP_1_ATEST_6,
 	ADC_MPP_1_ATEST_7,
-	ADC_MPP_1_CHANNEL_NONE,
 	ADC_MPP_2_ATEST_8 = 40,
 	ADC_MPP_2_USB_SNS_DIV20,
 	ADC_MPP_2_DCIN_SNS_DIV20,
@@ -92,7 +91,7 @@
 	ADC_MPP_2_ATEST_5,
 	ADC_MPP_2_ATEST_6,
 	ADC_MPP_2_ATEST_7,
-	ADC_MPP_2_CHANNEL_NONE,
+	ADC_CHANNEL_MAX_NUM,
 };
 
 #define PM8XXX_ADC_PMIC_0	0x0
diff --git a/include/linux/mfd/pm8xxx/pwm.h b/include/linux/mfd/pm8xxx/pwm.h
index 9169e90..09b165e 100644
--- a/include/linux/mfd/pm8xxx/pwm.h
+++ b/include/linux/mfd/pm8xxx/pwm.h
@@ -19,7 +19,6 @@
 
 #define PM8XXX_PWM_PERIOD_MIN	7 /* usec: 19.2M, n=6, m=0, pre=2 */
 #define PM8XXX_PWM_PERIOD_MAX	(384 * USEC_PER_SEC) /* 1K, n=9, m=7, pre=6 */
-
 #define PM_PWM_LUT_SIZE			64
 #define PM_PWM_LUT_DUTY_TIME_MAX	512	/* ms */
 #define PM_PWM_LUT_PAUSE_MAX		(7000 * PM_PWM_LUT_DUTY_TIME_MAX)
@@ -92,6 +91,14 @@
 };
 
 /**
+ * struct pm8xxx_pwm_platform_data - PWM platform data
+ * dtest_channel - Enable LPG DTEST mode for this LPG channel
+ */
+struct pm8xxx_pwm_platform_data {
+	int dtest_channel;
+};
+
+/**
  * pm8xxx_pwm_config_period - change PWM period
  *
  * @pwm: the PWM device
diff --git a/include/linux/mfd/pm8xxx/regulator.h b/include/linux/mfd/pm8xxx/regulator.h
index 9e0ce86..83492d2 100644
--- a/include/linux/mfd/pm8xxx/regulator.h
+++ b/include/linux/mfd/pm8xxx/regulator.h
@@ -30,6 +30,7 @@
  * %PM8XXX_REGULATOR_TYPE_VS:		voltage switch capable of sourcing 100mA
  * %PM8XXX_REGULATOR_TYPE_VS300:	voltage switch capable of sourcing 300mA
  * %PM8XXX_REGULATOR_TYPE_NCP:		negative charge pump
+ * %PM8XXX_REGULATOR_TYPE_BOOST:	boost regulator
  * %PM8XXX_REGULATOR_TYPE_MAX:		used internally for error checking; not
  *					a valid regulator type.
  *
@@ -44,6 +45,7 @@
 	PM8XXX_REGULATOR_TYPE_VS,
 	PM8XXX_REGULATOR_TYPE_VS300,
 	PM8XXX_REGULATOR_TYPE_NCP,
+	PM8XXX_REGULATOR_TYPE_BOOST,
 	PM8XXX_REGULATOR_TYPE_MAX,
 };
 
@@ -257,4 +259,13 @@
 		.prev_write_count = -1, \
 	}
 
+#define BOOST(_name, _ctrl_addr) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_BOOST, \
+		.ctrl_addr	= _ctrl_addr, \
+		.rdesc.name	= _name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
 #endif
diff --git a/include/linux/mfd/wcd9310/Kbuild b/include/linux/mfd/wcd9310/Kbuild
deleted file mode 100644
index 2702ec6..0000000
--- a/include/linux/mfd/wcd9310/Kbuild
+++ /dev/null
@@ -1 +0,0 @@
-header-y += registers.h
diff --git a/include/linux/mfd/wcd9310/core.h b/include/linux/mfd/wcd9310/core.h
deleted file mode 100644
index 8605ac6..0000000
--- a/include/linux/mfd/wcd9310/core.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* 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
- * 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 __MFD_TABLA_CORE_H__
-#define __MFD_TABLA_CORE_H__
-
-#include <linux/interrupt.h>
-#include <linux/wakelock.h>
-
-#define TABLA_NUM_IRQ_REGS 3
-
-#define TABLA_SLIM_NUM_PORT_REG 3
-
-#define TABLA_INTERFACE_TYPE_SLIMBUS	0x00
-#define TABLA_INTERFACE_TYPE_I2C	0x01
-
-#define TABLA_VERSION_1_0	0
-#define TABLA_VERSION_1_1	1
-#define TABLA_VERSION_2_0	2
-#define TABLA_IS_1_X(ver) \
-	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
-#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
-
-enum {
-	TABLA_IRQ_SLIMBUS = 0,
-	TABLA_IRQ_MBHC_REMOVAL,
-	TABLA_IRQ_MBHC_SHORT_TERM,
-	TABLA_IRQ_MBHC_PRESS,
-	TABLA_IRQ_MBHC_RELEASE,
-	TABLA_IRQ_MBHC_POTENTIAL,
-	TABLA_IRQ_MBHC_INSERTION,
-	TABLA_IRQ_BG_PRECHARGE,
-	TABLA_IRQ_PA1_STARTUP,
-	TABLA_IRQ_PA2_STARTUP,
-	TABLA_IRQ_PA3_STARTUP,
-	TABLA_IRQ_PA4_STARTUP,
-	TABLA_IRQ_PA5_STARTUP,
-	TABLA_IRQ_MICBIAS1_PRECHARGE,
-	TABLA_IRQ_MICBIAS2_PRECHARGE,
-	TABLA_IRQ_MICBIAS3_PRECHARGE,
-	TABLA_IRQ_HPH_PA_OCPL_FAULT,
-	TABLA_IRQ_HPH_PA_OCPR_FAULT,
-	TABLA_IRQ_EAR_PA_OCPL_FAULT,
-	TABLA_IRQ_HPH_L_PA_STARTUP,
-	TABLA_IRQ_HPH_R_PA_STARTUP,
-	TABLA_IRQ_EAR_PA_STARTUP,
-	TABLA_NUM_IRQS,
-};
-
-enum tabla_pm_state {
-	TABLA_PM_SLEEPABLE,
-	TABLA_PM_AWAKE,
-	TABLA_PM_ASLEEP,
-};
-
-struct tabla {
-	struct device *dev;
-	struct slim_device *slim;
-	struct slim_device *slim_slave;
-	struct mutex io_lock;
-	struct mutex xfer_lock;
-	struct mutex irq_lock;
-	u8 version;
-
-	unsigned int irq_base;
-	unsigned int irq;
-	u8 irq_masks_cur[TABLA_NUM_IRQ_REGS];
-	u8 irq_masks_cache[TABLA_NUM_IRQ_REGS];
-	u8 irq_level[TABLA_NUM_IRQ_REGS];
-
-	int reset_gpio;
-
-	int (*read_dev)(struct tabla *tabla, unsigned short reg,
-			int bytes, void *dest, bool interface_reg);
-	int (*write_dev)(struct tabla *tabla, unsigned short reg,
-			 int bytes, void *src, bool interface_reg);
-
-	struct regulator_bulk_data *supplies;
-
-	enum tabla_pm_state pm_state;
-	struct mutex pm_lock;
-	/* pm_wq notifies change of pm_state */
-	wait_queue_head_t pm_wq;
-	struct wake_lock wlock;
-	int wlock_holders;
-};
-
-int tabla_reg_read(struct tabla *tabla, unsigned short reg);
-int tabla_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
-int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg);
-int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
-int tabla_bulk_read(struct tabla *tabla, unsigned short reg, int count,
-		    u8 *buf);
-int tabla_bulk_write(struct tabla *tabla, unsigned short reg, int count,
-		     u8 *buf);
-int tabla_irq_init(struct tabla *tabla);
-void tabla_irq_exit(struct tabla *tabla);
-int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-int tabla_get_intf_type(void);
-
-void tabla_lock_sleep(struct tabla *tabla);
-void tabla_unlock_sleep(struct tabla *tabla);
-enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
-				     enum tabla_pm_state n);
-
-static inline int tabla_request_irq(struct tabla *tabla, int irq,
-				     irq_handler_t handler, const char *name,
-				     void *data)
-{
-	if (!tabla->irq_base)
-		return -EINVAL;
-	return request_threaded_irq(tabla->irq_base + irq, NULL, handler,
-				    IRQF_TRIGGER_RISING, name,
-				    data);
-}
-static inline void tabla_free_irq(struct tabla *tabla, int irq, void *data)
-{
-	if (!tabla->irq_base)
-		return;
-	free_irq(tabla->irq_base + irq, data);
-}
-static inline void tabla_enable_irq(struct tabla *tabla, int irq)
-{
-	if (!tabla->irq_base)
-		return;
-	enable_irq(tabla->irq_base + irq);
-}
-static inline void tabla_disable_irq(struct tabla *tabla, int irq)
-{
-	if (!tabla->irq_base)
-		return;
-	disable_irq_nosync(tabla->irq_base + irq);
-}
-
-#endif
diff --git a/include/linux/mfd/wcd9xxx/Kbuild b/include/linux/mfd/wcd9xxx/Kbuild
new file mode 100644
index 0000000..acfab6e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/Kbuild
@@ -0,0 +1,2 @@
+header-y += wcd9xxx_registers.h
+header-y += wcd9310_registers.h
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
new file mode 100644
index 0000000..fca9a94
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -0,0 +1,184 @@
+/* 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
+ * 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 __MFD_TABLA_CORE_H__
+#define __MFD_TABLA_CORE_H__
+
+#include <linux/interrupt.h>
+#include <linux/wakelock.h>
+
+#define WCD9XXX_NUM_IRQ_REGS 3
+
+#define WCD9XXX_SLIM_NUM_PORT_REG 3
+
+#define WCD9XXX_INTERFACE_TYPE_SLIMBUS	0x00
+#define WCD9XXX_INTERFACE_TYPE_I2C	0x01
+
+#define TABLA_VERSION_1_0	0
+#define TABLA_VERSION_1_1	1
+#define TABLA_VERSION_2_0	2
+#define TABLA_IS_1_X(ver) \
+	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
+#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
+
+enum {
+	TABLA_IRQ_SLIMBUS = 0,
+	TABLA_IRQ_MBHC_REMOVAL,
+	TABLA_IRQ_MBHC_SHORT_TERM,
+	TABLA_IRQ_MBHC_PRESS,
+	TABLA_IRQ_MBHC_RELEASE,
+	TABLA_IRQ_MBHC_POTENTIAL,
+	TABLA_IRQ_MBHC_INSERTION,
+	TABLA_IRQ_BG_PRECHARGE,
+	TABLA_IRQ_PA1_STARTUP,
+	TABLA_IRQ_PA2_STARTUP,
+	TABLA_IRQ_PA3_STARTUP,
+	TABLA_IRQ_PA4_STARTUP,
+	TABLA_IRQ_PA5_STARTUP,
+	TABLA_IRQ_MICBIAS1_PRECHARGE,
+	TABLA_IRQ_MICBIAS2_PRECHARGE,
+	TABLA_IRQ_MICBIAS3_PRECHARGE,
+	TABLA_IRQ_HPH_PA_OCPL_FAULT,
+	TABLA_IRQ_HPH_PA_OCPR_FAULT,
+	TABLA_IRQ_EAR_PA_OCPL_FAULT,
+	TABLA_IRQ_HPH_L_PA_STARTUP,
+	TABLA_IRQ_HPH_R_PA_STARTUP,
+	TABLA_IRQ_EAR_PA_STARTUP,
+	TABLA_NUM_IRQS,
+};
+
+enum {
+	SITAR_IRQ_SLIMBUS = 0,
+	SITAR_IRQ_MBHC_REMOVAL,
+	SITAR_IRQ_MBHC_SHORT_TERM,
+	SITAR_IRQ_MBHC_PRESS,
+	SITAR_IRQ_MBHC_RELEASE,
+	SITAR_IRQ_MBHC_POTENTIAL,
+	SITAR_IRQ_MBHC_INSERTION,
+	SITAR_IRQ_BG_PRECHARGE,
+	SITAR_IRQ_PA1_STARTUP,
+	SITAR_IRQ_PA2_STARTUP,
+	SITAR_IRQ_PA3_STARTUP,
+	SITAR_IRQ_PA4_STARTUP,
+	SITAR_IRQ_PA5_STARTUP,
+	SITAR_IRQ_MICBIAS1_PRECHARGE,
+	SITAR_IRQ_MICBIAS2_PRECHARGE,
+	SITAR_IRQ_MICBIAS3_PRECHARGE,
+	SITAR_IRQ_HPH_PA_OCPL_FAULT,
+	SITAR_IRQ_HPH_PA_OCPR_FAULT,
+	SITAR_IRQ_EAR_PA_OCPL_FAULT,
+	SITAR_IRQ_HPH_L_PA_STARTUP,
+	SITAR_IRQ_HPH_R_PA_STARTUP,
+	SITAR_IRQ_EAR_PA_STARTUP,
+	SITAR_NUM_IRQS,
+};
+
+
+enum wcd9xxx_pm_state {
+	WCD9XXX_PM_SLEEPABLE,
+	WCD9XXX_PM_AWAKE,
+	WCD9XXX_PM_ASLEEP,
+};
+
+struct wcd9xxx {
+	struct device *dev;
+	struct slim_device *slim;
+	struct slim_device *slim_slave;
+	struct mutex io_lock;
+	struct mutex xfer_lock;
+	struct mutex irq_lock;
+	u8 version;
+
+	unsigned int irq_base;
+	unsigned int irq;
+	u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
+	u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
+	u8 irq_level[WCD9XXX_NUM_IRQ_REGS];
+
+	int reset_gpio;
+
+	int (*read_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *dest, bool interface_reg);
+	int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			 int bytes, void *src, bool interface_reg);
+
+	struct regulator_bulk_data *supplies;
+
+	enum wcd9xxx_pm_state pm_state;
+	struct mutex pm_lock;
+	/* pm_wq notifies change of pm_state */
+	wait_queue_head_t pm_wq;
+	struct wake_lock wlock;
+	int wlock_holders;
+
+	int num_rx_port;
+	int num_tx_port;
+};
+
+int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
+int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		u8 val);
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		u8 val);
+int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int count, u8 *buf);
+int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int count, u8 *buf);
+int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
+int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
+int wcd9xxx_get_intf_type(void);
+
+bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
+				enum wcd9xxx_pm_state o,
+				enum wcd9xxx_pm_state n);
+
+static inline int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
+				     irq_handler_t handler, const char *name,
+				     void *data)
+{
+	if (!wcd9xxx->irq_base)
+		return -EINVAL;
+	return request_threaded_irq(wcd9xxx->irq_base + irq, NULL, handler,
+				    IRQF_TRIGGER_RISING, name,
+				    data);
+}
+static inline void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx,
+				int irq, void *data)
+{
+	if (!wcd9xxx->irq_base)
+		return;
+	free_irq(wcd9xxx->irq_base + irq, data);
+}
+static inline void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+	if (!wcd9xxx->irq_base)
+		return;
+	enable_irq(wcd9xxx->irq_base + irq);
+}
+static inline void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+	if (!wcd9xxx->irq_base)
+		return;
+	disable_irq_nosync(wcd9xxx->irq_base + irq);
+}
+static inline void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
+{
+	if (!wcd9xxx->irq_base)
+		return;
+	disable_irq(wcd9xxx->irq_base + irq);
+}
+
+#endif
diff --git a/include/linux/mfd/wcd9310/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
similarity index 71%
rename from include/linux/mfd/wcd9310/pdata.h
rename to include/linux/mfd/wcd9xxx/pdata.h
index af801f0..db76294 100644
--- a/include/linux/mfd/wcd9310/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.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
@@ -16,6 +16,15 @@
 
 #include <linux/slimbus/slimbus.h>
 
+#define SITAR_LDOH_1P95_V 0x0
+#define SITAR_LDOH_2P35_V 0x1
+#define SITAR_LDOH_2P75_V 0x2
+#define SITAR_LDOH_2P85_V 0x3
+
+#define SITAR_CFILT1_SEL 0x0
+#define SITAR_CFILT2_SEL 0x1
+#define SITAR_CFILT3_SEL 0x2
+
 #define TABLA_LDOH_1P95_V 0x0
 #define TABLA_LDOH_2P35_V 0x1
 #define TABLA_LDOH_2P75_V 0x2
@@ -51,7 +60,7 @@
 #define TABLA_DCYCLE_3839 0xE
 #define TABLA_DCYCLE_4095 0xF
 
-struct tabla_amic {
+struct wcd9xxx_amic {
 	/*legacy mode, txfe_enable and txfe_buff take 7 input
 	 * each bit represent the channel / TXFE number
 	 * and numbered as below
@@ -75,7 +84,7 @@
  * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
  */
 
-struct tabla_micbias_setting {
+struct wcd9xxx_micbias_setting {
 	u8 ldoh_v;
 	u32 cfilt1_mv; /* in mv */
 	u32 cfilt2_mv; /* in mv */
@@ -86,7 +95,7 @@
 	u8 bias4_cfilt_sel;
 };
 
-struct tabla_ocp_setting {
+struct wcd9xxx_ocp_setting {
 	unsigned int	use_pdata:1; /* 0 - use sys default as recommended */
 	unsigned int	num_attempts:4; /* up to 15 attempts */
 	unsigned int	run_time:4; /* in duty cycle */
@@ -94,15 +103,39 @@
 	unsigned int	hph_ocp_limit:3; /* Headphone OCP current limit */
 };
 
-struct tabla_pdata {
+#define MAX_REGULATOR	6
+/*
+ *      format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
+ *
+ *      <POWER_SUPPLY_PIN_NAME> from Tabla objective spec
+*/
+
+#define  WCD9XXX_CDC_VDDA_CP_CUR_MAX      500000
+#define  WCD9XXX_CDC_VDDA_RX_CUR_MAX      20000
+#define  WCD9XXX_CDC_VDDA_TX_CUR_MAX      20000
+#define  WCD9XXX_VDDIO_CDC_CUR_MAX        5000
+
+#define  WCD9XXX_VDDD_CDC_D_CUR_MAX       5000
+#define  WCD9XXX_VDDD_CDC_A_CUR_MAX       5000
+
+struct wcd9xxx_regulator {
+	const char *name;
+	int min_uV;
+	int max_uV;
+	int optimum_uA;
+	struct regulator *regulator;
+};
+
+struct wcd9xxx_pdata {
 	int irq;
 	int irq_base;
 	int num_irqs;
 	int reset_gpio;
-	struct tabla_amic amic_settings;
+	struct wcd9xxx_amic amic_settings;
 	struct slim_device slimbus_slave_device;
-	struct tabla_micbias_setting micbias;
-	struct tabla_ocp_setting ocp;
+	struct wcd9xxx_micbias_setting micbias;
+	struct wcd9xxx_ocp_setting ocp;
+	struct wcd9xxx_regulator regulator[MAX_REGULATOR];
 };
 
 #endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
new file mode 100644
index 0000000..df54e02
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
@@ -0,0 +1,742 @@
+/* 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 SITAR_CODEC_DIGITAL_H
+#define SITAR_CODEC_DIGITAL_H
+
+#define SITAR_A_PIN_CTL_OE0			(0x10)
+#define SITAR_A_PIN_CTL_OE0__POR			(0x00000000)
+#define SITAR_A_PIN_CTL_OE1			(0x11)
+#define SITAR_A_PIN_CTL_OE1__POR			(0x00000000)
+#define SITAR_A_PIN_CTL_DATA0			(0x12)
+#define SITAR_A_PIN_CTL_DATA0__POR			(0x00000000)
+#define SITAR_A_PIN_CTL_DATA1			(0x13)
+#define SITAR_A_PIN_CTL_DATA1__POR			(0x00000000)
+#define SITAR_A_HDRIVE_GENERIC			(0x18)
+#define SITAR_A_HDRIVE_GENERIC__POR			(0x00000000)
+#define SITAR_A_HDRIVE_OVERRIDE			(0x19)
+#define SITAR_A_HDRIVE_OVERRIDE__POR			(0x00000008)
+#define SITAR_A_ANA_CSR_WAIT_STATE			(0x20)
+#define SITAR_A_ANA_CSR_WAIT_STATE__POR			(0x00000044)
+#define SITAR_A_PROCESS_MONITOR_CTL0			(0x40)
+#define SITAR_A_PROCESS_MONITOR_CTL0__POR			(0x00000080)
+#define SITAR_A_PROCESS_MONITOR_CTL1			(0x41)
+#define SITAR_A_PROCESS_MONITOR_CTL1__POR			(0x00000000)
+#define SITAR_A_PROCESS_MONITOR_CTL2			(0x42)
+#define SITAR_A_PROCESS_MONITOR_CTL2__POR			(0x00000000)
+#define SITAR_A_PROCESS_MONITOR_CTL3			(0x43)
+#define SITAR_A_PROCESS_MONITOR_CTL3__POR			(0x00000001)
+#define SITAR_A_QFUSE_CTL			(0x48)
+#define SITAR_A_QFUSE_CTL__POR			(0x00000000)
+#define SITAR_A_QFUSE_STATUS			(0x49)
+#define SITAR_A_QFUSE_STATUS__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT0			(0x4A)
+#define SITAR_A_QFUSE_DATA_OUT0__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT1			(0x4B)
+#define SITAR_A_QFUSE_DATA_OUT1__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT2			(0x4C)
+#define SITAR_A_QFUSE_DATA_OUT2__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT3			(0x4D)
+#define SITAR_A_QFUSE_DATA_OUT3__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT4			(0x4E)
+#define SITAR_A_QFUSE_DATA_OUT4__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT5			(0x4F)
+#define SITAR_A_QFUSE_DATA_OUT5__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT6			(0x50)
+#define SITAR_A_QFUSE_DATA_OUT6__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT7			(0x51)
+#define SITAR_A_QFUSE_DATA_OUT7__POR			(0x00000000)
+#define SITAR_A_CDC_CTL			(0x80)
+#define SITAR_A_CDC_CTL__POR			(0x00000000)
+#define SITAR_A_LEAKAGE_CTL			(0x88)
+#define SITAR_A_LEAKAGE_CTL__POR			(0x00000004)
+#define SITAR_A_INTR_MODE			(0x90)
+#define SITAR_A_INTR_MODE__POR			(0x00000000)
+#define SITAR_A_INTR_MASK0			(0x94)
+#define SITAR_A_INTR_MASK0__POR			(0x000000ff)
+#define SITAR_A_INTR_MASK1			(0x95)
+#define SITAR_A_INTR_MASK1__POR			(0x000000ff)
+#define SITAR_A_INTR_MASK2			(0x96)
+#define SITAR_A_INTR_MASK2__POR			(0x000000ff)
+#define SITAR_A_INTR_STATUS0			(0x98)
+#define SITAR_A_INTR_STATUS0__POR			(0x00000000)
+#define SITAR_A_INTR_STATUS1			(0x99)
+#define SITAR_A_INTR_STATUS1__POR			(0x00000000)
+#define SITAR_A_INTR_STATUS2			(0x9A)
+#define SITAR_A_INTR_STATUS2__POR			(0x00000000)
+#define SITAR_A_INTR_CLEAR0			(0x9C)
+#define SITAR_A_INTR_CLEAR0__POR			(0x00000000)
+#define SITAR_A_INTR_CLEAR1			(0x9D)
+#define SITAR_A_INTR_CLEAR1__POR			(0x00000000)
+#define SITAR_A_INTR_CLEAR2			(0x9E)
+#define SITAR_A_INTR_CLEAR2__POR			(0x00000000)
+#define SITAR_A_INTR_LEVEL0			(0xA0)
+#define SITAR_A_INTR_LEVEL0__POR			(0x00000001)
+#define SITAR_A_INTR_LEVEL1			(0xA1)
+#define SITAR_A_INTR_LEVEL1__POR			(0x00000000)
+#define SITAR_A_INTR_LEVEL2			(0xA2)
+#define SITAR_A_INTR_LEVEL2__POR			(0x00000000)
+#define SITAR_A_INTR_TEST0			(0xA4)
+#define SITAR_A_INTR_TEST0__POR			(0x00000000)
+#define SITAR_A_INTR_TEST1			(0xA5)
+#define SITAR_A_INTR_TEST1__POR			(0x00000000)
+#define SITAR_A_INTR_TEST2			(0xA6)
+#define SITAR_A_INTR_TEST2__POR			(0x00000000)
+#define SITAR_A_INTR_SET0			(0xA8)
+#define SITAR_A_INTR_SET0__POR			(0x00000000)
+#define SITAR_A_INTR_SET1			(0xA9)
+#define SITAR_A_INTR_SET1__POR			(0x00000000)
+#define SITAR_A_INTR_SET2			(0xAA)
+#define SITAR_A_INTR_SET2__POR			(0x00000000)
+#define SITAR_A_CDC_TX_I2S_SCK_MODE			(0xC0)
+#define SITAR_A_CDC_TX_I2S_SCK_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_TX_I2S_WS_MODE			(0xC1)
+#define SITAR_A_CDC_TX_I2S_WS_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_DATA0_MODE			(0xC4)
+#define SITAR_A_CDC_DMIC_DATA0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_CLK0_MODE			(0xC5)
+#define SITAR_A_CDC_DMIC_CLK0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_DATA1_MODE			(0xC6)
+#define SITAR_A_CDC_DMIC_DATA1_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_CLK1_MODE			(0xC7)
+#define SITAR_A_CDC_DMIC_CLK1_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_TX_I2S_SD0_MODE			(0xC8)
+#define SITAR_A_CDC_TX_I2S_SD0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_INTR_MODE			(0xC9)
+#define SITAR_A_CDC_INTR_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_RX_I2S_SD0_MODE			(0xCA)
+#define SITAR_A_CDC_RX_I2S_SD0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_RX_I2S_SD1_MODE			(0xCB)
+#define SITAR_A_CDC_RX_I2S_SD1_MODE__POR			(0x00000000)
+#define SITAR_A_BIAS_REF_CTL			(0x100)
+#define SITAR_A_BIAS_REF_CTL__POR			(0x0000001c)
+#define SITAR_A_BIAS_CENTRAL_BG_CTL			(0x101)
+#define SITAR_A_BIAS_CENTRAL_BG_CTL__POR			(0x00000050)
+#define SITAR_A_BIAS_PRECHRG_CTL			(0x102)
+#define SITAR_A_BIAS_PRECHRG_CTL__POR			(0x00000007)
+#define SITAR_A_BIAS_CURR_CTL_1			(0x103)
+#define SITAR_A_BIAS_CURR_CTL_1__POR			(0x00000052)
+#define SITAR_A_BIAS_CURR_CTL_2			(0x104)
+#define SITAR_A_BIAS_CURR_CTL_2__POR			(0x00000000)
+#define SITAR_A_BIAS_OSC_BG_CTL			(0x105)
+#define SITAR_A_BIAS_OSC_BG_CTL__POR			(0x00000016)
+#define SITAR_A_CLK_BUFF_EN1			(0x108)
+#define SITAR_A_CLK_BUFF_EN1__POR			(0x00000004)
+#define SITAR_A_CLK_BUFF_EN2			(0x109)
+#define SITAR_A_CLK_BUFF_EN2__POR			(0x00000002)
+#define SITAR_A_LDO_H_MODE_1			(0x110)
+#define SITAR_A_LDO_H_MODE_1__POR			(0x00000065)
+#define SITAR_A_LDO_H_MODE_2			(0x111)
+#define SITAR_A_LDO_H_MODE_2__POR			(0x000000a8)
+#define SITAR_A_LDO_H_LOOP_CTL			(0x112)
+#define SITAR_A_LDO_H_LOOP_CTL__POR			(0x0000006b)
+#define SITAR_A_LDO_H_COMP_1			(0x113)
+#define SITAR_A_LDO_H_COMP_1__POR			(0x00000084)
+#define SITAR_A_LDO_H_COMP_2			(0x114)
+#define SITAR_A_LDO_H_COMP_2__POR			(0x000000e0)
+#define SITAR_A_LDO_H_BIAS_1			(0x115)
+#define SITAR_A_LDO_H_BIAS_1__POR			(0x0000006d)
+#define SITAR_A_LDO_H_BIAS_2			(0x116)
+#define SITAR_A_LDO_H_BIAS_2__POR			(0x000000a5)
+#define SITAR_A_LDO_H_BIAS_3			(0x117)
+#define SITAR_A_LDO_H_BIAS_3__POR			(0x00000060)
+#define SITAR_A_MICB_CFILT_1_CTL			(0x128)
+#define SITAR_A_MICB_CFILT_1_CTL__POR			(0x00000040)
+#define SITAR_A_MICB_CFILT_1_VAL			(0x129)
+#define SITAR_A_MICB_CFILT_1_VAL__POR			(0x00000080)
+#define SITAR_A_MICB_CFILT_1_PRECHRG			(0x12A)
+#define SITAR_A_MICB_CFILT_1_PRECHRG__POR			(0x00000038)
+#define SITAR_A_MICB_1_CTL			(0x12B)
+#define SITAR_A_MICB_1_CTL__POR			(0x00000016)
+#define SITAR_A_MICB_1_INT_RBIAS			(0x12C)
+#define SITAR_A_MICB_1_INT_RBIAS__POR			(0x00000024)
+#define SITAR_A_MICB_1_MBHC			(0x12D)
+#define SITAR_A_MICB_1_MBHC__POR			(0x00000001)
+#define SITAR_A_MICB_CFILT_2_CTL			(0x12E)
+#define SITAR_A_MICB_CFILT_2_CTL__POR			(0x00000040)
+#define SITAR_A_MICB_CFILT_2_VAL			(0x12F)
+#define SITAR_A_MICB_CFILT_2_VAL__POR			(0x00000080)
+#define SITAR_A_MICB_CFILT_2_PRECHRG			(0x130)
+#define SITAR_A_MICB_CFILT_2_PRECHRG__POR			(0x00000038)
+#define SITAR_A_MICB_2_CTL			(0x131)
+#define SITAR_A_MICB_2_CTL__POR			(0x00000016)
+#define SITAR_A_MICB_2_INT_RBIAS			(0x132)
+#define SITAR_A_MICB_2_INT_RBIAS__POR			(0x00000024)
+#define SITAR_A_MICB_2_MBHC			(0x133)
+#define SITAR_A_MICB_2_MBHC__POR			(0x00000002)
+#define SITAR_A_TX_COM_BIAS			(0x14C)
+#define SITAR_A_TX_COM_BIAS__POR			(0x000000e0)
+#define SITAR_A_MBHC_SCALING_MUX_1			(0x14E)
+#define SITAR_A_MBHC_SCALING_MUX_1__POR			(0x00000000)
+#define SITAR_A_MBHC_SCALING_MUX_2			(0x14F)
+#define SITAR_A_MBHC_SCALING_MUX_2__POR			(0x00000080)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_1			(0x151)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_1__POR			(0x00000000)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_2			(0x152)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_2__POR			(0x00000080)
+#define SITAR_A_TX_1_2_EN			(0x153)
+#define SITAR_A_TX_1_2_EN__POR			(0x00000000)
+#define SITAR_A_TX_1_2_TEST_EN			(0x154)
+#define SITAR_A_TX_1_2_TEST_EN__POR			(0x000000cc)
+#define SITAR_A_TX_1_2_ADC_CH1			(0x155)
+#define SITAR_A_TX_1_2_ADC_CH1__POR			(0x00000044)
+#define SITAR_A_TX_1_2_ADC_CH2			(0x156)
+#define SITAR_A_TX_1_2_ADC_CH2__POR			(0x00000044)
+#define SITAR_A_TX_1_2_ATEST_REFCTRL			(0x157)
+#define SITAR_A_TX_1_2_ATEST_REFCTRL__POR			(0x00000000)
+#define SITAR_A_TX_1_2_TEST_CTL			(0x158)
+#define SITAR_A_TX_1_2_TEST_CTL__POR			(0x00000038)
+#define SITAR_A_TX_1_2_TEST_BLOCK_EN			(0x159)
+#define SITAR_A_TX_1_2_TEST_BLOCK_EN__POR			(0x000000fc)
+#define SITAR_A_TX_1_2_TXFE_CLKDIV			(0x15A)
+#define SITAR_A_TX_1_2_TXFE_CLKDIV__POR			(0x000000ee)
+#define SITAR_A_TX_1_2_SAR_ERR_CH1			(0x15B)
+#define SITAR_A_TX_1_2_SAR_ERR_CH1__POR			(0x00000000)
+#define SITAR_A_TX_1_2_SAR_ERR_CH2			(0x15C)
+#define SITAR_A_TX_1_2_SAR_ERR_CH2__POR			(0x00000000)
+#define SITAR_A_TX_3_EN			(0x15D)
+#define SITAR_A_TX_3_EN__POR			(0x00000000)
+#define SITAR_A_TX_3_TEST_EN			(0x15E)
+#define SITAR_A_TX_3_TEST_EN__POR			(0x000000cc)
+#define SITAR_A_TX_3_ADC			(0x15F)
+#define SITAR_A_TX_3_ADC__POR			(0x00000044)
+#define SITAR_A_TX_3_MBHC_ATEST_REFCTRL			(0x161)
+#define SITAR_A_TX_3_MBHC_ATEST_REFCTRL__POR			(0x00000000)
+#define SITAR_A_TX_3_TEST_CTL			(0x162)
+#define SITAR_A_TX_3_TEST_CTL__POR			(0x00000038)
+#define SITAR_A_TX_3_TEST_BLOCK_EN			(0x163)
+#define SITAR_A_TX_3_TEST_BLOCK_EN__POR			(0x000000fc)
+#define SITAR_A_TX_3_TXFE_CKDIV			(0x164)
+#define SITAR_A_TX_3_TXFE_CKDIV__POR			(0x000000ee)
+#define SITAR_A_TX_3_SAR_ERR			(0x165)
+#define SITAR_A_TX_3_SAR_ERR__POR			(0x00000000)
+#define SITAR_A_TX_4_MBHC_EN			(0x171)
+#define SITAR_A_TX_4_MBHC_EN__POR			(0x0000000c)
+#define SITAR_A_TX_4_MBHC_ADC			(0x173)
+#define SITAR_A_TX_4_MBHC_ADC__POR			(0x00000044)
+#define SITAR_A_TX_4_MBHC_TEST_CTL			(0x174)
+#define SITAR_A_TX_4_MBHC_TEST_CTL__POR			(0x00000038)
+#define SITAR_A_TX_4_MBHC_SAR_ERR			(0x175)
+#define SITAR_A_TX_4_MBHC_SAR_ERR__POR			(0x00000000)
+#define SITAR_A_TX_4_TXFE_CLKDIV			(0x176)
+#define SITAR_A_TX_4_TXFE_CLKDIV__POR			(0x0000001c)
+#define SITAR_A_AUX_COM_CTL			(0x180)
+#define SITAR_A_AUX_COM_CTL__POR			(0x00000034)
+#define SITAR_A_AUX_COM_ATEST			(0x181)
+#define SITAR_A_AUX_COM_ATEST__POR			(0x00000000)
+#define SITAR_A_AUX_L_EN			(0x182)
+#define SITAR_A_AUX_L_EN__POR			(0x00000000)
+#define SITAR_A_AUX_L_GAIN			(0x183)
+#define SITAR_A_AUX_L_GAIN__POR			(0x0000001f)
+#define SITAR_A_AUX_L_PA_CONN			(0x184)
+#define SITAR_A_AUX_L_PA_CONN__POR			(0x00000000)
+#define SITAR_A_AUX_L_PA_CONN_INV			(0x185)
+#define SITAR_A_AUX_L_PA_CONN_INV__POR			(0x00000000)
+#define SITAR_A_AUX_R_EN			(0x186)
+#define SITAR_A_AUX_R_EN__POR			(0x00000000)
+#define SITAR_A_AUX_R_GAIN			(0x187)
+#define SITAR_A_AUX_R_GAIN__POR			(0x0000001f)
+#define SITAR_A_AUX_R_PA_CONN			(0x188)
+#define SITAR_A_AUX_R_PA_CONN__POR			(0x00000000)
+#define SITAR_A_AUX_R_PA_CONN_INV			(0x189)
+#define SITAR_A_AUX_R_PA_CONN_INV__POR			(0x00000000)
+#define SITAR_A_CP_EN			(0x192)
+#define SITAR_A_CP_EN__POR			(0x000000e6)
+#define SITAR_A_CP_CLK			(0x193)
+#define SITAR_A_CP_CLK__POR			(0x00000029)
+#define SITAR_A_CP_STATIC			(0x194)
+#define SITAR_A_CP_STATIC__POR			(0x00000010)
+#define SITAR_A_CP_DCC1			(0x195)
+#define SITAR_A_CP_DCC1__POR			(0x00000052)
+#define SITAR_A_CP_DCC3			(0x196)
+#define SITAR_A_CP_DCC3__POR			(0x00000001)
+#define SITAR_A_CP_ATEST			(0x197)
+#define SITAR_A_CP_ATEST__POR			(0x00000000)
+#define SITAR_A_CP_DTEST			(0x198)
+#define SITAR_A_CP_DTEST__POR			(0x00000000)
+#define SITAR_A_RX_COM_TIMER_DIV			(0x19E)
+#define SITAR_A_RX_COM_TIMER_DIV__POR			(0x000000e8)
+#define SITAR_A_RX_COM_OCP_CTL			(0x19F)
+#define SITAR_A_RX_COM_OCP_CTL__POR			(0x0000001f)
+#define SITAR_A_RX_COM_OCP_COUNT			(0x1A0)
+#define SITAR_A_RX_COM_OCP_COUNT__POR			(0x00000077)
+#define SITAR_A_RX_COM_DAC_CTL			(0x1A1)
+#define SITAR_A_RX_COM_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_COM_BIAS			(0x1A2)
+#define SITAR_A_RX_COM_BIAS__POR			(0x00000000)
+#define SITAR_A_RX_HPH_BIAS_PA			(0x1A6)
+#define SITAR_A_RX_HPH_BIAS_PA__POR			(0x00000057)
+#define SITAR_A_RX_HPH_BIAS_LDO			(0x1A7)
+#define SITAR_A_RX_HPH_BIAS_LDO__POR			(0x00000056)
+#define SITAR_A_RX_HPH_BIAS_CNP			(0x1A8)
+#define SITAR_A_RX_HPH_BIAS_CNP__POR			(0x0000008a)
+#define SITAR_A_RX_HPH_BIAS_WG			(0x1A9)
+#define SITAR_A_RX_HPH_BIAS_WG__POR			(0x00000060)
+#define SITAR_A_RX_HPH_OCP_CTL			(0x1AA)
+#define SITAR_A_RX_HPH_OCP_CTL__POR			(0x000000e8)
+#define SITAR_A_RX_HPH_CNP_EN			(0x1AB)
+#define SITAR_A_RX_HPH_CNP_EN__POR			(0x00000080)
+#define SITAR_A_RX_HPH_CNP_WG_CTL			(0x1AC)
+#define SITAR_A_RX_HPH_CNP_WG_CTL__POR			(0x000000dc)
+#define SITAR_A_RX_HPH_CNP_WG_TIME			(0x1AD)
+#define SITAR_A_RX_HPH_CNP_WG_TIME__POR			(0x00000028)
+#define SITAR_A_RX_HPH_L_GAIN			(0x1AE)
+#define SITAR_A_RX_HPH_L_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_HPH_L_TEST			(0x1AF)
+#define SITAR_A_RX_HPH_L_TEST__POR			(0x00000001)
+#define SITAR_A_RX_HPH_L_PA_CTL			(0x1B0)
+#define SITAR_A_RX_HPH_L_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_HPH_L_DAC_CTL			(0x1B1)
+#define SITAR_A_RX_HPH_L_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_HPH_L_ATEST			(0x1B2)
+#define SITAR_A_RX_HPH_L_ATEST__POR			(0x00000000)
+#define SITAR_A_RX_HPH_L_STATUS			(0x1B3)
+#define SITAR_A_RX_HPH_L_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_HPH_R_GAIN			(0x1B4)
+#define SITAR_A_RX_HPH_R_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_HPH_R_TEST			(0x1B5)
+#define SITAR_A_RX_HPH_R_TEST__POR			(0x00000001)
+#define SITAR_A_RX_HPH_R_PA_CTL			(0x1B6)
+#define SITAR_A_RX_HPH_R_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_HPH_R_DAC_CTL			(0x1B7)
+#define SITAR_A_RX_HPH_R_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_HPH_R_ATEST			(0x1B8)
+#define SITAR_A_RX_HPH_R_ATEST__POR			(0x00000000)
+#define SITAR_A_RX_HPH_R_STATUS			(0x1B9)
+#define SITAR_A_RX_HPH_R_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_EAR_BIAS_PA			(0x1BA)
+#define SITAR_A_RX_EAR_BIAS_PA__POR			(0x000000a6)
+#define SITAR_A_RX_EAR_BIAS_CMBUFF			(0x1BB)
+#define SITAR_A_RX_EAR_BIAS_CMBUFF__POR			(0x000000a0)
+#define SITAR_A_RX_EAR_EN			(0x1BC)
+#define SITAR_A_RX_EAR_EN__POR			(0x00000000)
+#define SITAR_A_RX_EAR_GAIN			(0x1BD)
+#define SITAR_A_RX_EAR_GAIN__POR			(0x00000002)
+#define SITAR_A_RX_EAR_CMBUFF			(0x1BE)
+#define SITAR_A_RX_EAR_CMBUFF__POR			(0x00000004)
+#define SITAR_A_RX_EAR_ICTL			(0x1BF)
+#define SITAR_A_RX_EAR_ICTL__POR			(0x00000040)
+#define SITAR_A_RX_EAR_CCOMP			(0x1C0)
+#define SITAR_A_RX_EAR_CCOMP__POR			(0x00000008)
+#define SITAR_A_RX_EAR_VCM			(0x1C1)
+#define SITAR_A_RX_EAR_VCM__POR			(0x00000003)
+#define SITAR_A_RX_EAR_CNP			(0x1C2)
+#define SITAR_A_RX_EAR_CNP__POR			(0x000000f2)
+#define SITAR_A_RX_EAR_ATEST			(0x1C3)
+#define SITAR_A_RX_EAR_ATEST__POR			(0x00000000)
+#define SITAR_A_RX_EAR_STATUS			(0x1C5)
+#define SITAR_A_RX_EAR_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_LINE_BIAS_PA			(0x1C6)
+#define SITAR_A_RX_LINE_BIAS_PA__POR			(0x000000aa)
+#define SITAR_A_RX_LINE_BIAS_LDO			(0x1C7)
+#define SITAR_A_RX_LINE_BIAS_LDO__POR			(0x00000086)
+#define SITAR_A_RX_LINE_BIAS_CNP1			(0x1C8)
+#define SITAR_A_RX_LINE_BIAS_CNP1__POR			(0x00000060)
+#define SITAR_A_RX_LINE_COM			(0x1C9)
+#define SITAR_A_RX_LINE_COM__POR			(0x00000000)
+#define SITAR_A_RX_LINE_CNP_EN			(0x1CA)
+#define SITAR_A_RX_LINE_CNP_EN__POR			(0x00000080)
+#define SITAR_A_RX_LINE_CNP_WG_CTL			(0x1CB)
+#define SITAR_A_RX_LINE_CNP_WG_CTL__POR			(0x000000dc)
+#define SITAR_A_RX_LINE_CNP_WG_TIME			(0x1CC)
+#define SITAR_A_RX_LINE_CNP_WG_TIME__POR			(0x00000028)
+#define SITAR_A_RX_LINE_1_GAIN			(0x1CD)
+#define SITAR_A_RX_LINE_1_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_LINE_1_TEST			(0x1CE)
+#define SITAR_A_RX_LINE_1_TEST__POR			(0x00000001)
+#define SITAR_A_RX_LINE_1_DAC_CTL			(0x1CF)
+#define SITAR_A_RX_LINE_1_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_LINE_1_STATUS			(0x1D0)
+#define SITAR_A_RX_LINE_1_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_LINE_2_GAIN			(0x1D1)
+#define SITAR_A_RX_LINE_2_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_LINE_2_TEST			(0x1D2)
+#define SITAR_A_RX_LINE_2_TEST__POR			(0x00000001)
+#define SITAR_A_RX_LINE_2_DAC_CTL			(0x1D3)
+#define SITAR_A_RX_LINE_2_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_LINE_2_STATUS			(0x1D4)
+#define SITAR_A_RX_LINE_2_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_LINE_BIAS_CNP2			(0x1E1)
+#define SITAR_A_RX_LINE_BIAS_CNP2__POR			(0x0000008a)
+#define SITAR_A_RX_LINE_OCP_CTL			(0x1E2)
+#define SITAR_A_RX_LINE_OCP_CTL__POR			(0x000000e8)
+#define SITAR_A_RX_LINE_1_PA_CTL			(0x1E3)
+#define SITAR_A_RX_LINE_1_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_LINE_2_PA_CTL			(0x1E4)
+#define SITAR_A_RX_LINE_2_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_LINE_CNP_DBG			(0x1EC)
+#define SITAR_A_RX_LINE_CNP_DBG__POR			(0x00000000)
+#define SITAR_A_MBHC_HPH			(0x1ED)
+#define SITAR_A_MBHC_HPH__POR			(0x00000048)
+#define SITAR_A_RC_OSC_FREQ			(0x1F7)
+#define SITAR_A_RC_OSC_FREQ__POR			(0x00000046)
+#define SITAR_A_RC_OSC_TEST			(0x1F8)
+#define SITAR_A_RC_OSC_TEST__POR			(0x0000000a)
+#define SITAR_A_RC_OSC_STATUS			(0x1F9)
+#define SITAR_A_RC_OSC_STATUS__POR			(0x0000001c)
+#define SITAR_A_RC_OSC_TUNER			(0x1FA)
+#define SITAR_A_RC_OSC_TUNER__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_CTL			(0x200)
+#define SITAR_A_CDC_ANC1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_SHIFT			(0x201)
+#define SITAR_A_CDC_ANC1_SHIFT__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B1_CTL			(0x202)
+#define SITAR_A_CDC_ANC1_IIR_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B2_CTL			(0x203)
+#define SITAR_A_CDC_ANC1_IIR_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B3_CTL			(0x204)
+#define SITAR_A_CDC_ANC1_IIR_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B4_CTL			(0x205)
+#define SITAR_A_CDC_ANC1_IIR_B4_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B1_CTL			(0x206)
+#define SITAR_A_CDC_ANC1_LPF_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B2_CTL			(0x207)
+#define SITAR_A_CDC_ANC1_LPF_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B3_CTL			(0x208)
+#define SITAR_A_CDC_ANC1_LPF_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_SPARE			(0x209)
+#define SITAR_A_CDC_ANC1_SPARE__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_SMLPF_CTL			(0x20A)
+#define SITAR_A_CDC_ANC1_SMLPF_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_DCFLT_CTL			(0x20B)
+#define SITAR_A_CDC_ANC1_DCFLT_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER			(0x220)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN			(0x221)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG			(0x222)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_MUX_CTL			(0x223)
+#define SITAR_A_CDC_TX1_MUX_CTL__POR			(0x00000008)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL			(0x224)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR			(0x00000003)
+#define SITAR_A_CDC_TX1_DMIC_CTL			(0x225)
+#define SITAR_A_CDC_TX1_DMIC_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_SRC1_PDA_CFG			(0x2A0)
+#define SITAR_A_CDC_SRC1_PDA_CFG__POR			(0x00000000)
+#define SITAR_A_CDC_SRC1_FS_CTL			(0x2A1)
+#define SITAR_A_CDC_SRC1_FS_CTL__POR			(0x0000001b)
+
+#define SITAR_A_CDC_RX1_B1_CTL                  (0x000002B0)
+#define SITAR_A_CDC_RX1_B1_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B1_CTL                  (0x000002B8)
+#define SITAR_A_CDC_RX2_B1_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B1_CTL                  (0x000002C0)
+#define SITAR_A_CDC_RX3_B1_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B2_CTL                  (0x000002B1)
+#define SITAR_A_CDC_RX1_B2_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B2_CTL                  (0x000002B9)
+#define SITAR_A_CDC_RX2_B2_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B2_CTL                  (0x000002C1)
+#define SITAR_A_CDC_RX3_B2_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B3_CTL                  (0x000002B2)
+#define SITAR_A_CDC_RX1_B3_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B3_CTL                  (0x000002BA)
+#define SITAR_A_CDC_RX2_B3_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B3_CTL                  (0x000002C2)
+#define SITAR_A_CDC_RX3_B3_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B4_CTL                  (0x000002B3)
+#define SITAR_A_CDC_RX1_B4_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B4_CTL                  (0x000002BB)
+#define SITAR_A_CDC_RX2_B4_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B4_CTL                  (0x000002C3)
+#define SITAR_A_CDC_RX3_B4_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B5_CTL                  (0x000002B4)
+#define SITAR_A_CDC_RX1_B5_CTL__POR                     (0x00000060)
+#define SITAR_A_CDC_RX2_B5_CTL                  (0x000002BC)
+#define SITAR_A_CDC_RX2_B5_CTL__POR                     (0x00000060)
+#define SITAR_A_CDC_RX3_B5_CTL                  (0x000002C4)
+#define SITAR_A_CDC_RX3_B5_CTL__POR                     (0x00000060)
+
+#define SITAR_A_CDC_RX1_B6_CTL                  (0x000002B5)
+#define SITAR_A_CDC_RX1_B6_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B6_CTL                  (0x000002BD)
+#define SITAR_A_CDC_RX2_B6_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B6_CTL                  (0x000002C5)
+#define SITAR_A_CDC_RX3_B6_CTL__POR                     (0x00000000)
+
+
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL			(0x2B6)
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL			(0x2B7)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL			(0x300)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL			(0x301)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL			(0x302)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL			(0x303)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_DMIC_CTL			(0x304)
+#define SITAR_A_CDC_CLK_DMIC_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_I2S_CTL			(0x305)
+#define SITAR_A_CDC_CLK_RX_I2S_CTL__POR			(0x00000003)
+#define SITAR_A_CDC_CLK_TX_I2S_CTL			(0x306)
+#define SITAR_A_CDC_CLK_TX_I2S_CTL__POR			(0x00000003)
+#define SITAR_A_CDC_CLK_OTHR_RESET_CTL			(0x307)
+#define SITAR_A_CDC_CLK_OTHR_RESET_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL			(0x308)
+#define SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_OTHR_CTL			(0x30A)
+#define SITAR_A_CDC_CLK_OTHR_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL			(0x30B)
+#define SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_ANC_CLK_EN_CTL			(0x30C)
+#define SITAR_A_CDC_CLK_ANC_CLK_EN_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_B1_CTL			(0x30D)
+#define SITAR_A_CDC_CLK_RX_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_B2_CTL			(0x30E)
+#define SITAR_A_CDC_CLK_RX_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_MCLK_CTL			(0x30F)
+#define SITAR_A_CDC_CLK_MCLK_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_PDM_CTL			(0x310)
+#define SITAR_A_CDC_CLK_PDM_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_SD_CTL			(0x311)
+#define SITAR_A_CDC_CLK_SD_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_LP_CTL			(0x312)
+#define SITAR_A_CDC_CLK_LP_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL			(0x320)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR	(0x00000007)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL		(0x321)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR	(0x00000013)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL		(0x322)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR	(0x0000001b)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL		(0x323)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR	(0x0000007f)
+#define SITAR_A_CDC_CLSG_GAIN_THRESH_CTL		(0x324)
+#define SITAR_A_CDC_CLSG_GAIN_THRESH_CTL__POR		(0x00000026)
+#define SITAR_A_CDC_CLSG_TIMER_B1_CFG			(0x325)
+#define SITAR_A_CDC_CLSG_TIMER_B1_CFG__POR		(0x0000000a)
+#define SITAR_A_CDC_CLSG_TIMER_B2_CFG			(0x326)
+#define SITAR_A_CDC_CLSG_TIMER_B2_CFG__POR		(0x00000000)
+#define SITAR_A_CDC_CLSG_CTL			(0x327)
+#define SITAR_A_CDC_CLSG_CTL__POR			(0x00000013)
+#define SITAR_A_CDC_IIR1_GAIN_B1_CTL			(0x340)
+#define SITAR_A_CDC_IIR1_GAIN_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B2_CTL			(0x341)
+#define SITAR_A_CDC_IIR1_GAIN_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B3_CTL			(0x342)
+#define SITAR_A_CDC_IIR1_GAIN_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B4_CTL			(0x343)
+#define SITAR_A_CDC_IIR1_GAIN_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B5_CTL			(0x344)
+#define SITAR_A_CDC_IIR1_GAIN_B5_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B6_CTL			(0x345)
+#define SITAR_A_CDC_IIR1_GAIN_B6_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B7_CTL			(0x346)
+#define SITAR_A_CDC_IIR1_GAIN_B7_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B8_CTL			(0x347)
+#define SITAR_A_CDC_IIR1_GAIN_B8_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_CTL				(0x348)
+#define SITAR_A_CDC_IIR1_CTL__POR			(0x00000040)
+#define SITAR_A_CDC_IIR1_GAIN_TIMER_CTL			(0x349)
+#define SITAR_A_CDC_IIR1_GAIN_TIMER_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B1_CTL			(0x34A)
+#define SITAR_A_CDC_IIR1_COEF_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B2_CTL			(0x34B)
+#define SITAR_A_CDC_IIR1_COEF_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B3_CTL			(0x34C)
+#define SITAR_A_CDC_IIR1_COEF_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B4_CTL			(0x34D)
+#define SITAR_A_CDC_IIR1_COEF_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B5_CTL			(0x34E)
+#define SITAR_A_CDC_IIR1_COEF_B5_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_TOP_GAIN_UPDATE			(0x360)
+#define SITAR_A_CDC_TOP_GAIN_UPDATE__POR		(0x00000000)
+#define SITAR_A_CDC_TOP_RDAC_DOUT_CTL			(0x361)
+#define SITAR_A_CDC_TOP_RDAC_DOUT_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_DEBUG_B1_CTL			(0x368)
+#define SITAR_A_CDC_DEBUG_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B2_CTL			(0x369)
+#define SITAR_A_CDC_DEBUG_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B3_CTL			(0x36A)
+#define SITAR_A_CDC_DEBUG_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B4_CTL			(0x36B)
+#define SITAR_A_CDC_DEBUG_B4_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B5_CTL			(0x36C)
+#define SITAR_A_CDC_DEBUG_B5_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B6_CTL			(0x36D)
+#define SITAR_A_CDC_DEBUG_B6_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B7_CTL			(0x36E)
+#define SITAR_A_CDC_DEBUG_B7_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_COMP1_B1_CTL			(0x370)
+#define SITAR_A_CDC_COMP1_B1_CTL__POR			(0x00000030)
+#define SITAR_A_CDC_COMP1_B2_CTL			(0x371)
+#define SITAR_A_CDC_COMP1_B2_CTL__POR			(0x000000b5)
+#define SITAR_A_CDC_COMP1_B3_CTL			(0x372)
+#define SITAR_A_CDC_COMP1_B3_CTL__POR			(0x00000028)
+#define SITAR_A_CDC_COMP1_B4_CTL			(0x373)
+#define SITAR_A_CDC_COMP1_B4_CTL__POR			(0x0000003c)
+#define SITAR_A_CDC_COMP1_B5_CTL			(0x374)
+#define SITAR_A_CDC_COMP1_B5_CTL__POR			(0x0000001f)
+#define SITAR_A_CDC_COMP1_B6_CTL			(0x375)
+#define SITAR_A_CDC_COMP1_B6_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS		(0x376)
+#define SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR		(0x00000003)
+#define SITAR_A_CDC_COMP1_FS_CFG			(0x377)
+#define SITAR_A_CDC_COMP1_FS_CFG__POR			(0x0000001b)
+#define SITAR_A_CDC_CONN_RX1_B1_CTL			(0x380)
+#define SITAR_A_CDC_CONN_RX1_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX1_B2_CTL			(0x381)
+#define SITAR_A_CDC_CONN_RX1_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX1_B3_CTL			(0x382)
+#define SITAR_A_CDC_CONN_RX1_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B1_CTL			(0x383)
+#define SITAR_A_CDC_CONN_RX2_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B2_CTL			(0x384)
+#define SITAR_A_CDC_CONN_RX2_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B3_CTL			(0x385)
+#define SITAR_A_CDC_CONN_RX2_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B1_CTL			(0x386)
+#define SITAR_A_CDC_CONN_RX3_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B2_CTL			(0x387)
+#define SITAR_A_CDC_CONN_RX3_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B3_CTL			(0x388)
+#define SITAR_A_CDC_CONN_RX3_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_ANC_B1_CTL			(0x391)
+#define SITAR_A_CDC_CONN_ANC_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_ANC_B2_CTL			(0x392)
+#define SITAR_A_CDC_CONN_ANC_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_B1_CTL			(0x393)
+#define SITAR_A_CDC_CONN_TX_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CONN_TX_B2_CTL			(0x394)
+#define SITAR_A_CDC_CONN_TX_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B1_CTL			(0x397)
+#define SITAR_A_CDC_CONN_EQ1_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B2_CTL			(0x398)
+#define SITAR_A_CDC_CONN_EQ1_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B3_CTL			(0x399)
+#define SITAR_A_CDC_CONN_EQ1_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B4_CTL			(0x39A)
+#define SITAR_A_CDC_CONN_EQ1_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B1_CTL			(0x39B)
+#define SITAR_A_CDC_CONN_EQ2_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B2_CTL			(0x39C)
+#define SITAR_A_CDC_CONN_EQ2_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B3_CTL			(0x39D)
+#define SITAR_A_CDC_CONN_EQ2_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B4_CTL			(0x39E)
+#define SITAR_A_CDC_CONN_EQ2_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC1_B1_CTL			(0x39F)
+#define SITAR_A_CDC_CONN_SRC1_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC1_B2_CTL			(0x3A0)
+#define SITAR_A_CDC_CONN_SRC1_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC2_B1_CTL			(0x3A1)
+#define SITAR_A_CDC_CONN_SRC2_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC2_B2_CTL			(0x3A2)
+#define SITAR_A_CDC_CONN_SRC2_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B1_CTL			(0x3A3)
+#define SITAR_A_CDC_CONN_TX_SB_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B2_CTL			(0x3A4)
+#define SITAR_A_CDC_CONN_TX_SB_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B3_CTL			(0x3A5)
+#define SITAR_A_CDC_CONN_TX_SB_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B4_CTL			(0x3A6)
+#define SITAR_A_CDC_CONN_TX_SB_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B5_CTL			(0x3A7)
+#define SITAR_A_CDC_CONN_TX_SB_B5_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX_SB_B1_CTL			(0x3AE)
+#define SITAR_A_CDC_CONN_RX_SB_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX_SB_B2_CTL			(0x3AF)
+#define SITAR_A_CDC_CONN_RX_SB_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_CLSG_CTL			(0x3B0)
+#define SITAR_A_CDC_CONN_CLSG_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CONN_SPARE			(0x3B1)
+#define SITAR_A_CDC_CONN_SPARE__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_EN_CTL			(0x3C0)
+#define SITAR_A_CDC_MBHC_EN_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_FIR_B1_CFG			(0x3C1)
+#define SITAR_A_CDC_MBHC_FIR_B1_CFG__POR		(0x00000000)
+#define SITAR_A_CDC_MBHC_FIR_B2_CFG			(0x3C2)
+#define SITAR_A_CDC_MBHC_FIR_B2_CFG__POR		(0x00000006)
+#define SITAR_A_CDC_MBHC_TIMER_B1_CTL			(0x3C3)
+#define SITAR_A_CDC_MBHC_TIMER_B1_CTL__POR		(0x00000003)
+#define SITAR_A_CDC_MBHC_TIMER_B2_CTL			(0x3C4)
+#define SITAR_A_CDC_MBHC_TIMER_B2_CTL__POR		(0x00000009)
+#define SITAR_A_CDC_MBHC_TIMER_B3_CTL			(0x3C5)
+#define SITAR_A_CDC_MBHC_TIMER_B3_CTL__POR		(0x0000001e)
+#define SITAR_A_CDC_MBHC_TIMER_B4_CTL			(0x3C6)
+#define SITAR_A_CDC_MBHC_TIMER_B4_CTL__POR		(0x00000045)
+#define SITAR_A_CDC_MBHC_TIMER_B5_CTL			(0x3C7)
+#define SITAR_A_CDC_MBHC_TIMER_B5_CTL__POR		(0x00000004)
+#define SITAR_A_CDC_MBHC_TIMER_B6_CTL			(0x3C8)
+#define SITAR_A_CDC_MBHC_TIMER_B6_CTL__POR		(0x00000078)
+#define SITAR_A_CDC_MBHC_B1_STATUS			(0x3C9)
+#define SITAR_A_CDC_MBHC_B1_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B2_STATUS			(0x3CA)
+#define SITAR_A_CDC_MBHC_B2_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B3_STATUS			(0x3CB)
+#define SITAR_A_CDC_MBHC_B3_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B4_STATUS			(0x3CC)
+#define SITAR_A_CDC_MBHC_B4_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B5_STATUS			(0x3CD)
+#define SITAR_A_CDC_MBHC_B5_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B1_CTL			(0x3CE)
+#define SITAR_A_CDC_MBHC_B1_CTL__POR			(0x000000c0)
+#define SITAR_A_CDC_MBHC_B2_CTL			(0x3CF)
+#define SITAR_A_CDC_MBHC_B2_CTL__POR			(0x0000005d)
+#define SITAR_A_CDC_MBHC_VOLT_B1_CTL			(0x3D0)
+#define SITAR_A_CDC_MBHC_VOLT_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B2_CTL			(0x3D1)
+#define SITAR_A_CDC_MBHC_VOLT_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B3_CTL			(0x3D2)
+#define SITAR_A_CDC_MBHC_VOLT_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B4_CTL			(0x3D3)
+#define SITAR_A_CDC_MBHC_VOLT_B4_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B5_CTL			(0x3D4)
+#define SITAR_A_CDC_MBHC_VOLT_B5_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B6_CTL			(0x3D5)
+#define SITAR_A_CDC_MBHC_VOLT_B6_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B7_CTL			(0x3D6)
+#define SITAR_A_CDC_MBHC_VOLT_B7_CTL__POR			(0x000000ff)
+#define SITAR_A_CDC_MBHC_VOLT_B8_CTL			(0x3D7)
+#define SITAR_A_CDC_MBHC_VOLT_B8_CTL__POR			(0x00000007)
+#define SITAR_A_CDC_MBHC_VOLT_B9_CTL			(0x3D8)
+#define SITAR_A_CDC_MBHC_VOLT_B9_CTL__POR			(0x000000ff)
+#define SITAR_A_CDC_MBHC_VOLT_B10_CTL			(0x3D9)
+#define SITAR_A_CDC_MBHC_VOLT_B10_CTL__POR			(0x0000007f)
+#define SITAR_A_CDC_MBHC_VOLT_B11_CTL			(0x3DA)
+#define SITAR_A_CDC_MBHC_VOLT_B11_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B12_CTL			(0x3DB)
+#define SITAR_A_CDC_MBHC_VOLT_B12_CTL__POR			(0x00000080)
+#define SITAR_A_CDC_MBHC_CLK_CTL			(0x3DC)
+#define SITAR_A_CDC_MBHC_CLK_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_INT_CTL			(0x3DD)
+#define SITAR_A_CDC_MBHC_INT_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_DEBUG_CTL			(0x3DE)
+#define SITAR_A_CDC_MBHC_DEBUG_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_SPARE			(0x3DF)
+#define SITAR_A_CDC_MBHC_SPARE__POR			(0x00000000)
+/* SLIMBUS Slave Registers */
+#define SITAR_SLIM_PGD_PORT_INT_EN0                     (0x30)
+#define SITAR_SLIM_PGD_PORT_INT_STATUS0                 (0x34)
+#define SITAR_SLIM_PGD_PORT_INT_CLR0                    (0x38)
+#define SITAR_SLIM_PGD_PORT_INT_SOURCE0                 (0x60)
+
+/* Macros for Packing Register Writes into a U32 */
+#define SITAR_PACKED_REG_SIZE sizeof(u32)
+
+#define SITAR_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\
+	((mask & 0xff) << 8)|((reg & 0xffff) << 16))
+
+#define SITAR_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+	do { \
+		((reg) = ((packed >> 16) & (0xffff))); \
+		((mask) = ((packed >> 8) & (0xff))); \
+		((val) = ((packed) & (0xff))); \
+	} while (0);
+#endif
diff --git a/include/linux/mfd/wcd9310/registers.h b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
similarity index 93%
rename from include/linux/mfd/wcd9310/registers.h
rename to include/linux/mfd/wcd9xxx/wcd9310_registers.h
index ef27c08..67c2a6b 100644
--- a/include/linux/mfd/wcd9310/registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
@@ -1,29 +1,41 @@
+/* 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 TABLA_CODEC_DIGITAL_H
 
 #define TABLA_CODEC_DIGITAL_H
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 
-#define TABLA_A_CHIP_CTL			(0x00)
-#define TABLA_A_CHIP_CTL__POR			(0x00000000)
-#define TABLA_A_CHIP_STATUS			(0x01)
-#define TABLA_A_CHIP_STATUS__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_0			(0x04)
-#define TABLA_A_CHIP_ID_BYTE_0__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_1			(0x05)
-#define TABLA_A_CHIP_ID_BYTE_1__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_2			(0x06)
-#define TABLA_A_CHIP_ID_BYTE_2__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_3			(0x07)
-#define TABLA_A_CHIP_ID_BYTE_3__POR			(0x00000001)
-#define TABLA_A_CHIP_VERSION			(0x08)
-#define TABLA_A_CHIP_VERSION__POR			(0x00000020)
-#define TABLA_A_SB_VERSION			(0x09)
-#define TABLA_A_SB_VERSION__POR			(0x00000010)
-#define TABLA_A_SLAVE_ID_1			(0x0C)
-#define TABLA_A_SLAVE_ID_1__POR			(0x00000077)
-#define TABLA_A_SLAVE_ID_2			(0x0D)
-#define TABLA_A_SLAVE_ID_2__POR			(0x00000066)
-#define TABLA_A_SLAVE_ID_3			(0x0E)
-#define TABLA_A_SLAVE_ID_3__POR			(0x00000055)
+#define TABLA_A_CHIP_CTL			WCD9XXX_A_CHIP_CTL
+#define TABLA_A_CHIP_CTL__POR			WCD9XXX_A_CHIP_CTL__POR
+#define TABLA_A_CHIP_STATUS			WCD9XXX_A_CHIP_STATUS
+#define TABLA_A_CHIP_STATUS__POR		WCD9XXX_A_CHIP_STATUS__POR
+#define TABLA_A_CHIP_ID_BYTE_0			WCD9XXX_A_CHIP_ID_BYTE_0
+#define TABLA_A_CHIP_ID_BYTE_0__POR		WCD9XXX_A_CHIP_ID_BYTE_0__POR
+#define TABLA_A_CHIP_ID_BYTE_1			WCD9XXX_A_CHIP_ID_BYTE_1
+#define TABLA_A_CHIP_ID_BYTE_1__POR		WCD9XXX_A_CHIP_ID_BYTE_1__POR
+#define TABLA_A_CHIP_ID_BYTE_2			WCD9XXX_A_CHIP_ID_BYTE_2
+#define TABLA_A_CHIP_ID_BYTE_2__POR		WCD9XXX_A_CHIP_ID_BYTE_2__POR
+#define TABLA_A_CHIP_ID_BYTE_3			WCD9XXX_A_CHIP_ID_BYTE_3
+#define TABLA_A_CHIP_ID_BYTE_3__POR		WCD9XXX_A_CHIP_ID_BYTE_3__POR
+#define TABLA_A_CHIP_VERSION			WCD9XXX_A_CHIP_VERSION
+#define TABLA_A_CHIP_VERSION__POR		WCD9XXX_A_CHIP_VERSION__POR
+#define TABLA_A_SB_VERSION			WCD9XXX_A_SB_VERSION
+#define TABLA_A_SB_VERSION__POR			WCD9XXX_A_SB_VERSION__POR
+#define TABLA_A_SLAVE_ID_1			WCD9XXX_A_SLAVE_ID_1
+#define TABLA_A_SLAVE_ID_1__POR			WCD9XXX_A_SLAVE_ID_1__POR
+#define TABLA_A_SLAVE_ID_2			WCD9XXX_A_SLAVE_ID_2
+#define TABLA_A_SLAVE_ID_2__POR			WCD9XXX_A_SLAVE_ID_2__POR
+#define TABLA_A_SLAVE_ID_3			WCD9XXX_A_SLAVE_ID_3
+#define TABLA_A_SLAVE_ID_3__POR			WCD9XXX_A_SLAVE_ID_3__POR
 #define TABLA_A_PIN_CTL_OE0			(0x10)
 #define TABLA_A_PIN_CTL_OE0__POR			(0x00000000)
 #define TABLA_A_PIN_CTL_OE1			(0x11)
@@ -58,10 +70,10 @@
 #define TABLA_A_QFUSE_DATA_OUT2__POR			(0x00000000)
 #define TABLA_A_QFUSE_DATA_OUT3			(0x4D)
 #define TABLA_A_QFUSE_DATA_OUT3__POR			(0x00000000)
-#define TABLA_A_CDC_CTL			(0x80)
-#define TABLA_A_CDC_CTL__POR			(0x00000000)
-#define TABLA_A_LEAKAGE_CTL			(0x88)
-#define TABLA_A_LEAKAGE_CTL__POR			(0x00000004)
+#define TABLA_A_CDC_CTL				WCD9XXX_A_CDC_CTL
+#define TABLA_A_CDC_CTL__POR			WCD9XXX_A_CDC_CTL__POR
+#define TABLA_A_LEAKAGE_CTL			WCD9XXX_A_LEAKAGE_CTL
+#define TABLA_A_LEAKAGE_CTL__POR		WCD9XXX_A_LEAKAGE_CTL__POR
 #define TABLA_A_INTR_MODE			(0x90)
 #define TABLA_A_INTR_MODE__POR			(0x00000000)
 #define TABLA_A_INTR_MASK0			(0x94)
@@ -885,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/mfd/wcd9310/wcd9310-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
similarity index 84%
rename from include/linux/mfd/wcd9310/wcd9310-slimslave.h
rename to include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 0bbf96f..fcd3bd3 100644
--- a/include/linux/mfd/wcd9310/wcd9310-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -14,7 +14,7 @@
 #define __WCD9310_SLIMSLAVE_H_
 
 #include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
 
 /* Local to the core only */
 #define SLIM_MAX_RX_PORTS 7
@@ -84,19 +84,19 @@
 #define BASE_CH_NUM 128
 
 
-int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la);
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la);
 
-int tabla_deinit_slimslave(struct tabla *tabla);
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx);
 
-int tabla_cfg_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch, unsigned int rate);
-int tabla_cfg_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch, unsigned int rate);
-int tabla_close_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch);
-int tabla_close_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch);
-int tabla_get_channel(struct tabla *tabla,
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
 			unsigned int *rx_ch,
 			unsigned int *tx_ch);
 #endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
new file mode 100644
index 0000000..c66e953
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -0,0 +1,42 @@
+/* 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 WCD9XXX_CODEC_DIGITAL_H
+
+#define WCD9XXX_CODEC_DIGITAL_H
+
+#define WCD9XXX_A_CHIP_CTL			(0x00)
+#define WCD9XXX_A_CHIP_CTL__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_STATUS			(0x01)
+#define WCD9XXX_A_CHIP_STATUS__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_0			(0x04)
+#define WCD9XXX_A_CHIP_ID_BYTE_0__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_1			(0x05)
+#define WCD9XXX_A_CHIP_ID_BYTE_1__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_2			(0x06)
+#define WCD9XXX_A_CHIP_ID_BYTE_2__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_3			(0x07)
+#define WCD9XXX_A_CHIP_ID_BYTE_3__POR			(0x00000001)
+#define WCD9XXX_A_CHIP_VERSION			(0x08)
+#define WCD9XXX_A_CHIP_VERSION__POR			(0x00000020)
+#define WCD9XXX_A_SB_VERSION			(0x09)
+#define WCD9XXX_A_SB_VERSION__POR			(0x00000010)
+#define WCD9XXX_A_SLAVE_ID_1			(0x0C)
+#define WCD9XXX_A_SLAVE_ID_1__POR			(0x00000077)
+#define WCD9XXX_A_SLAVE_ID_2			(0x0D)
+#define WCD9XXX_A_SLAVE_ID_2__POR			(0x00000066)
+#define WCD9XXX_A_SLAVE_ID_3			(0x0E)
+#define WCD9XXX_A_SLAVE_ID_3__POR			(0x00000055)
+#define WCD9XXX_A_CDC_CTL			(0x80)
+#define WCD9XXX_A_CDC_CTL__POR			(0x00000000)
+#define WCD9XXX_A_LEAKAGE_CTL			(0x88)
+#define WCD9XXX_A_LEAKAGE_CTL__POR			(0x00000004)
+#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index c73fdf8..2009b31 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -358,36 +358,50 @@
 	return page;
 }
 
+/*
+ * The atomic page->_mapcount, starts from -1: so that transitions
+ * both from it and to it can be tracked, using atomic_inc_and_test
+ * and atomic_add_negative(-1).
+ */
+static inline void reset_page_mapcount(struct page *page)
+{
+	atomic_set(&(page)->_mapcount, -1);
+}
+
+static inline int page_mapcount(struct page *page)
+{
+	return atomic_read(&(page)->_mapcount) + 1;
+}
+
 static inline int page_count(struct page *page)
 {
 	return atomic_read(&compound_head(page)->_count);
 }
 
-static inline void get_page(struct page *page)
+static inline void get_huge_page_tail(struct page *page)
 {
 	/*
-	 * Getting a normal page or the head of a compound page
-	 * requires to already have an elevated page->_count. Only if
-	 * we're getting a tail page, the elevated page->_count is
-	 * required only in the head page, so for tail pages the
-	 * bugcheck only verifies that the page->_count isn't
-	 * negative.
+	 * __split_huge_page_refcount() cannot run
+	 * from under us.
 	 */
-	VM_BUG_ON(atomic_read(&page->_count) < !PageTail(page));
-	atomic_inc(&page->_count);
+	VM_BUG_ON(page_mapcount(page) < 0);
+	VM_BUG_ON(atomic_read(&page->_count) != 0);
+	atomic_inc(&page->_mapcount);
+}
+
+extern bool __get_page_tail(struct page *page);
+
+static inline void get_page(struct page *page)
+{
+	if (unlikely(PageTail(page)))
+		if (likely(__get_page_tail(page)))
+			return;
 	/*
-	 * Getting a tail page will elevate both the head and tail
-	 * page->_count(s).
+	 * Getting a normal page or the head of a compound page
+	 * requires to already have an elevated page->_count.
 	 */
-	if (unlikely(PageTail(page))) {
-		/*
-		 * This is safe only because
-		 * __split_huge_page_refcount can't run under
-		 * get_page().
-		 */
-		VM_BUG_ON(atomic_read(&page->first_page->_count) <= 0);
-		atomic_inc(&page->first_page->_count);
-	}
+	VM_BUG_ON(atomic_read(&page->_count) <= 0);
+	atomic_inc(&page->_count);
 }
 
 static inline struct page *virt_to_head_page(const void *x)
@@ -806,21 +820,6 @@
 }
 
 /*
- * The atomic page->_mapcount, like _count, starts from -1:
- * so that transitions both from it and to it can be tracked,
- * using atomic_inc_and_test and atomic_add_negative(-1).
- */
-static inline void reset_page_mapcount(struct page *page)
-{
-	atomic_set(&(page)->_mapcount, -1);
-}
-
-static inline int page_mapcount(struct page *page)
-{
-	return atomic_read(&(page)->_mapcount) + 1;
-}
-
-/*
  * Return true if this page is mapped into pagetables.
  */
 static inline int page_mapped(struct page *page)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 027935c..059839c 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -36,10 +36,24 @@
 					 * updated asynchronously */
 	atomic_t _count;		/* Usage count, see below. */
 	union {
-		atomic_t _mapcount;	/* Count of ptes mapped in mms,
-					 * to show when page is mapped
-					 * & limit reverse map searches.
-					 */
+		/*
+		 * Count of ptes mapped in
+		 * mms, to show when page is
+		 * mapped & limit reverse map
+		 * searches.
+		 *
+		 * Used also for tail pages
+		 * refcounting instead of
+		 * _count. Tail pages cannot
+		 * be mapped and keeping the
+		 * tail page _count zero at
+		 * all times guarantees
+		 * get_page_unless_zero() will
+		 * never succeed on tail
+		 * pages.
+		 */
+		atomic_t _mapcount;
+
 		struct {		/* SLUB */
 			u16 inuse;
 			u16 objects;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9e82abf8..0fcae7c 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -50,8 +50,12 @@
 	u8			rel_sectors;
 	u8			rel_param;
 	u8			part_config;
+	u8			cache_ctrl;
+	u8			rst_n_function;
 	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
+	unsigned int		generic_cmd6_time;	/* Units: 10ms */
+	unsigned int            power_off_longtime;     /* Units: ms */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
 	unsigned int		card_type;
@@ -64,10 +68,15 @@
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
 	unsigned int		boot_size;		/* in bytes */
+	unsigned int		cache_size;		/* Units: KB */
+	bool			hpi_en;			/* HPI enablebit */
+	bool			hpi;			/* HPI support bit */
+	unsigned int		hpi_cmd;		/* cmd used as HPI */
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
+	u8			out_of_int_time;	/* 198 */
 	u8			raw_s_a_timeout;		/* 217 */
 	u8			raw_hc_erase_gap_size;	/* 221 */
 	u8			raw_erase_timeout_mult;	/* 223 */
@@ -77,6 +86,9 @@
 	u8			raw_sec_feature_support;/* 231 */
 	u8			raw_trim_mult;		/* 232 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
+
+	unsigned int            feature_support;
+#define MMC_DISCARD_FEATURE	BIT(0)                  /* CMD38 feature */
 };
 
 struct sd_scr {
@@ -178,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 */
@@ -189,6 +202,11 @@
 #define MMC_QUIRK_DISABLE_CD	(1<<5)		/* disconnect CD/DAT[3] resistor */
 #define MMC_QUIRK_INAND_CMD38	(1<<6)		/* iNAND devices have broken CMD38 */
 #define MMC_QUIRK_BLK_NO_CMD23	(1<<7)		/* Avoid CMD23 for regular multiblock */
+	unsigned int    poweroff_notify_state;	/* eMMC4.5 notify feature */
+#define MMC_NO_POWER_NOTIFICATION	0
+#define MMC_POWERED_ON			1
+#define MMC_POWEROFF_SHORT		2
+#define MMC_POWEROFF_LONG		3
 
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
@@ -209,7 +227,6 @@
 	struct sdio_cccr	cccr;		/* common card info */
 	struct sdio_cis		cis;		/* common tuple info */
 	struct sdio_func	*sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
-	struct sdio_func	*sdio_single_irq; /* SDIO function when only one IRQ active */
 	unsigned		num_info;	/* number of info strings */
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
@@ -311,6 +328,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)
@@ -320,6 +338,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/core.h b/include/linux/mmc/core.h
index 279c023..7f30e24 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -117,6 +117,7 @@
 
 	unsigned int		sg_len;		/* size of scatter list */
 	struct scatterlist	*sg;		/* I/O scatter list */
+	s32			host_cookie;	/* host private data */
 };
 
 struct mmc_request {
@@ -125,13 +126,17 @@
 	struct mmc_data		*data;
 	struct mmc_command	*stop;
 
-	void			*done_data;	/* completion data */
+	struct completion	completion;
 	void			(*done)(struct mmc_request *);/* completion function */
 };
 
 struct mmc_host;
 struct mmc_card;
+struct mmc_async_req;
 
+extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
+					   struct mmc_async_req *, int *);
+extern int mmc_interrupt_hpi(struct mmc_card *);
 extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
@@ -142,6 +147,7 @@
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
 #define MMC_TRIM_ARG		0x00000001
+#define MMC_DISCARD_ARG		0x00000003
 #define MMC_SECURE_TRIM1_ARG	0x80000001
 #define MMC_SECURE_TRIM2_ARG	0x80008000
 
@@ -152,11 +158,17 @@
 		     unsigned int arg);
 extern int mmc_can_erase(struct mmc_card *card);
 extern int mmc_can_trim(struct mmc_card *card);
+extern int mmc_can_discard(struct mmc_card *card);
+extern int mmc_can_sanitize(struct mmc_card *card);
 extern int mmc_can_secure_erase_trim(struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 				   unsigned int nr);
+extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+extern int mmc_hw_reset(struct mmc_host *host);
+extern int mmc_hw_reset_check(struct mmc_host *host);
+extern int mmc_can_reset(struct mmc_card *card);
 
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
@@ -165,8 +177,9 @@
 extern void mmc_release_host(struct mmc_host *host);
 extern void mmc_do_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
-
+extern void mmc_set_ios(struct mmc_host *host);
 extern int mmc_detect_card_removed(struct mmc_host *host);
+extern int mmc_flush_cache(struct mmc_card *);
 
 /**
  *	mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d90c779..e19225e 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) */
 
@@ -107,6 +110,15 @@
 	 */
 	int (*enable)(struct mmc_host *host);
 	int (*disable)(struct mmc_host *host, int lazy);
+	/*
+	 * It is optional for the host to implement pre_req and post_req in
+	 * order to support double buffering of requests (prepare one
+	 * request while another request is active).
+	 */
+	void	(*post_req)(struct mmc_host *host, struct mmc_request *req,
+			    int err);
+	void	(*pre_req)(struct mmc_host *host, struct mmc_request *req,
+			   bool is_first_req);
 	void	(*request)(struct mmc_host *host, struct mmc_request *req);
 	/*
 	 * Avoid calling these three functions too often or in a "fast path",
@@ -138,13 +150,26 @@
 	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);
 };
 
 struct mmc_card;
 struct device;
 
+struct mmc_async_req {
+	/* active mmc request */
+	struct mmc_request	*mrq;
+	/*
+	 * Check error status of completed mmc request.
+	 * Returns 0 if success otherwise non zero.
+	 */
+	int (*err_check) (struct mmc_card *, struct mmc_async_req *);
+};
+
 struct mmc_host {
 	struct device		*parent;
 	struct device		class_dev;
@@ -212,10 +237,24 @@
 #define MMC_CAP_MAX_CURRENT_600	(1 << 28)	/* Host max current limit is 600mA */
 #define MMC_CAP_MAX_CURRENT_800	(1 << 29)	/* Host max current limit is 800mA */
 #define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */
+#define MMC_CAP_HW_RESET	(1 << 31)	/* Hardware reset */
 
+	unsigned int		caps2;		/* More host capabilities */
+
+#define MMC_CAP2_BOOTPART_NOACC	(1 << 0)	/* Boot partition no access */
+#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
+#define MMC_HOST_PW_NOTIFY_SHORT	1
+#define MMC_HOST_PW_NOTIFY_LONG		2
 
-#ifdef CONFIG_MMC_CLKGATE
 	int			clk_requests;	/* internal reference counter */
 	unsigned int		clk_delay;	/* number of MCI clk hold cycles */
 	bool			clk_gated;	/* clock gated */
@@ -225,7 +264,6 @@
 	struct mutex		clk_gate_mutex;	/* mutex for clock gating */
 	struct device_attribute clkgate_delay_attr;
 	unsigned long		clkgate_delay;
-#endif
 
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
@@ -234,6 +272,7 @@
 	unsigned int		max_req_size;	/* maximum number of bytes in one req */
 	unsigned int		max_blk_size;	/* maximum size of one mmc block */
 	unsigned int		max_blk_count;	/* maximum number of blocks in one req */
+	unsigned int		max_discard_to;	/* max. discard timeout in ms */
 
 	/* private data */
 	spinlock_t		lock;		/* lock for claim and bus ops */
@@ -313,7 +352,11 @@
 		ktime_t wtime_drv;	   /* Wr time  MMC Host  */
 		ktime_t start;
 	} perf;
+	bool perf_enable;
 #endif
+
+	struct mmc_async_req	*areq;		/* active async req */
+
 	unsigned long		private[0] ____cacheline_aligned;
 };
 
@@ -362,6 +405,8 @@
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
 
+extern int mmc_cache_ctrl(struct mmc_host *, u8);
+
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
 	host->ops->enable_sdio_irq(host, 0);
@@ -432,6 +477,11 @@
 	return host->caps & MMC_CAP_CMD23;
 }
 
+static inline int mmc_boot_partition_access(struct mmc_host *host)
+{
+	return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
+}
+
 #ifdef CONFIG_MMC_CLKGATE
 void mmc_host_clk_hold(struct mmc_host *host);
 void mmc_host_clk_release(struct mmc_host *host);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 53013f9..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  */
@@ -271,18 +272,30 @@
  * EXT_CSD fields
  */
 
+#define EXT_CSD_FLUSH_CACHE		32      /* W */
+#define EXT_CSD_CACHE_CTRL		33      /* R/W */
+#define EXT_CSD_POWER_OFF_NOTIFICATION	34	/* R/W */
 #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
+#define EXT_CSD_HPI_MGMT		161	/* R/W */
+#define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
+#define EXT_CSD_SANITIZE_START		165     /* W */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
+#define EXT_CSD_POWER_CLASS		187	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_STRUCTURE		194	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_OUT_OF_INTERRUPT_TIME	198	/* RO */
 #define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
+#define EXT_CSD_PWR_CL_52_195		200	/* RO */
+#define EXT_CSD_PWR_CL_26_195		201	/* RO */
+#define EXT_CSD_PWR_CL_52_360		202	/* RO */
+#define EXT_CSD_PWR_CL_26_360		203	/* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_REL_WR_SEC_C		222	/* RO */
@@ -294,6 +307,14 @@
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
 #define EXT_CSD_TRIM_MULT		232	/* RO */
+#define EXT_CSD_PWR_CL_200_195		236	/* RO */
+#define EXT_CSD_PWR_CL_200_360		237	/* RO */
+#define EXT_CSD_PWR_CL_DDR_52_195	238	/* RO */
+#define EXT_CSD_PWR_CL_DDR_52_360	239	/* RO */
+#define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
+#define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
+#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_HPI_FEATURES		503	/* RO */
 
 /*
  * EXT_CSD field definitions
@@ -311,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 */
@@ -328,7 +412,20 @@
 #define EXT_CSD_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
+#define EXT_CSD_SEC_SANITIZE	BIT(6)  /* v4.5 only */
 
+#define EXT_CSD_RST_N_EN_MASK	0x3
+#define EXT_CSD_RST_N_ENABLED	1	/* RST_n is enabled on card */
+
+#define EXT_CSD_NO_POWER_NOTIFICATION	0
+#define EXT_CSD_POWER_ON		1
+#define EXT_CSD_POWER_OFF_SHORT		2
+#define EXT_CSD_POWER_OFF_LONG		3
+
+#define EXT_CSD_PWR_CL_8BIT_MASK	0xF0	/* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_4BIT_MASK	0x0F	/* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_8BIT_SHIFT	4
+#define EXT_CSD_PWR_CL_4BIT_SHIFT	0
 /*
  * MMC_SWITCH access modes
  */
diff --git a/include/linux/msm_audio.h b/include/linux/msm_audio.h
index 30d74ce..f2a39e4 100644
--- a/include/linux/msm_audio.h
+++ b/include/linux/msm_audio.h
@@ -1,6 +1,7 @@
 /* include/linux/msm_audio.h
  *
  * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 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
@@ -63,6 +64,9 @@
 					unsigned short)
 #define AUDIO_GET_BITSTREAM_ERROR_INFO _IOR(AUDIO_IOCTL_MAGIC, 42, \
 			       struct msm_audio_bitstream_error_info)
+
+#define AUDIO_SET_SRS_TRUMEDIA_PARAM _IOW(AUDIO_IOCTL_MAGIC, 43, unsigned)
+
 /* Qualcomm extensions */
 #define AUDIO_SET_STREAM_CONFIG   _IOW(AUDIO_IOCTL_MAGIC, 80, \
 				struct msm_audio_stream_config)
@@ -90,6 +94,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
 
 
@@ -129,6 +136,8 @@
 #define IIR_ENABLE		0x0004
 #define QCONCERT_PLUS_ENABLE	0x0008
 #define MBADRC_ENABLE		0x0010
+#define SRS_ENABLE		0x0020
+#define SRS_DISABLE	0x0040
 
 #define AGC_ENABLE		0x0001
 #define NS_ENABLE		0x0002
@@ -166,6 +175,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_audio_mvs.h b/include/linux/msm_audio_mvs.h
index 2813c8f..8ec9796 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -24,7 +24,7 @@
 #define MVS_MODE_G729A 0xE
 #define MVS_MODE_G711A 0xF
 #define MVS_MODE_G722 0x10
-#define MVS_MODE_PCM_WB 0x80000000
+#define MVS_MODE_PCM_WB 0x12
 
 enum msm_audio_amr_mode {
 	MVS_AMR_MODE_0475, /* AMR 4.75 kbps */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 37b9d35..672468e 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
 #define _MSM_KGSL_H
 
 #define KGSL_VERSION_MAJOR        3
-#define KGSL_VERSION_MINOR        8
+#define KGSL_VERSION_MINOR        9
 
 /*context flags */
 #define KGSL_CONTEXT_SAVE_GMEM	1
@@ -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 {
@@ -140,6 +151,13 @@
 #define KGSL_2D1_REG_MEMORY	"kgsl_2d1_reg_memory"
 #define KGSL_2D1_IRQ		"kgsl_2d1_irq"
 
+struct kgsl_device_iommu_data {
+	const char **iommu_ctx_names;
+	int iommu_ctx_count;
+	unsigned int physstart;
+	unsigned int physend;
+};
+
 struct kgsl_device_platform_data {
 	struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
 	int init_level;
@@ -150,8 +168,9 @@
 	unsigned int clk_map;
 	unsigned int idle_needed;
 	struct msm_bus_scale_pdata *bus_scale_table;
-	const char *iommu_user_ctx_name;
-	const char *iommu_priv_ctx_name;
+	struct kgsl_device_iommu_data *iommu_data;
+	int iommu_count;
+	struct msm_dcvs_core_info *core_info;
 };
 
 #endif
@@ -186,19 +205,8 @@
 #define IOCTL_KGSL_DEVICE_GETPROPERTY \
 	_IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty)
 
-
-/* read a GPU register.
-   offsetwords it the 32 bit word offset from the beginning of the
-   GPU register space.
+/* IOCTL_KGSL_DEVICE_READ (0x3) - removed 03/2012
  */
-struct kgsl_device_regread {
-	unsigned int offsetwords;
-	unsigned int value; /* output param */
-};
-
-#define IOCTL_KGSL_DEVICE_REGREAD \
-	_IOWR(KGSL_IOC_TYPE, 0x3, struct kgsl_device_regread)
-
 
 /* block until the GPU has executed past a given timestamp
  * timeout is in milliseconds.
@@ -447,6 +455,14 @@
 	int handle; /* Handle of the genlock lock to release */
 };
 
+/*
+ * Set a property within the kernel.  Uses the same structure as
+ * IOCTL_KGSL_GETPROPERTY
+ */
+
+#define IOCTL_KGSL_SETPROPERTY \
+	_IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty)
+
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 07d5af6..aa54b71 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -25,7 +25,7 @@
 #define MSMFB_RESUME_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 129, unsigned int)
 #define MSMFB_CURSOR _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor)
 #define MSMFB_SET_LUT _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap)
-#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram)
+#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram_data)
 /* new ioctls's for set/get ccs matrix */
 #define MSMFB_GET_CCS_MATRIX  _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs)
 #define MSMFB_SET_CCS_MATRIX  _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs)
@@ -44,8 +44,9 @@
 #define MSMFB_OVERLAY_BLT       _IOWR(MSMFB_IOCTL_MAGIC, 142, \
 						struct msmfb_overlay_blt)
 #define MSMFB_OVERLAY_BLT_OFFSET     _IOW(MSMFB_IOCTL_MAGIC, 143, unsigned int)
-#define MSMFB_HISTOGRAM_START	_IO(MSMFB_IOCTL_MAGIC, 144)
-#define MSMFB_HISTOGRAM_STOP	_IO(MSMFB_IOCTL_MAGIC, 145)
+#define MSMFB_HISTOGRAM_START	_IOR(MSMFB_IOCTL_MAGIC, 144, \
+						struct mdp_histogram_start_req)
+#define MSMFB_HISTOGRAM_STOP	_IOR(MSMFB_IOCTL_MAGIC, 145, unsigned int)
 #define MSMFB_NOTIFY_UPDATE	_IOW(MSMFB_IOCTL_MAGIC, 146, unsigned int)
 
 #define MSMFB_OVERLAY_3D       _IOWR(MSMFB_IOCTL_MAGIC, 147, \
@@ -140,6 +141,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
@@ -327,6 +329,32 @@
 	MDP_BLOCK_MAX,
 };
 
+/*
+ * mdp_histogram_start_req is used to provide the parameters for
+ * histogram start request
+ */
+
+struct mdp_histogram_start_req {
+	uint32_t block;
+	uint8_t frame_cnt;
+	uint8_t bit_mask;
+	uint8_t num_bins;
+};
+
+/*
+ * mdp_histogram_data is used to return the histogram data, once
+ * the histogram is done/stopped/cance
+ */
+
+struct mdp_histogram_data {
+	uint32_t block;
+	uint8_t bin_cnt;
+	uint32_t *c0;
+	uint32_t *c1;
+	uint32_t *c2;
+	uint32_t extra_info[2];
+};
+
 struct mdp_pcc_coeff {
 	uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1;
 };
@@ -444,11 +472,16 @@
 	struct mdp_mixer_info info[MAX_PIPE_PER_MIXER];
 };
 
+enum {
+	DISPLAY_SUBSYSTEM_ID,
+	ROTATOR_SUBSYSTEM_ID,
+};
 
 #ifdef __KERNEL__
 
 /* get the framebuffer physical address information */
-int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num);
+int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num,
+	int subsys_id);
 struct fb_info *msm_fb_get_writeback_fb(void);
 int msm_fb_writeback_init(struct fb_info *info);
 int msm_fb_writeback_start(struct fb_info *info);
diff --git a/include/linux/msm_tsens.h b/include/linux/msm_tsens.h
index 99b5acd..f5472ec 100644
--- a/include/linux/msm_tsens.h
+++ b/include/linux/msm_tsens.h
@@ -1,5 +1,5 @@
 /*
- * 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,7 +21,7 @@
 enum platform_type {
 	MSM_8660 = 0,
 	MSM_8960,
-	MSM_9615,
+	MDM_9615,
 	APQ_8064,
 	MSM_TYPE
 };
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
index 9c742b5..0c03e13 100644
--- a/include/linux/msm_vidc_dec.h
+++ b/include/linux/msm_vidc_dec.h
@@ -514,6 +514,12 @@
 	uint32_t   bottom;
 };
 
+struct vdec_aspectratioinfo {
+	uint32_t aspect_ratio;
+	uint32_t par_width;
+	uint32_t par_height;
+};
+
 struct vdec_output_frameinfo {
 	void __user *bufferaddr;
 	size_t offset;
@@ -525,6 +531,7 @@
 	void *input_frame_clientdata;
 	struct vdec_framesize framesize;
 	enum vdec_interlaced_format interlaced_format;
+	struct vdec_aspectratioinfo aspect_ratio_info;
 };
 
 union vdec_msgdata {
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/namei.h b/include/linux/namei.h
index eba45ea..82ab16b 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -49,6 +49,7 @@
 #define LOOKUP_FOLLOW		0x0001
 #define LOOKUP_DIRECTORY	0x0002
 #define LOOKUP_CONTINUE		0x0004
+#define LOOKUP_AUTOMOUNT	0x0008
 
 #define LOOKUP_PARENT		0x0010
 #define LOOKUP_REVAL		0x0020
@@ -67,6 +68,7 @@
 #define LOOKUP_EMPTY		0x4000
 
 extern int user_path_at(int, const char __user *, unsigned, struct path *);
+extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
 
 #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
 #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path)
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index b522370..acdc370 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -410,6 +410,9 @@
 extern const struct inode_operations nfs3_file_inode_operations;
 #endif /* CONFIG_NFS_V3 */
 extern const struct file_operations nfs_file_operations;
+#ifdef CONFIG_NFS_V4
+extern const struct file_operations nfs4_file_operations;
+#endif /* CONFIG_NFS_V4 */
 extern const struct address_space_operations nfs_file_aops;
 extern const struct address_space_operations nfs_dir_aops;
 
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index be2eba7..0012fc3 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1149,6 +1149,7 @@
 	const struct dentry_operations *dentry_ops;
 	const struct inode_operations *dir_inode_ops;
 	const struct inode_operations *file_inode_ops;
+	const struct file_operations *file_ops;
 
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsinfo *);
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 70fe6ca..e7cc68e 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1242,6 +1242,18 @@
 	NL80211_ATTR_IE_PROBE_RESP,
 	NL80211_ATTR_IE_ASSOC_RESP,
 
+	NL80211_ATTR_STA_WME,
+	NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+	NL80211_ATTR_ROAM_SUPPORT,
+
+	NL80211_ATTR_SCHED_SCAN_MATCH,
+	NL80211_ATTR_MAX_MATCH_SETS,
+
+	NL80211_ATTR_PMKSA_CANDIDATE,
+
+	NL80211_ATTR_TX_NO_CCK_RATE,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/include/linux/of.h b/include/linux/of.h
index 6a1272c..452ed98 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -202,6 +202,11 @@
 
 extern int of_property_read_string(struct device_node *np, char *propname,
 					const char **out_string);
+extern int of_property_read_string_index(struct device_node *np,
+					 const char *propname,
+					 int index, const char **output);
+extern int of_property_count_strings(struct device_node *np,
+				     const char *propname);
 extern int of_device_is_compatible(const struct device_node *device,
 				   const char *);
 extern int of_device_is_available(const struct device_node *device);
@@ -241,6 +246,22 @@
 	return false;
 }
 
+#define for_each_child_of_node(parent, child) \
+	while (0)
+
+static inline int of_device_is_compatible(const struct device_node *device,
+					  const char *name)
+{
+	return 0;
+}
+
+static inline struct property *of_find_property(const struct device_node *np,
+						const char *name,
+						int *lenp)
+{
+	return NULL;
+}
+
 static inline int of_property_read_u32_array(const struct device_node *np,
 				char *propname, u32 *out_values, size_t sz)
 {
@@ -253,6 +274,19 @@
 	return -ENOSYS;
 }
 
+static inline int of_property_read_string_index(struct device_node *np,
+						const char *propname, int index,
+						const char **out_string)
+{
+	return -ENOSYS;
+}
+
+static inline int of_property_count_strings(struct device_node *np,
+					    const char *propname)
+{
+	return -ENOSYS;
+}
+
 static inline const void *of_get_property(const struct device_node *node,
 				const char *name,
 				int *lenp)
@@ -260,6 +294,13 @@
 	return NULL;
 }
 
+static inline struct device_node *of_parse_phandle(struct device_node *np,
+						   const char *phandle_name,
+						   int index)
+{
+	return NULL;
+}
+
 #endif /* CONFIG_OF */
 
 static inline int of_property_read_u32(const struct device_node *np,
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3118623..01b925a 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -4,6 +4,7 @@
 #include <linux/errno.h>
 #include <linux/of.h>
 
+#ifdef CONFIG_OF_ADDRESS
 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
 extern int of_address_to_resource(struct device_node *dev, int index,
 				  struct resource *r);
@@ -25,12 +26,37 @@
 #define pci_address_to_pio pci_address_to_pio
 #endif
 
-#ifdef CONFIG_PCI
+#else /* CONFIG_OF_ADDRESS */
+static inline int of_address_to_resource(struct device_node *dev, int index,
+					 struct resource *r)
+{
+	return -EINVAL;
+}
+static inline struct device_node *of_find_matching_node_by_address(
+					struct device_node *from,
+					const struct of_device_id *matches,
+					u64 base_address)
+{
+	return NULL;
+}
+static inline void __iomem *of_iomap(struct device_node *device, int index)
+{
+	return NULL;
+}
+static inline const u32 *of_get_address(struct device_node *dev, int index,
+					u64 *size, unsigned int *flags)
+{
+	return NULL;
+}
+#endif /* CONFIG_OF_ADDRESS */
+
+
+#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)
 extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no,
 			       u64 *size, unsigned int *flags);
 extern int of_pci_address_to_resource(struct device_node *dev, int bar,
 				      struct resource *r);
-#else /* CONFIG_PCI */
+#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */
 static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
 				             struct resource *r)
 {
@@ -42,8 +68,7 @@
 {
 	return NULL;
 }
-#endif /* CONFIG_PCI */
-
+#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */
 
 #endif /* __OF_ADDRESS_H */
 
diff --git a/include/linux/of_slimbus.h b/include/linux/of_slimbus.h
new file mode 100644
index 0000000..8e1dc65
--- /dev/null
+++ b/include/linux/of_slimbus.h
@@ -0,0 +1,34 @@
+/* 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/slimbus/slimbus.h>
+#include <linux/of_irq.h>
+
+#ifdef CONFIG_OF_SLIMBUS
+/*
+ * of_slim_register_devices() - Register devices in the SLIMbus Device Tree
+ * @ctrl: slim_controller which devices should be registered to.
+ *
+ * This routine scans the SLIMbus Device Tree, allocating resources and
+ * creating slim_devices according to the SLIMbus Device Tree
+ * hierarchy. Details of this hierarchy can be found in
+ * Documentation/devicetree/bindings/slimbus. This routine is normally
+ * called from the probe routine of the driver registering as a
+ * slim_controller.
+ */
+extern int of_register_slim_devices(struct slim_controller *ctrl);
+#else
+static int of_register_slim_devices(struct slim_controller *ctrl)
+{
+	return 0;
+}
+#endif /* CONFIG_OF_SLIMBUS */
diff --git a/include/linux/of_spmi.h b/include/linux/of_spmi.h
index d07ce63..fe09dec 100644
--- a/include/linux/of_spmi.h
+++ b/include/linux/of_spmi.h
@@ -14,6 +14,17 @@
 #include <linux/of_irq.h>
 
 #ifdef CONFIG_OF_SPMI
+/**
+ * of_spmi_register_devices() - Register devices in the SPMI Device Tree
+ * @ctrl: spmi_controller which devices should be registered to.
+ *
+ * This routine scans the SPMI Device Tree, allocating resources and
+ * creating spmi_devices according to the SPMI bus Device Tree
+ * hierarchy. Details of this hierarchy can be found in
+ * Documentation/devicetree/bindings/spmi. This routine is normally
+ * called from the probe routine of the driver registering as a
+ * spmi_controller.
+ */
 int of_spmi_register_devices(struct spmi_controller *ctrl);
 #else
 static int of_spmi_register_devices(struct spmi_controller *ctrl)
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index 7cea7b6..c832014 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -29,7 +29,7 @@
 extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
 extern void pci_disable_link_state(struct pci_dev *pdev, int state);
 extern void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
-extern void pcie_clear_aspm(void);
+extern void pcie_clear_aspm(struct pci_bus *bus);
 extern void pcie_no_aspm(void);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
@@ -47,7 +47,7 @@
 static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
 {
 }
-static inline void pcie_clear_aspm(void)
+static inline void pcie_clear_aspm(struct pci_bus *bus)
 {
 }
 static inline void pcie_no_aspm(void)
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index e884096..dad7d9a 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -392,7 +392,7 @@
 #define  PCI_EXP_TYPE_DOWNSTREAM 0x6	/* Downstream Port */
 #define  PCI_EXP_TYPE_PCI_BRIDGE 0x7	/* PCI/PCI-X Bridge */
 #define  PCI_EXP_TYPE_RC_END	0x9	/* Root Complex Integrated Endpoint */
-#define  PCI_EXP_TYPE_RC_EC	0x10	/* Root Complex Event Collector */
+#define  PCI_EXP_TYPE_RC_EC	0xa	/* Root Complex Event Collector */
 #define PCI_EXP_FLAGS_SLOT	0x0100	/* Slot implemented */
 #define PCI_EXP_FLAGS_IRQ	0x3e00	/* Interrupt message number */
 #define PCI_EXP_DEVCAP		4	/* Device capabilities */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7da5fa8..4d3f63a 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -418,7 +418,7 @@
 
 	/*
 	 * Requests a Tx timestamp for 'skb'. The phy driver promises
-	 * to deliver it to the socket's error queue as soon as a
+	 * to deliver it using skb_complete_tx_timestamp() as soon as a
 	 * timestamp becomes available. One of the PTP_CLASS_ values
 	 * is passed in 'type'.
 	 */
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/qpnp/gpio.h b/include/linux/qpnp/gpio.h
new file mode 100644
index 0000000..0447a08
--- /dev/null
+++ b/include/linux/qpnp/gpio.h
@@ -0,0 +1,114 @@
+/* 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 <mach/qpnp.h>
+
+#define QPNP_GPIO_DIR_OUT			1
+#define QPNP_GPIO_DIR_IN			2
+#define QPNP_GPIO_DIR_BOTH	(QPNP_GPIO_DIR_OUT | QPNP_GPIO_DIR_IN)
+
+#define QPNP_GPIO_OUT_BUF_OPEN_DRAIN		1
+#define QPNP_GPIO_OUT_BUF_CMOS			0
+
+#define QPNP_GPIO_VIN0				0
+#define QPNP_GPIO_VIN1				1
+#define QPNP_GPIO_VIN2				2
+#define QPNP_GPIO_VIN3				3
+#define QPNP_GPIO_VIN4				4
+#define QPNP_GPIO_VIN5				5
+#define QPNP_GPIO_VIN6				6
+#define QPNP_GPIO_VIN7				7
+
+#define QPNP_GPIO_PULL_UP_30			0
+#define QPNP_GPIO_PULL_UP_1P5			1
+#define QPNP_GPIO_PULL_UP_31P5			2
+#define QPNP_GPIO_PULL_UP_1P5_30		3
+#define QPNP_GPIO_PULL_DN			4
+#define QPNP_GPIO_PULL_NO			5
+
+#define QPNP_GPIO_OUT_STRENGTH_LOW		1
+#define QPNP_GPIO_OUT_STRENGTH_MED		2
+#define QPNP_GPIO_OUT_STRENGTH_HIGH		3
+
+#define QPNP_GPIO_FUNC_NORMAL			0
+#define QPNP_GPIO_FUNC_PAIRED			1
+#define QPNP_GPIO_FUNC_1			2
+#define QPNP_GPIO_FUNC_2			3
+#define QPNP_GPIO_DTEST1			4
+#define QPNP_GPIO_DTEST2			5
+#define QPNP_GPIO_DTEST3			6
+#define QPNP_GPIO_DTEST4			7
+
+/**
+ * struct qpnp_gpio_cfg - structure to specify gpio configurtion values
+ * @direction:		indicates whether the gpio should be input, output, or
+ *			both. Should be of the type QPNP_GPIO_DIR_*
+ * @output_type:	indicates gpio should be configured as CMOS or open
+ *			drain. Should be of the type QPNP_GPIO_OUT_BUF_*
+ * @output_value:	The gpio output value of the gpio line - 0 or 1
+ * @pull:		Indicates whether a pull up or pull down should be
+ *			applied. If a pullup is required the current strength
+ *			needs to be specified. Current values of 30uA, 1.5uA,
+ *			31.5uA, 1.5uA with 30uA boost are supported. This value
+ *			should be one of the QPNP_GPIO_PULL_*
+ * @vin_sel:		specifies the voltage level when the output is set to 1.
+ *			For an input gpio specifies the voltage level at which
+ *			the input is interpreted as a logical 1.
+ * @out_strength:	the amount of current supplied for an output gpio,
+ *			should be of the type QPNP_GPIO_STRENGTH_*
+ * @source_sel:		choose alternate function for the gpio. Certain gpios
+ *			can be paired (shorted) with each other. Some gpio pin
+ *			can act as alternate functions. This parameter should
+ *			be of type QPNP_GPIO_FUNC_*
+ * @inv_int_pol:	Invert polarity before feeding the line to the interrupt
+ *			module in pmic. This feature will almost be never used
+ *			since the pm8xxx interrupt block can detect both edges
+ *			and both levels.
+ * @master_en:		1 = Enable features within the GPIO block based on
+ *			configurations.
+ *			0 = Completely disable the GPIO block and let the pin
+ *			float with high impedance regardless of other settings.
+ */
+struct qpnp_gpio_cfg {
+	int		direction;
+	int		output_type;
+	int		output_value;
+	int		pull;
+	int		vin_sel;
+	int		out_strength;
+	int		src_select;
+	int		inv_int_pol;
+	int		master_en;
+};
+
+/**
+ * qpnp_gpio_config - Apply gpio configuration for Linux gpio
+ * @gpio: Linux gpio number to configure.
+ * @param: parameters to configure.
+ *
+ * This routine takes a Linux gpio number that corresponds with a
+ * PMIC gpio and applies the configuration specified in 'param'.
+ * This gpio number can be ascertained by of_get_gpio_flags() or
+ * the qpnp_gpio_map_gpio() API.
+ */
+int qpnp_gpio_config(int gpio, struct qpnp_gpio_cfg *param);
+
+/**
+ * qpnp_gpio_map_gpio - Obtain Linux GPIO number from device spec
+ * @slave_id: slave_id of the spmi_device for the gpio in question.
+ * @pmic_gpio: PMIC gpio number to lookup.
+ *
+ * This routine is used in legacy configurations that do not support
+ * Device Tree. If you are using Device Tree, you should not use this.
+ * For such cases, use of_get_gpio() instead.
+ */
+int qpnp_gpio_map_gpio(uint16_t slave_id, uint32_t pmic_gpio);
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
new file mode 100644
index 0000000..6d39026
--- /dev/null
+++ b/include/linux/qseecom.h
@@ -0,0 +1,149 @@
+#ifndef __QSEECOM_H_
+#define __QSEECOM_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define MAX_ION_FD  4
+#define MAX_APP_NAME_SIZE  32
+
+/*
+ * struct qseecom_register_listener_req -
+ *      for register listener ioctl request
+ * @listener_id - service id (shared between userspace and QSE)
+ * @ifd_data_fd - ion handle
+ * @virt_sb_base - shared buffer base in user space
+ * @sb_size - shared buffer size
+ */
+struct qseecom_register_listener_req {
+	uint32_t listener_id; /* in */
+	int32_t ifd_data_fd; /* in */
+	uint32_t virt_sb_base; /* in */
+	uint32_t sb_size; /* in */
+};
+
+/*
+ * struct qseecom_send_cmd_req - for send command ioctl request
+ * @cmd_req_len - command buffer length
+ * @cmd_req_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ */
+struct qseecom_send_cmd_req {
+	void *cmd_req_buf; /* in */
+	unsigned int cmd_req_len; /* in */
+	void *resp_buf; /* in/out */
+	unsigned int resp_len; /* in/out */
+};
+
+
+/*
+ * struct qseecom_ion_fd_info - ion fd handle data information
+ * @fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_ion_fd_info {
+	int32_t fd;
+	uint32_t cmd_buf_offset;
+};
+/*
+ * struct qseecom_send_modfd_cmd_req - for send command ioctl request
+ * @cmd_req_len - command buffer length
+ * @cmd_req_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ * @ifd_data_fd - ion handle to memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_send_modfd_cmd_req {
+	void *cmd_req_buf; /* in */
+	unsigned int cmd_req_len; /* in */
+	void *resp_buf; /* in/out */
+	unsigned int resp_len; /* in/out */
+	struct qseecom_ion_fd_info ifd_data[MAX_ION_FD];
+};
+/*
+ * struct qseecom_listener_send_resp_req - signal to continue the send_cmd req.
+ * Used as a trigger from HLOS service to notify QSEECOM that it's done with its
+ * operation and provide the response for QSEECOM can continue the incomplete
+ * command execution
+ * @resp_len - Length of the response
+ * @resp_buf - Response buffer where the response of the cmd should go.
+ */
+struct qseecom_send_resp_req {
+	void *resp_buf; /* in */
+	unsigned int resp_len; /* in */
+};
+
+/*
+ * struct qseecom_load_img_data - for sending image length information and
+ * ion file descriptor to the qseecom driver. ion file descriptor is used
+ * for retrieving the ion file handle and in turn the physical address of
+ * the image location.
+ * @mdt_len - Length of the .mdt file in bytes.
+ * @img_len - Length of the .mdt + .b00 +..+.bxx images files in bytes
+ * @ion_fd - Ion file descriptor used when allocating memory.
+ * @img_name - Name of the image.
+*/
+struct qseecom_load_img_req {
+	uint32_t mdt_len; /* in */
+	uint32_t img_len; /* in */
+	int32_t  ifd_data_fd; /* in */
+	char	 img_name[MAX_APP_NAME_SIZE]; /* in */
+	int app_id; /* out*/
+};
+
+struct qseecom_set_sb_mem_param_req {
+	int32_t ifd_data_fd; /* in */
+	uint32_t virt_sb_base; /* in */
+	uint32_t sb_len; /* in */
+};
+
+/*
+ * struct qseecom_qseos_version_req - get qseos version
+ * @qseos_version - version number
+ */
+struct qseecom_qseos_version_req {
+	unsigned int qseos_version; /* in */
+};
+
+#define QSEECOM_IOC_MAGIC    0x97
+
+
+#define QSEECOM_IOCTL_REGISTER_LISTENER_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 1, struct qseecom_register_listener_req)
+
+#define QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 2)
+
+#define QSEECOM_IOCTL_SEND_CMD_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 3, struct qseecom_send_cmd_req)
+
+#define QSEECOM_IOCTL_SEND_MODFD_CMD_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 4, struct qseecom_send_modfd_cmd_req)
+
+#define QSEECOM_IOCTL_RECEIVE_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 5)
+
+#define QSEECOM_IOCTL_SEND_RESP_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 6)
+
+#define QSEECOM_IOCTL_LOAD_APP_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 7, struct qseecom_load_img_req)
+
+#define QSEECOM_IOCTL_SET_MEM_PARAM_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 8, struct qseecom_set_sb_mem_param_req)
+
+#define QSEECOM_IOCTL_UNLOAD_APP_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 9)
+
+#define QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 10, struct qseecom_qseos_version_req)
+
+#define QSEECOM_IOCTL_PERF_ENABLE_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 11)
+
+#define QSEECOM_IOCTL_PERF_DISABLE_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 12)
+
+#endif /* __QSEECOM_H_ */
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 6c433b8..956a331 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -153,6 +153,7 @@
  * this type.
  *
  * @name: Identifying name for the regulator.
+ * @supply_name: Identifying the regulator supply
  * @id: Numerical identifier for the regulator.
  * @n_voltages: Number of selectors available for ops.list_voltage().
  * @ops: Regulator operations table.
@@ -162,6 +163,7 @@
  */
 struct regulator_desc {
 	const char *name;
+	const char *supply_name;
 	int id;
 	unsigned n_voltages;
 	struct regulator_ops *ops;
@@ -210,7 +212,7 @@
 
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
 	struct device *dev, const struct regulator_init_data *init_data,
-	void *driver_data);
+	void *driver_data, struct device_node *of_node);
 void regulator_unregister(struct regulator_dev *rdev);
 
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 6804ef3..22a832a 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -95,7 +95,7 @@
  */
 struct regulation_constraints {
 
-	char *name;
+	const char *name;
 
 	/* voltage output range (inclusive) - for voltage control */
 	int min_uV;
diff --git a/include/linux/regulator/of_regulator.h b/include/linux/regulator/of_regulator.h
new file mode 100644
index 0000000..d83a98d
--- /dev/null
+++ b/include/linux/regulator/of_regulator.h
@@ -0,0 +1,20 @@
+/*
+ * OpenFirmware regulator support routines
+ *
+ */
+
+#ifndef __LINUX_OF_REG_H
+#define __LINUX_OF_REG_H
+
+#if defined(CONFIG_OF)
+extern struct regulator_init_data
+	*of_get_regulator_init_data(struct device *dev);
+#else
+static inline struct regulator_init_data
+	*of_get_regulator_init_data(struct device *dev)
+{
+	return NULL;
+}
+#endif /* CONFIG_OF */
+
+#endif /* __LINUX_OF_REG_H */
diff --git a/include/linux/regulator/stub-regulator.h b/include/linux/regulator/stub-regulator.h
new file mode 100644
index 0000000..e7f4110
--- /dev/null
+++ b/include/linux/regulator/stub-regulator.h
@@ -0,0 +1,35 @@
+/* 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 __STUB_REGULATOR_H__
+#define __STUB_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+#define STUB_REGULATOR_DRIVER_NAME "stub-regulator"
+
+/**
+ * struct stub_regulator_pdata - stub regulator device data
+ * @init_data:		regulator constraints
+ * @hpm_min_load:	minimum load in uA that will result in the regulator
+ *			being set to high power mode
+ * @system_uA:		current drawn from regulator not accounted for by any
+ *			regulator framework consumer
+ */
+struct stub_regulator_pdata {
+	struct regulator_init_data	init_data;
+	int				hpm_min_load;
+	int				system_uA;
+};
+
+int __init regulator_stub_init(void);
+#endif
diff --git a/include/linux/sigma.h b/include/linux/sigma.h
index e2accb3..d0de882 100644
--- a/include/linux/sigma.h
+++ b/include/linux/sigma.h
@@ -24,7 +24,7 @@
 struct sigma_firmware_header {
 	unsigned char magic[7];
 	u8 version;
-	u32 crc;
+	__le32 crc;
 };
 
 enum {
@@ -40,19 +40,14 @@
 struct sigma_action {
 	u8 instr;
 	u8 len_hi;
-	u16 len;
-	u16 addr;
+	__le16 len;
+	__be16 addr;
 	unsigned char payload[];
 };
 
 static inline u32 sigma_action_len(struct sigma_action *sa)
 {
-	return (sa->len_hi << 16) | sa->len;
-}
-
-static inline size_t sigma_action_size(struct sigma_action *sa, u32 payload_len)
-{
-	return sizeof(*sa) + payload_len + (payload_len % 2);
+	return (sa->len_hi << 16) | le16_to_cpu(sa->len);
 }
 
 extern int process_sigma_firmware(struct i2c_client *client, const char *name);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index c0a4f3a..b920a72 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1996,8 +1996,13 @@
 /**
  * skb_complete_tx_timestamp() - deliver cloned skb with tx timestamps
  *
+ * PHY drivers may accept clones of transmitted packets for
+ * timestamping via their phy_driver.txtstamp method. These drivers
+ * must call this function to return the skb back to the stack, with
+ * or without a timestamp.
+ *
  * @skb: clone of the the original outgoing packet
- * @hwtstamps: hardware time stamps
+ * @hwtstamps: hardware time stamps, may be NULL if not available
  *
  */
 void skb_complete_tx_timestamp(struct sk_buff *skb,
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 448d9ab..75b132b 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -877,6 +877,7 @@
  * -EXFULL is returned if there is no space in TDM to reserve the bandwidth.
  * -EISCONN/-ENOTCONN is returned if the channel is already connected or not
  * yet defined.
+ * -EINVAL is returned if individual control of a grouped-channel is attempted.
  */
 extern int slim_control_ch(struct slim_device *sb, u16 grpchanh,
 				enum slim_ch_control chctrl, bool commit);
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index ffcb24e..927978a 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -88,24 +88,36 @@
 #define to_spmi_driver(d) container_of(d, struct spmi_driver, driver)
 
 /**
+ * struct spmi_resource: spmi_resource for one device_node
+ * @num_resources: number of resources for this device node
+ * @resources: array of resources for this device_node
+ * @of_node: device_node of the resource in question
+ */
+struct spmi_resource {
+	struct resource		*resource;
+	u32			num_resources;
+	struct device_node	*of_node;
+};
+
+/**
  * Client/device handle (struct spmi_device):
  * ------------------------------------------
- * This is the client/device handle returned when a SPMI device
- * is registered with a controller.
- * Pointer to this structure is used by client-driver as a handle.
- * @dev: driver model representation of the device.
- * @name: name of driver to use with this device.
- * @ctrl: SPMI controller managing the bus hosting this device.
- * @resource: array of resources for this device_node
- * @num_resources: number of resources for this device node
- * @sid: slave identifier.
+ *  This is the client/device handle returned when a SPMI device
+ *  is registered with a controller.
+ *  Pointer to this structure is used by client-driver as a handle.
+ *  @dev: Driver model representation of the device.
+ *  @name: Name of driver to use with this device.
+ *  @ctrl: SPMI controller managing the bus hosting this device.
+ *  @dev_node: array of SPMI resources - one entry per device_node.
+ *  @num_dev_node: number of device_node structures.
+ *  @sid: Slave Identifier.
  */
 struct spmi_device {
 	struct device		dev;
 	const char		*name;
 	struct spmi_controller	*ctrl;
-	struct resource		*resource;
-	u32			num_resources;
+	struct spmi_resource	*dev_node;
+	u32			num_dev_node;
 	u8			sid;
 };
 #define to_spmi_device(d) container_of(d, struct spmi_device, dev)
@@ -115,16 +127,16 @@
  * @slave_id: slave identifier.
  * @spmi_device: device to be registered with the SPMI framework.
  * @of_node: pointer to the OpenFirmware device node.
- * @num_resources: number of resources for this device node
- * @resource: array of resources for this device_node
+ * @dev_node: one spmi_resource for each device_node.
+ * @num_dev_node: number of device_node structures.
  * @platform_data: goes to spmi_device.dev.platform_data
  */
 struct spmi_boardinfo {
 	char			name[SPMI_NAME_SIZE];
 	uint8_t			slave_id;
 	struct device_node	*of_node;
-	u32			num_resources;
-	struct resource		*resource;
+	struct spmi_resource	*dev_node;
+	u32			num_dev_node;
 	const void		*platform_data;
 };
 
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 85c50b4..c84e974 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -34,7 +34,7 @@
 /*
  * Function prototypes.
  */
-void		svc_close_all(struct list_head *);
+void		svc_close_all(struct svc_serv *);
 int		svc_recv(struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6660c41..1ff6b62 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -472,7 +472,9 @@
 extern struct tty_struct *get_current_tty(void);
 extern void tty_default_fops(struct file_operations *fops);
 extern struct tty_struct *alloc_tty_struct(void);
-extern int tty_add_file(struct tty_struct *tty, struct file *file);
+extern int tty_alloc_file(struct file *file);
+extern void tty_add_file(struct tty_struct *tty, struct file *file);
+extern void tty_free_file(struct file *file);
 extern void free_tty_struct(struct tty_struct *tty);
 extern void initialize_tty_struct(struct tty_struct *tty,
 		struct tty_driver *driver, int idx);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 583ceb8..9db1a03 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 */
 
@@ -1226,6 +1233,7 @@
 	void *transfer_buffer;		/* (in) associated data buffer */
 	dma_addr_t transfer_dma;	/* (in) dma addr for transfer_buffer */
 	struct scatterlist *sg;		/* (in) scatter gather buffer list */
+	int num_mapped_sgs;		/* (internal) mapped sg entries */
 	int num_sgs;			/* (in) number of entries in the sg list */
 	u32 transfer_buffer_length;	/* (in) data buffer length */
 	u32 actual_length;		/* (return) actual transfer length */
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 81a9279..2b39f69 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -53,6 +53,7 @@
 #define USB_CDC_DMM_TYPE		0x14
 #define USB_CDC_OBEX_TYPE		0x15
 #define USB_CDC_NCM_TYPE		0x1a
+#define USB_CDC_MBB_TYPE		0x1b	/* mbb_desc */
 
 /* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
 struct usb_cdc_header_desc {
@@ -187,6 +188,21 @@
 	__le16	bcdNcmVersion;
 	__u8	bmNetworkCapabilities;
 } __attribute__ ((packed));
+
+/* "MBIM Functional Descriptor" */
+struct usb_cdc_mbb_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__le16	bcdMbbVersion;
+	__le16	wMaxControlMessage;
+	__u8	bNumberFilters;
+	__u8	bMaxFilterSize;
+	__le16	wMaxSegmentSize;
+	__u8	bmNetworkCapabilities;
+} __packed;
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -201,6 +217,7 @@
 
 #define USB_CDC_SEND_ENCAPSULATED_COMMAND	0x00
 #define USB_CDC_GET_ENCAPSULATED_RESPONSE	0x01
+#define USB_CDC_RESET_FUNCTION			0x05
 #define USB_CDC_REQ_SET_LINE_CODING		0x20
 #define USB_CDC_REQ_GET_LINE_CODING		0x21
 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE	0x22
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 736203b..247e35c 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 */
@@ -587,8 +613,26 @@
 } __attribute__ ((packed));
 
 #define USB_DT_SS_EP_COMP_SIZE		6
+
 /* Bits 4:0 of bmAttributes if this is a bulk endpoint */
-#define USB_SS_MAX_STREAMS(p)		(1 << ((p) & 0x1f))
+static inline int
+usb_ss_max_streams(const struct usb_ss_ep_comp_descriptor *comp)
+{
+	int		max_streams;
+
+	if (!comp)
+		return 0;
+
+	max_streams = comp->bmAttributes & 0x1f;
+
+	if (!max_streams)
+		return 0;
+
+	max_streams = 1 << max_streams;
+
+	return max_streams;
+}
+
 /* Bits 1:0 of bmAttributes if this is an isoc endpoint */
 #define USB_SS_MULT(p)			(1 + ((p) & 0x3))
 
@@ -617,8 +661,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/hcd.h b/include/linux/usb/hcd.h
index b43a097..5762463 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -178,7 +178,7 @@
 	 * this structure.
 	 */
 	unsigned long hcd_priv[0]
-			__attribute__ ((aligned(sizeof(unsigned long))));
+			__attribute__ ((aligned(sizeof(s64))));
 };
 
 /* 2.4 does this a bit differently ... */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 037cfe7..bb6a01d 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -183,6 +183,46 @@
 	struct msm_bus_scale_pdata *bus_scale_table;
 };
 
+/* Timeout (in msec) values (min - max) associated with OTG timers */
+
+#define TA_WAIT_VRISE	100	/* ( - 100)  */
+#define TA_WAIT_VFALL	500	/* ( - 1000) */
+
+/*
+ * This option is set for embedded hosts or OTG devices in which leakage
+ * currents are very minimal.
+ */
+#ifdef CONFIG_USB_OTG
+#define TA_WAIT_BCON	30000	/* (1100 - 30000) */
+#else
+#define TA_WAIT_BCON	-1
+#endif
+
+#define TA_AIDL_BDIS	500	/* (200 - ) */
+#define TA_BIDL_ADIS	155	/* (155 - 200) */
+#define TB_SRP_FAIL	6000	/* (5000 - 6000) */
+#define TB_ASE0_BRST	200	/* (155 - ) */
+
+/* TB_SSEND_SRP and TB_SE0_SRP are combined */
+#define TB_SRP_INIT	2000	/* (1500 - ) */
+
+#define TA_TST_MAINT	10100	/* (9900 - 10100) */
+#define TB_TST_SRP	3000	/* ( - 5000) */
+#define TB_TST_CONFIG	300
+
+/* Timeout variables */
+
+#define A_WAIT_VRISE	0
+#define A_WAIT_VFALL	1
+#define A_WAIT_BCON	2
+#define A_AIDL_BDIS	3
+#define A_BIDL_ADIS	4
+#define B_SRP_FAIL	5
+#define B_ASE0_BRST	6
+#define A_TST_MAINT	7
+#define B_TST_SRP	8
+#define B_TST_CONFIG	9
+
 /**
  * struct msm_otg: OTG driver data. Shared by HCD and DCD.
  * @otg: USB OTG Transceiver structure.
@@ -229,6 +269,18 @@
 #define ID_A		2
 #define ID_B		3
 #define ID_C		4
+#define A_BUS_DROP	5
+#define A_BUS_REQ	6
+#define A_SRP_DET	7
+#define A_VBUS_VLD	8
+#define B_CONN		9
+#define ADP_CHANGE	10
+#define POWER_UP	11
+#define A_CLR_ERR	12
+#define A_BUS_RESUME	13
+#define A_BUS_SUSPEND	14
+#define A_CONN		15
+#define B_BUS_REQ	16
 	unsigned long inputs;
 	struct work_struct sm_work;
 	atomic_t in_lpm;
@@ -243,7 +295,7 @@
 	unsigned mA_port;
 	struct timer_list id_timer;
 	unsigned long caps;
-	struct clk *xo_handle;
+	struct msm_xo_voter *xo_handle;
 	uint32_t bus_perf_client;
 	/*
 	 * Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
@@ -269,6 +321,10 @@
 #define PHY_OTG_COMP_DISABLED		BIT(2)
 	struct pm_qos_request_list pm_qos_req_dma;
 	int reset_counter;
+	unsigned long b_last_se0_sess;
+	unsigned long tmouts;
+	u8 active_tmout;
+	struct hrtimer timer;
 };
 
 struct msm_hsic_host_platform_data {
@@ -277,6 +333,11 @@
 	unsigned hub_reset;
 };
 
+struct msm_usb_host_platform_data {
+	unsigned int power_budget;
+	unsigned int dock_connect_irq;
+};
+
 struct usb_bam_pipe_connect {
 	u32 src_phy_addr;
 	int src_pipe_index;
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index fcd91da..8a05136 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -33,6 +33,8 @@
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK         (3 << 30)
 #define PORTSC_PTS_ULPI         (3 << 30)
+#define PORTSC_CSC              (1 << 1)
+#define PORTSC_CCS              (1 << 0)
 
 #define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
 #define ULPI_RUN              (1 << 30)
@@ -54,14 +56,26 @@
 #define PHY_IDHV_INTEN          (1 << 8) /* PHY ID HV interrupt */
 #define PHY_OTGSESSVLDHV_INTEN  (1 << 9) /* PHY Session Valid HV int. */
 
+#define STS_PCI                 (1 << 2) /* R/WC - Port Change Detect */
+#define STS_URI                 (1 << 6) /* R/WC - RESET recv'd */
+#define STS_SLI                 (1 << 8) /* R/WC - suspend state entered */
+
 /* OTG definitions */
 #define OTGSC_INTSTS_MASK	(0x7f << 16)
 #define OTGSC_IDPU		(1 << 5)
+#define OTGSC_INTR_MASK		(0x7f << 24)
+#define OTGSC_HADP		(1 << 6)
 #define OTGSC_ID		(1 << 8)
 #define OTGSC_BSV		(1 << 11)
 #define OTGSC_IDIS		(1 << 16)
 #define OTGSC_BSVIS		(1 << 19)
 #define OTGSC_IDIE		(1 << 24)
 #define OTGSC_BSVIE		(1 << 27)
+#define OTGSC_DPIE		(1 << 30)
+#define OTGSC_DPIS		(1 << 22)
+
+/* OTG interrupt status mask */
+#define OTG_USBSTS_MASK		(STS_PCI | STS_URI | STS_SLI | PHY_ALT_INT)
+#define OTG_OTGSTS_MASK		(OTGSC_IDIS | OTGSC_BSVIS | OTGSC_DPIS)
 
 #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
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/linux/usb/ulpi.h b/include/linux/usb/ulpi.h
index 9595796..540a74c 100644
--- a/include/linux/usb/ulpi.h
+++ b/include/linux/usb/ulpi.h
@@ -145,6 +145,7 @@
 #define ULPI_INT_SESS_VALID			(1 << 2)
 #define ULPI_INT_SESS_END			(1 << 3)
 #define ULPI_INT_IDGRD				(1 << 4)
+#define ULPI_INT_DP				(1 << 7)
 
 /* Debug */
 #define ULPI_DEBUG_LINESTATE0			(1 << 0)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index ebd2b75..175b54f 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1089,6 +1089,7 @@
 #define V4L2_CTRL_FLAG_NEXT_CTRL	0x80000000
 
 /*  User-class control IDs defined by V4L2 */
+#define V4L2_CID_MAX_CTRLS		1024
 #define V4L2_CID_BASE			(V4L2_CTRL_CLASS_USER | 0x900)
 #define V4L2_CID_USER_BASE 		V4L2_CID_BASE
 /*  IDs reserved for driver specific controls */
@@ -1344,6 +1345,7 @@
 enum v4l2_mpeg_video_header_mode {
 	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
 	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
+	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME		= 2,
 
 };
 #define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 9332e52..687fb11 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -13,6 +13,7 @@
 #define VM_MAP		0x00000004	/* vmap()ed pages */
 #define VM_USERMAP	0x00000008	/* suitable for remap_vmalloc_range */
 #define VM_VPAGES	0x00000010	/* buffer for pages was vmalloc'ed */
+#define VM_UNLIST	0x00000020	/* vm_struct is not listed in vmlist */
 /* bits [20..32] reserved for arch specific ioremap internals */
 
 /*
diff --git a/include/media/Kbuild b/include/media/Kbuild
index f4a8a86..a60b86c 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -3,3 +3,4 @@
 header-y += msm_camera.h
 header-y += msm_isp.h
 header-y += msm_gemini.h
+header-y += msm_v4l2_overlay.h
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
index 3eab611..61a7fbb 100644
--- a/include/media/gpio-ir-recv.h
+++ b/include/media/gpio-ir-recv.h
@@ -16,7 +16,6 @@
 struct gpio_ir_recv_platform_data {
 	unsigned int gpio_nr;
 	bool active_low;
-	bool can_wakeup;
 };
 
 #endif /* __GPIO_IR_RECV_H__ */
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 1cd8448..20d3ef9 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -53,9 +53,16 @@
 	VCD_PWR_STATE_SLEEP,
 };
 
+struct vcd_aspect_ratio {
+	u32 aspect_ratio;
+	u32 extended_par_width;
+	u32 extended_par_height;
+};
+
 struct vcd_frame_data {
 	u8 *virtual;
 	u8 *physical;
+	u32 ion_flag;
 	u32 alloc_len;
 	u32 data_len;
 	u32 offset;
@@ -69,6 +76,8 @@
 	u32 intrlcd_ip_frm_tag;
 	u8 *desc_buf;
 	u32 desc_size;
+	struct ion_handle *buff_ion_handle;
+	struct vcd_aspect_ratio aspect_ratio_info;
 };
 
 struct vcd_sequence_hdr {
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 0279216..0b501ea 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -50,6 +50,7 @@
 #define VCD_I_META_BUFFER_MODE (VCD_START_BASE + 0x22)
 #define VCD_I_DISABLE_DMX (VCD_START_BASE + 0x23)
 #define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
+#define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -347,4 +348,8 @@
 	int alignment;
 };
 
+struct vcd_property_sps_pps_for_idr_enable {
+	u32 sps_pps_for_idr_enable_flag;
+};
+
 #endif
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
index 60cc35f..c681213 100644
--- a/include/media/msm/vidc_init.h
+++ b/include/media/msm/vidc_init.h
@@ -14,7 +14,8 @@
 #ifndef VIDC_INIT_H
 #define VIDC_INIT_H
 #include <linux/ion.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_property.h>
 
 #define VIDC_MAX_NUM_CLIENTS 4
 #define MAX_VIDEO_NUM_OF_BUFF 100
@@ -28,6 +29,7 @@
 	unsigned long user_vaddr;
 	unsigned long kernel_vaddr;
 	unsigned long phy_addr;
+	unsigned long buff_ion_flag;
 	struct ion_handle *buff_ion_handle;
 	int pmem_fd;
 	struct file *file;
@@ -63,6 +65,10 @@
 void __iomem *vidc_get_ioaddr(void);
 int vidc_load_firmware(void);
 void vidc_release_firmware(void);
+u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
+		enum buffer_dir buffer, int pmem_fd,
+		unsigned long kvaddr, int index,
+		struct ion_handle **buff_handle);
 u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
 	enum buffer_dir buffer, u32 search_with_user_vaddr,
 	unsigned long *user_vaddr, unsigned long *kernel_vaddr,
@@ -73,9 +79,16 @@
 	unsigned long *kernel_vaddr, int pmem_fd,
 	unsigned long buffer_addr_offset,
 	unsigned int max_num_buffers, unsigned long length);
+u32 vidc_insert_addr_table_kernel(struct video_client_ctx *client_ctx,
+	enum buffer_dir buffer, unsigned long user_vaddr,
+	unsigned long kernel_vaddr, unsigned long phys_addr,
+	unsigned int max_num_buffers,
+	unsigned long length);
 u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
 	enum buffer_dir buffer, unsigned long user_vaddr,
 	unsigned long *kernel_vaddr);
+void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
+		enum buffer_dir buffer);
 
 u32 vidc_timer_create(void (*timer_handler)(void *),
 	void *user_data, void **timer_handle);
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index e0a04dc..a448df6 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 */
 
@@ -641,6 +642,8 @@
 	uint32_t status_bits;
 	unsigned long buffer;
 	int fd;
+	int length;
+	struct ion_handle *handle;
 	uint32_t frame_id;
 };
 #define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0
@@ -1137,6 +1140,10 @@
 	uint32_t f_pix_den;
 	uint32_t total_f_dist_num;
 	uint32_t total_f_dist_den;
+	uint32_t hor_view_angle_num;
+	uint32_t hor_view_angle_den;
+	uint32_t ver_view_angle_num;
+	uint32_t ver_view_angle_den;
 };
 
 struct msm_actuator_cfg_data {
@@ -1185,7 +1192,6 @@
 	uint32_t s_mount_angle[MSM_MAX_CAMERA_SENSORS];
 	const char *video_dev_name[MSM_MAX_CAMERA_SENSORS];
 	enum sensor_type_t sensor_type[MSM_MAX_CAMERA_SENSORS];
-
 };
 
 struct msm_cam_config_dev_info {
@@ -1220,6 +1226,13 @@
 	uint8_t flash_enabled;
 	int8_t total_steps;
 	uint8_t support_3d;
+	enum flash_type flashtype;
+	enum sensor_type_t sensor_type;
+	uint32_t pxlcode; /* enum v4l2_mbus_pixelcode */
+	uint32_t camera_type; /* msm_camera_type */
+	int mount_angle;
+	uint32_t max_width;
+	uint32_t max_height;
 };
 
 #define V4L2_SINGLE_PLANE	0
@@ -1247,4 +1260,8 @@
 	uint8_t vpe_can_use;
 };
 
+#define QCAMERA_NAME "qcamera"
+#define QCAMERA_DEVICE_GROUP_ID 1
+#define QCAMERA_VNODE_GROUP_ID 2
+
 #endif /* __LINUX_MSM_CAMERA_H */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 07784e2..cb728a0 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -199,6 +199,7 @@
 #define VFE_CMD_SCALE_OUTPUT2_CONFIG                    135
 #define VFE_CMD_CAPTURE_RAW                             136
 #define VFE_CMD_STOP_LIVESHOT                           137
+#define VFE_CMD_RECONFIG_VFE                            138
 
 struct msm_isp_cmd {
 	int32_t  id;
@@ -241,8 +242,17 @@
 #define VPE_SCALER_CONFIG_LEN           260
 #define VPE_DIS_OFFSET_CFG_LEN          12
 
-#define IMEM_Y_OFFSET  0x2E000000
-#define IMEM_CBCR_OFFSET  0x2E00FA00
+
+#define CAPTURE_WIDTH          1280
+#define IMEM_Y_SIZE            (CAPTURE_WIDTH*16)
+#define IMEM_CBCR_SIZE         (CAPTURE_WIDTH*8)
+
+#define IMEM_Y_PING_OFFSET     0x2E000000
+#define IMEM_CBCR_PING_OFFSET  (IMEM_Y_PING_OFFSET + IMEM_Y_SIZE)
+
+#define IMEM_Y_PONG_OFFSET     (IMEM_CBCR_PING_OFFSET + IMEM_CBCR_SIZE)
+#define IMEM_CBCR_PONG_OFFSET  (IMEM_Y_PONG_OFFSET + IMEM_Y_SIZE)
+
 
 struct msm_vpe_op_mode_cfg {
 	uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN];
diff --git a/include/media/msm_v4l2_overlay.h b/include/media/msm_v4l2_overlay.h
new file mode 100644
index 0000000..c83cfb7
--- /dev/null
+++ b/include/media/msm_v4l2_overlay.h
@@ -0,0 +1,9 @@
+#ifndef LINUX_MSM_V4L2_OVERLAY
+#define LINUX_MSM_V4L2_OVERLAY
+
+#include <linux/videodev2.h>
+
+#define VIDIOC_MSM_USERPTR_QBUF	\
+_IOWR('V', BASE_VIDIOC_PRIVATE, struct v4l2_buffer)
+
+#endif
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 34a21bd..de2b356 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -675,7 +675,7 @@
 
 /* Band limits */
 #define REGION_US_EU_BAND_LOW              87500
-#define REGION_US_EU_BAND_HIGH             107900
+#define REGION_US_EU_BAND_HIGH             108000
 #define REGION_JAPAN_STANDARD_BAND_LOW     76000
 #define REGION_JAPAN_STANDARD_BAND_HIGH    90000
 #define REGION_JAPAN_WIDE_BAND_LOW         90000
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index bedfc7c..381f5c4 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -152,7 +152,7 @@
 	* Here we have IOCTl's that are specific to IRIS
 	* (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28)
 	*/
-	V4L2_CID_PRIVATE_SOFT_MUTE, /* 0x800001E*/
+	V4L2_CID_PRIVATE_SOFT_MUTE,/* 0x800001E*/
 	V4L2_CID_PRIVATE_RIVA_ACCS_ADDR,
 	V4L2_CID_PRIVATE_RIVA_ACCS_LEN,
 	V4L2_CID_PRIVATE_RIVA_PEEK,
@@ -162,16 +162,16 @@
 	V4L2_CID_PRIVATE_SSBI_POKE,
 	V4L2_CID_PRIVATE_TX_TONE,
 	V4L2_CID_PRIVATE_RDS_GRP_COUNTERS,
-	V4L2_CID_PRIVATE_SET_NOTCH_FILTER, /* 0x8000028 */
+	V4L2_CID_PRIVATE_SET_NOTCH_FILTER,/* 0x8000028 */
 
-	V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, /* 0x8000029 */
-	V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION, /* 0x800002A : IRIS command */
-	V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, /* 0x800002B */
-
-	V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD =
-		V4L2_CTRL_CLASS_USER + 0x92B,
-	V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD =
-		V4L2_CTRL_CLASS_USER + 0x92C
+	V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,/* 0x8000029 */
+	V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION,/* 0x800002A : IRIS */
+	V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,/* 0x800002B */
+	V4L2_CID_PRIVATE_IRIS_GET_SINR, /* 0x800002C : IRIS */
+	V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, /* 0x800002D */
+	V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */
+	V4L2_CID_PRIVATE_SINR_THRESHOLD,  /* 0x800002F : IRIS */
+	V4L2_CID_PRIVATE_SINR_SAMPLES,  /* 0x8000030 : IRIS */
 
 };
 
@@ -349,6 +349,7 @@
 	(reg = (reg & ~mask) | (((val) << offset) & mask))
 #define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset)
 #define RSH_DATA(val, offset)    ((val) >> (offset))
+#define LSH_DATA(val, offset)    ((val) << (offset))
 #define GET_ABS_VAL(val)        ((val) & (0xFF))
 
 enum radio_state_t {
@@ -471,7 +472,8 @@
 	TAVARUA_EVT_NEW_SRCH_LIST,
 	TAVARUA_EVT_NEW_AF_LIST,
 	TAVARUA_EVT_TXRDSDAT,
-	TAVARUA_EVT_TXRDSDONE
+	TAVARUA_EVT_TXRDSDONE,
+	TAVARUA_EVT_RADIO_DISABLED
 };
 
 enum tavarua_region_t {
diff --git a/include/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 0c7cf8c..822dd69 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.h
@@ -56,8 +56,6 @@
 	int dirty;
 	unsigned int count;
 	void *alloc_ctx;
-	struct msm_mapped_buffer *msm_buffer;
-	int subsys_id;
 	unsigned long mapped_phyaddr;
 	struct ion_handle *ion_handle;
 	struct ion_client *client;
diff --git a/include/net/arp.h b/include/net/arp.h
index 91f0568..fb0eb90 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -16,6 +16,7 @@
 			 const unsigned char *dest_hw,
 			 const unsigned char *src_hw, const unsigned char *th);
 extern int	arp_bind_neighbour(struct dst_entry *dst);
+extern struct neighbour *__arp_bind_neighbour(struct dst_entry *dst, __be32 nexthop);
 extern int	arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
 extern void	arp_ifdown(struct net_device *dev);
 
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index 0a2849a..ec517b0 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -1,5 +1,5 @@
 /*
-   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
@@ -115,7 +115,7 @@
 void amp_exit(void);
 
 /* L2CAP-AMP fixed channel interface */
-void amp_conn_ind(struct l2cap_conn *conn, struct sk_buff *skb);
+void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb);
 
 /* L2CAP-AMP link interface */
 void amp_create_physical(struct l2cap_conn *conn, struct sock *sk);
@@ -256,7 +256,7 @@
 };
 struct amp_work_conn_ind {
 	struct work_struct work;
-	struct l2cap_conn *conn;
+	struct hci_conn *hcon;
 	struct sk_buff *skb;
 };
 struct amp_work_create_physical {
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index cd85855..eb89f4b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -869,6 +869,17 @@
 	__le16   num_blocks;
 } __packed;
 
+#define HCI_OP_READ_RSSI	0x1405
+struct hci_cp_read_rssi {
+	__le16   handle;
+} __packed;
+
+struct hci_rp_read_rssi {
+	__u8     status;
+	__le16   handle;
+	__s8     rssi;
+} __packed;
+
 #define HCI_OP_READ_LOCAL_AMP_INFO	0x1409
 struct hci_rp_read_local_amp_info {
 	__u8     status;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 164d3b4..d98a79d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -310,12 +310,17 @@
 	__u8		remote_oob;
 	__u8		remote_auth;
 
+	__s8	rssi_threshold;
+	__u16	rssi_update_interval;
+	__u8	rssi_update_thresh_exceed;
+
 	unsigned int	sent;
 
 	struct sk_buff_head data_q;
 
 	struct timer_list disc_timer;
 	struct timer_list idle_timer;
+	struct delayed_work	rssi_update_work;
 
 	struct work_struct work_add;
 	struct work_struct work_del;
@@ -570,7 +575,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);
@@ -581,10 +586,7 @@
 }
 int hci_chan_put(struct hci_chan *chan);
 
-struct hci_chan *hci_chan_accept(struct hci_conn *hcon,
-				struct hci_ext_fs *tx_fs,
-				struct hci_ext_fs *rx_fs);
-struct hci_chan *hci_chan_create(struct hci_conn *hcon,
+struct hci_chan *hci_chan_create(struct hci_chan *chan,
 				struct hci_ext_fs *tx_fs,
 				struct hci_ext_fs *rx_fs);
 void hci_chan_modify(struct hci_chan *chan,
@@ -607,6 +609,10 @@
 void hci_conn_hold_device(struct hci_conn *conn);
 void hci_conn_put_device(struct hci_conn *conn);
 
+void hci_conn_set_rssi_reporter(struct hci_conn *conn,
+		s8 rssi_threshold, u16 interval, u8 updateOnThreshExceed);
+void hci_conn_unset_rssi_reporter(struct hci_conn *conn);
+
 static inline void hci_conn_hold(struct hci_conn *conn)
 {
 	atomic_inc(&conn->refcnt);
@@ -751,7 +757,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 +815,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);
@@ -1037,6 +1045,8 @@
 								u8 status);
 int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
 				u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir);
+void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
+				u16 handle, u8 status);
 int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name);
 void mgmt_inquiry_started(u16 index);
 void mgmt_inquiry_complete_evt(u16 index, u8 status);
@@ -1049,6 +1059,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)
@@ -1087,4 +1098,6 @@
 void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
 void hci_le_ltk_neg_reply(struct hci_conn *conn);
 
+void hci_read_rssi(struct hci_conn *conn);
+
 #endif /* __HCI_CORE_H */
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index d5c4189..b903c5c 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -51,7 +51,7 @@
 
 #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
 #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
-#define L2CAP_MOVE_TIMEOUT		(2*HZ)  /*  2 seconds */
+#define L2CAP_MOVE_TIMEOUT		(4*HZ)  /*  4 seconds */
 #define L2CAP_MOVE_ERTX_TIMEOUT		(60*HZ) /* 60 seconds */
 
 /* L2CAP socket address */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 9e79fb3..e34c425 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -161,7 +161,6 @@
 struct mgmt_cp_pair_device {
 	bdaddr_t bdaddr;
 	__u8 io_cap;
-	__u8 ssp_cap;
 } __packed;
 struct mgmt_rp_pair_device {
 	bdaddr_t bdaddr;
@@ -234,6 +233,19 @@
 	__u8 enable;
 } __packed;
 
+#define MGMT_OP_SET_RSSI_REPORTER		0x0022
+struct mgmt_cp_set_rssi_reporter {
+	bdaddr_t	bdaddr;
+	__s8		rssi_threshold;
+	__le16	interval;
+	__u8		updateOnThreshExceed;
+} __packed;
+
+#define MGMT_OP_UNSET_RSSI_REPORTER		0x0023
+struct mgmt_cp_unset_rssi_reporter {
+	bdaddr_t	bdaddr;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
@@ -355,3 +367,15 @@
 	__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;
+
+#define MGMT_EV_RSSI_UPDATE		0x0020
+struct mgmt_ev_rssi_update {
+	bdaddr_t	bdaddr;
+	__s8			rssi;
+} __packed;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8be88bb..4898ea2 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -847,9 +847,11 @@
  * @n_channels: total number of channels to scan
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
+ * @rates: bitmap of rates to advertise for each band
  * @wiphy: the wiphy this was for
  * @dev: the interface
  * @aborted: (internal) scan request was notified as aborted
+ * @no_cck: used to send probe requests at non CCK rate in 2GHz band
  */
 struct cfg80211_scan_request {
 	struct cfg80211_ssid *ssids;
@@ -858,10 +860,13 @@
 	const u8 *ie;
 	size_t ie_len;
 
+	u32 rates[IEEE80211_NUM_BANDS];
+
 	/* internal */
 	struct wiphy *wiphy;
 	struct net_device *dev;
 	bool aborted;
+	bool no_cck;
 
 	/* keep last */
 	struct ieee80211_channel *channels[0];
diff --git a/include/net/dst.h b/include/net/dst.h
index e12ddfb..d020134 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -37,7 +37,7 @@
 	unsigned long		_metrics;
 	unsigned long		expires;
 	struct dst_entry	*path;
-	struct neighbour	*neighbour;
+	struct neighbour __rcu	*_neighbour;
 	struct hh_cache		*hh;
 #ifdef CONFIG_XFRM
 	struct xfrm_state	*xfrm;
@@ -86,6 +86,21 @@
 	};
 };
 
+static inline struct neighbour *dst_get_neighbour(struct dst_entry *dst)
+{
+	return rcu_dereference(dst->_neighbour);
+}
+
+static inline struct neighbour *dst_get_neighbour_raw(struct dst_entry *dst)
+{
+	return rcu_dereference_raw(dst->_neighbour);
+}
+
+static inline void dst_set_neighbour(struct dst_entry *dst, struct neighbour *neigh)
+{
+	rcu_assign_pointer(dst->_neighbour, neigh);
+}
+
 extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
 extern const u32 dst_default_metrics[RTAX_MAX];
 
@@ -371,8 +386,14 @@
 
 static inline void dst_confirm(struct dst_entry *dst)
 {
-	if (dst)
-		neigh_confirm(dst->neighbour);
+	if (dst) {
+		struct neighbour *n;
+
+		rcu_read_lock();
+		n = dst_get_neighbour(dst);
+		neigh_confirm(n);
+		rcu_read_unlock();
+	}
 }
 
 static inline void dst_link_failure(struct sk_buff *skb)
diff --git a/include/net/flow.h b/include/net/flow.h
index c6d5fe5..32359fd 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -7,6 +7,7 @@
 #ifndef _NET_FLOW_H
 #define _NET_FLOW_H
 
+#include <linux/socket.h>
 #include <linux/in6.h>
 #include <asm/atomic.h>
 
@@ -68,7 +69,7 @@
 #define fl4_ipsec_spi		uli.spi
 #define fl4_mh_type		uli.mht.type
 #define fl4_gre_key		uli.gre_key
-};
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
 
 static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
 				      __u32 mark, __u8 tos, __u8 scope,
@@ -112,7 +113,7 @@
 #define fl6_ipsec_spi		uli.spi
 #define fl6_mh_type		uli.mht.type
 #define fl6_gre_key		uli.gre_key
-};
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
 
 struct flowidn {
 	struct flowi_common	__fl_common;
@@ -127,7 +128,7 @@
 	union flowi_uli		uli;
 #define fld_sport		uli.ports.sport
 #define fld_dport		uli.ports.dport
-};
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
 
 struct flowi {
 	union {
@@ -161,6 +162,24 @@
 	return container_of(fldn, struct flowi, u.dn);
 }
 
+typedef unsigned long flow_compare_t;
+
+static inline size_t flow_key_size(u16 family)
+{
+	switch (family) {
+	case AF_INET:
+		BUILD_BUG_ON(sizeof(struct flowi4) % sizeof(flow_compare_t));
+		return sizeof(struct flowi4) / sizeof(flow_compare_t);
+	case AF_INET6:
+		BUILD_BUG_ON(sizeof(struct flowi6) % sizeof(flow_compare_t));
+		return sizeof(struct flowi6) / sizeof(flow_compare_t);
+	case AF_DECnet:
+		BUILD_BUG_ON(sizeof(struct flowidn) % sizeof(flow_compare_t));
+		return sizeof(struct flowidn) / sizeof(flow_compare_t);
+	}
+	return 0;
+}
+
 #define FLOW_DIR_IN	0
 #define FLOW_DIR_OUT	1
 #define FLOW_DIR_FWD	2
diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h
index 3419bf5..d55f434 100644
--- a/include/net/netns/generic.h
+++ b/include/net/netns/generic.h
@@ -41,6 +41,7 @@
 	ptr = ng->ptr[id - 1];
 	rcu_read_unlock();
 
+	BUG_ON(!ptr);
 	return ptr;
 }
 #endif
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 7df327a..c388421 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -236,6 +236,9 @@
 	 * bits is an indicator of when to send and window update SACK.
 	 */
 	int rwnd_update_shift;
+
+	/* Threshold for autoclose timeout, in seconds. */
+	unsigned long max_autoclose;
 } sctp_globals;
 
 #define sctp_rto_initial		(sctp_globals.rto_initial)
@@ -271,6 +274,7 @@
 #define sctp_auth_enable		(sctp_globals.auth_enable)
 #define sctp_checksum_disable		(sctp_globals.checksum_disable)
 #define sctp_rwnd_upd_shift		(sctp_globals.rwnd_update_shift)
+#define sctp_max_autoclose		(sctp_globals.max_autoclose)
 
 /* SCTP Socket type: UDP or TCP style. */
 typedef enum {
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 097ba39..85da871 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -61,6 +61,7 @@
 #define RT_PROXY_PORT_001_TX	0x2001    /* index = 31 */
 
 #define AFE_PORT_INVALID 0xFFFF
+#define SLIMBUS_INVALID AFE_PORT_INVALID
 
 #define AFE_PORT_CMD_START 0x000100ca
 
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/include/sound/soc.h b/include/sound/soc.h
index 3fffcc5..8d52423 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -368,6 +368,8 @@
 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
 		     struct snd_soc_jack *jack);
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
+void snd_soc_jack_report_no_dapm(struct snd_soc_jack *jack, int status,
+				 int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
 			  struct snd_soc_jack_pin *pins);
 void snd_soc_jack_notifier_register(struct snd_soc_jack *jack,
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 561ac99..0fe6679 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -36,6 +36,7 @@
 #define TRANSPORT_SENSE_BUFFER			SCSI_SENSE_BUFFERSIZE
 /* Used by transport_send_check_condition_and_sense() */
 #define SPC_SENSE_KEY_OFFSET			2
+#define SPC_ADD_SENSE_LEN_OFFSET		7
 #define SPC_ASC_KEY_OFFSET			12
 #define SPC_ASCQ_KEY_OFFSET			13
 #define TRANSPORT_IQN_LEN			224
diff --git a/include/xen/interface/io/xs_wire.h b/include/xen/interface/io/xs_wire.h
index 99fcffb..454ee26 100644
--- a/include/xen/interface/io/xs_wire.h
+++ b/include/xen/interface/io/xs_wire.h
@@ -84,4 +84,7 @@
     XENSTORE_RING_IDX rsp_cons, rsp_prod;
 };
 
+/* Violating this is very bad.  See docs/misc/xenstore.txt. */
+#define XENSTORE_PAYLOAD_MAX 4096
+
 #endif /* _XS_WIRE_H */
diff --git a/init/do_mounts.c b/init/do_mounts.c
index c0851a8..ef6478f 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -360,15 +360,42 @@
 }
  
 #ifdef CONFIG_ROOT_NFS
+
+#define NFSROOT_TIMEOUT_MIN	5
+#define NFSROOT_TIMEOUT_MAX	30
+#define NFSROOT_RETRY_MAX	5
+
 static int __init mount_nfs_root(void)
 {
 	char *root_dev, *root_data;
+	unsigned int timeout;
+	int try, err;
 
-	if (nfs_root_data(&root_dev, &root_data) != 0)
+	err = nfs_root_data(&root_dev, &root_data);
+	if (err != 0)
 		return 0;
-	if (do_mount_root(root_dev, "nfs", root_mountflags, root_data) != 0)
-		return 0;
-	return 1;
+
+	/*
+	 * The server or network may not be ready, so try several
+	 * times.  Stop after a few tries in case the client wants
+	 * to fall back to other boot methods.
+	 */
+	timeout = NFSROOT_TIMEOUT_MIN;
+	for (try = 1; ; try++) {
+		err = do_mount_root(root_dev, "nfs",
+					root_mountflags, root_data);
+		if (err == 0)
+			return 1;
+		if (try > NFSROOT_RETRY_MAX)
+			break;
+
+		/* Wait, in case the server refused us immediately */
+		ssleep(timeout);
+		timeout <<= 1;
+		if (timeout > NFSROOT_TIMEOUT_MAX)
+			timeout = NFSROOT_TIMEOUT_MAX;
+	}
+	return 0;
 }
 #endif
 
diff --git a/init/main.c b/init/main.c
index d7211fa..d0f330b 100644
--- a/init/main.c
+++ b/init/main.c
@@ -347,6 +347,7 @@
 static noinline void __init_refok rest_init(void)
 {
 	int pid;
+	const struct sched_param param = { .sched_priority = 1 };
 
 	rcu_scheduler_starting();
 	/*
@@ -360,6 +361,7 @@
 	rcu_read_lock();
 	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
 	rcu_read_unlock();
+	sched_setscheduler_nocheck(kthreadd_task, SCHED_FIFO, &param);
 	complete(&kthreadd_done);
 
 	/*
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 241b74a..5083a09 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1176,10 +1176,10 @@
 
 	/*
 	 * If the 'all' option was specified select all the subsystems,
-	 * otherwise 'all, 'none' and a subsystem name options were not
-	 * specified, let's default to 'all'
+	 * otherwise if 'none', 'name=' and a subsystem name options
+	 * were not specified, let's default to 'all'
 	 */
-	if (all_ss || (!all_ss && !one_ss && !opts->none)) {
+	if (all_ss || (!one_ss && !opts->none && !opts->name)) {
 		for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
 			struct cgroup_subsys *ss = subsys[i];
 			if (ss == NULL)
@@ -2105,11 +2105,6 @@
 			continue;
 		/* get old css_set pointer */
 		task_lock(tsk);
-		if (tsk->flags & PF_EXITING) {
-			/* ignore this task if it's going away */
-			task_unlock(tsk);
-			continue;
-		}
 		oldcg = tsk->cgroups;
 		get_css_set(oldcg);
 		task_unlock(tsk);
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index 6ebda1d..dfb1e75 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -153,6 +153,13 @@
 	kfree(cgroup_freezer(cgroup));
 }
 
+/* task is frozen or will freeze immediately when next it gets woken */
+static bool is_task_frozen_enough(struct task_struct *task)
+{
+	return frozen(task) ||
+		(task_is_stopped_or_traced(task) && freezing(task));
+}
+
 /*
  * The call to cgroup_lock() in the freezer.state write method prevents
  * a write to that file racing against an attach, and hence the
@@ -239,7 +246,7 @@
 	cgroup_iter_start(cgroup, &it);
 	while ((task = cgroup_iter_next(cgroup, &it))) {
 		ntotal++;
-		if (frozen(task))
+		if (is_task_frozen_enough(task))
 			nfrozen++;
 	}
 
@@ -292,7 +299,7 @@
 	while ((task = cgroup_iter_next(cgroup, &it))) {
 		if (!freeze_task(task, true))
 			continue;
-		if (frozen(task))
+		if (is_task_frozen_enough(task))
 			continue;
 		if (!freezing(task) && !freezer_should_skip(task))
 			num_cant_freeze_now++;
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 4047707..eae3d9b 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -15,6 +15,7 @@
 #include <linux/stop_machine.h>
 #include <linux/mutex.h>
 #include <linux/gfp.h>
+#include <linux/suspend.h>
 
 #ifdef CONFIG_SMP
 /* Serializes the updates to cpu_online_mask, cpu_present_mask */
@@ -476,6 +477,79 @@
 	return 0;
 }
 core_initcall(alloc_frozen_cpus);
+
+/*
+ * Prevent regular CPU hotplug from racing with the freezer, by disabling CPU
+ * hotplug when tasks are about to be frozen. Also, don't allow the freezer
+ * to continue until any currently running CPU hotplug operation gets
+ * completed.
+ * To modify the 'cpu_hotplug_disabled' flag, we need to acquire the
+ * 'cpu_add_remove_lock'. And this same lock is also taken by the regular
+ * CPU hotplug path and released only after it is complete. Thus, we
+ * (and hence the freezer) will block here until any currently running CPU
+ * hotplug operation gets completed.
+ */
+void cpu_hotplug_disable_before_freeze(void)
+{
+	cpu_maps_update_begin();
+	cpu_hotplug_disabled = 1;
+	cpu_maps_update_done();
+}
+
+
+/*
+ * When tasks have been thawed, re-enable regular CPU hotplug (which had been
+ * disabled while beginning to freeze tasks).
+ */
+void cpu_hotplug_enable_after_thaw(void)
+{
+	cpu_maps_update_begin();
+	cpu_hotplug_disabled = 0;
+	cpu_maps_update_done();
+}
+
+/*
+ * When callbacks for CPU hotplug notifications are being executed, we must
+ * ensure that the state of the system with respect to the tasks being frozen
+ * or not, as reported by the notification, remains unchanged *throughout the
+ * duration* of the execution of the callbacks.
+ * Hence we need to prevent the freezer from racing with regular CPU hotplug.
+ *
+ * This synchronization is implemented by mutually excluding regular CPU
+ * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/
+ * Hibernate notifications.
+ */
+static int
+cpu_hotplug_pm_callback(struct notifier_block *nb,
+			unsigned long action, void *ptr)
+{
+	switch (action) {
+
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		cpu_hotplug_disable_before_freeze();
+		break;
+
+	case PM_POST_SUSPEND:
+	case PM_POST_HIBERNATION:
+		cpu_hotplug_enable_after_thaw();
+		break;
+
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return NOTIFY_OK;
+}
+
+
+int cpu_hotplug_pm_sync_init(void)
+{
+	pm_notifier(cpu_hotplug_pm_callback, 0);
+	return 0;
+}
+core_initcall(cpu_hotplug_pm_sync_init);
+
 #endif /* CONFIG_PM_SLEEP_SMP */
 
 /**
diff --git a/kernel/exit.c b/kernel/exit.c
index f2b321b..303bed2 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1553,8 +1553,15 @@
 	}
 
 	/* dead body doesn't have much to contribute */
-	if (p->exit_state == EXIT_DEAD)
+	if (unlikely(p->exit_state == EXIT_DEAD)) {
+		/*
+		 * But do not ignore this task until the tracer does
+		 * wait_task_zombie()->do_notify_parent().
+		 */
+		if (likely(!ptrace) && unlikely(ptrace_reparented(p)))
+			wo->notask_error = 0;
 		return 0;
+	}
 
 	/* slay zombie? */
 	if (p->exit_state == EXIT_ZOMBIE) {
diff --git a/kernel/futex.c b/kernel/futex.c
index 11cbe05..e6160fa 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -314,17 +314,29 @@
 #endif
 
 	lock_page(page_head);
+
+	/*
+	 * If page_head->mapping is NULL, then it cannot be a PageAnon
+	 * page; but it might be the ZERO_PAGE or in the gate area or
+	 * in a special mapping (all cases which we are happy to fail);
+	 * or it may have been a good file page when get_user_pages_fast
+	 * found it, but truncated or holepunched or subjected to
+	 * invalidate_complete_page2 before we got the page lock (also
+	 * cases which we are happy to fail).  And we hold a reference,
+	 * so refcount care in invalidate_complete_page's remove_mapping
+	 * prevents drop_caches from setting mapping to NULL beneath us.
+	 *
+	 * The case we do have to guard against is when memory pressure made
+	 * shmem_writepage move it from filecache to swapcache beneath us:
+	 * an unlikely race, but we do need to retry for page_head->mapping.
+	 */
 	if (!page_head->mapping) {
+		int shmem_swizzled = PageSwapCache(page_head);
 		unlock_page(page_head);
 		put_page(page_head);
-		/*
-		* ZERO_PAGE pages don't have a mapping. Avoid a busy loop
-		* trying to find one. RW mapping would have COW'd (and thus
-		* have a mapping) so this page is RO and won't ever change.
-		*/
-		if ((page_head == ZERO_PAGE(address)))
-			return -EFAULT;
-		goto again;
+		if (shmem_swizzled)
+			goto again;
+		return -EFAULT;
 	}
 
 	/*
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index ea64012..e972276 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -74,11 +74,17 @@
 
 	/*
 	 * Ensure the task is not frozen.
-	 * Also, when a freshly created task is scheduled once, changes
-	 * its state to TASK_UNINTERRUPTIBLE without having ever been
-	 * switched out once, it musn't be checked.
+	 * Also, skip vfork and any other user process that freezer should skip.
 	 */
-	if (unlikely(t->flags & PF_FROZEN || !switch_count))
+	if (unlikely(t->flags & (PF_FROZEN | PF_FREEZER_SKIP)))
+	    return;
+
+	/*
+	 * When a freshly created task is scheduled once, changes its state to
+	 * TASK_UNINTERRUPTIBLE without having ever been switched out once, it
+	 * musn't be checked.
+	 */
+	if (unlikely(!switch_count))
 		return;
 
 	if (switch_count != t->last_switch_count) {
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 1db1dc6..0097e89 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -646,8 +646,9 @@
 
 static int irq_wait_for_interrupt(struct irqaction *action)
 {
+	set_current_state(TASK_INTERRUPTIBLE);
+
 	while (!kthread_should_stop()) {
-		set_current_state(TASK_INTERRUPTIBLE);
 
 		if (test_and_clear_bit(IRQTF_RUNTHREAD,
 				       &action->thread_flags)) {
@@ -655,7 +656,9 @@
 			return 0;
 		}
 		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
 	}
+	__set_current_state(TASK_RUNNING);
 	return -1;
 }
 
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index 0e5ab4d..0e3b919 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -9,6 +9,7 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/syscore_ops.h>
 
 #include "internals.h"
 
@@ -39,25 +40,58 @@
 }
 EXPORT_SYMBOL_GPL(suspend_device_irqs);
 
-/**
- * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs()
- *
- * Enable all interrupt lines previously disabled by suspend_device_irqs() that
- * have the IRQS_SUSPENDED flag set.
- */
-void resume_device_irqs(void)
+static void resume_irqs(bool want_early)
 {
 	struct irq_desc *desc;
 	int irq;
 
 	for_each_irq_desc_reverse(irq, desc) {
 		unsigned long flags;
+		bool is_early = desc->action &&
+			desc->action->flags & IRQF_EARLY_RESUME;
+
+		if (is_early != want_early)
+			continue;
 
 		raw_spin_lock_irqsave(&desc->lock, flags);
 		__enable_irq(desc, irq, true);
 		raw_spin_unlock_irqrestore(&desc->lock, flags);
 	}
 }
+
+/**
+ * irq_pm_syscore_ops - enable interrupt lines early
+ *
+ * Enable all interrupt lines with %IRQF_EARLY_RESUME set.
+ */
+static void irq_pm_syscore_resume(void)
+{
+	resume_irqs(true);
+}
+
+static struct syscore_ops irq_pm_syscore_ops = {
+	.resume		= irq_pm_syscore_resume,
+};
+
+static int __init irq_pm_init_ops(void)
+{
+	register_syscore_ops(&irq_pm_syscore_ops);
+	return 0;
+}
+
+device_initcall(irq_pm_init_ops);
+
+/**
+ * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs()
+ *
+ * Enable all non-%IRQF_EARLY_RESUME interrupt lines previously
+ * disabled by suspend_device_irqs() that have the IRQS_SUSPENDED flag
+ * set as well as those with %IRQF_FORCE_RESUME.
+ */
+void resume_device_irqs(void)
+{
+	resume_irqs(false);
+}
 EXPORT_SYMBOL_GPL(resume_device_irqs);
 
 /**
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index aa57d5d..dc813a9 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -84,7 +84,9 @@
 	 */
 	action = desc->action;
 	if (!action || !(action->flags & IRQF_SHARED) ||
-	    (action->flags & __IRQF_TIMER) || !action->next)
+	    (action->flags & __IRQF_TIMER) ||
+	    (action->handler(irq, action->dev_id) == IRQ_HANDLED) ||
+	    !action->next)
 		goto out;
 
 	/* Already running on another processor */
@@ -115,7 +117,7 @@
 	struct irq_desc *desc;
 	int i, ok = 0;
 
-	if (atomic_inc_return(&irq_poll_active) == 1)
+	if (atomic_inc_return(&irq_poll_active) != 1)
 		goto out;
 
 	irq_poll_cpu = smp_processor_id();
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index a8ce450..e6f1f24 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -66,8 +66,9 @@
 		return;
 
 	jump_label_lock();
-	if (atomic_add_return(1, &key->enabled) == 1)
+	if (atomic_read(&key->enabled) == 0)
 		jump_label_update(key, JUMP_LABEL_ENABLE);
+	atomic_inc(&key->enabled);
 	jump_label_unlock();
 }
 
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 47613df..fabfe54 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -114,10 +114,12 @@
 	atomic_inc(&kmod_concurrent);
 	if (atomic_read(&kmod_concurrent) > max_modprobes) {
 		/* We may be blaming an innocent here, but unlikely */
-		if (kmod_loop_msg++ < 5)
+		if (kmod_loop_msg < 5) {
 			printk(KERN_ERR
 			       "request_module: runaway loop modprobe %s\n",
 			       module_name);
+			kmod_loop_msg++;
+		}
 		atomic_dec(&kmod_concurrent);
 		return -ENOMEM;
 	}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 7798181..9cdbf26 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -78,10 +78,10 @@
 static DEFINE_MUTEX(kprobe_mutex);
 static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
 static struct {
-	spinlock_t lock ____cacheline_aligned_in_smp;
+	raw_spinlock_t lock ____cacheline_aligned_in_smp;
 } kretprobe_table_locks[KPROBE_TABLE_SIZE];
 
-static spinlock_t *kretprobe_table_lock_ptr(unsigned long hash)
+static raw_spinlock_t *kretprobe_table_lock_ptr(unsigned long hash)
 {
 	return &(kretprobe_table_locks[hash].lock);
 }
@@ -1013,9 +1013,9 @@
 	hlist_del(&ri->hlist);
 	INIT_HLIST_NODE(&ri->hlist);
 	if (likely(rp)) {
-		spin_lock(&rp->lock);
+		raw_spin_lock(&rp->lock);
 		hlist_add_head(&ri->hlist, &rp->free_instances);
-		spin_unlock(&rp->lock);
+		raw_spin_unlock(&rp->lock);
 	} else
 		/* Unregistering */
 		hlist_add_head(&ri->hlist, head);
@@ -1026,19 +1026,19 @@
 __acquires(hlist_lock)
 {
 	unsigned long hash = hash_ptr(tsk, KPROBE_HASH_BITS);
-	spinlock_t *hlist_lock;
+	raw_spinlock_t *hlist_lock;
 
 	*head = &kretprobe_inst_table[hash];
 	hlist_lock = kretprobe_table_lock_ptr(hash);
-	spin_lock_irqsave(hlist_lock, *flags);
+	raw_spin_lock_irqsave(hlist_lock, *flags);
 }
 
 static void __kprobes kretprobe_table_lock(unsigned long hash,
 	unsigned long *flags)
 __acquires(hlist_lock)
 {
-	spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
-	spin_lock_irqsave(hlist_lock, *flags);
+	raw_spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
+	raw_spin_lock_irqsave(hlist_lock, *flags);
 }
 
 void __kprobes kretprobe_hash_unlock(struct task_struct *tsk,
@@ -1046,18 +1046,18 @@
 __releases(hlist_lock)
 {
 	unsigned long hash = hash_ptr(tsk, KPROBE_HASH_BITS);
-	spinlock_t *hlist_lock;
+	raw_spinlock_t *hlist_lock;
 
 	hlist_lock = kretprobe_table_lock_ptr(hash);
-	spin_unlock_irqrestore(hlist_lock, *flags);
+	raw_spin_unlock_irqrestore(hlist_lock, *flags);
 }
 
 static void __kprobes kretprobe_table_unlock(unsigned long hash,
        unsigned long *flags)
 __releases(hlist_lock)
 {
-	spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
-	spin_unlock_irqrestore(hlist_lock, *flags);
+	raw_spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
+	raw_spin_unlock_irqrestore(hlist_lock, *flags);
 }
 
 /*
@@ -1077,6 +1077,7 @@
 		/* Early boot.  kretprobe_table_locks not yet initialized. */
 		return;
 
+	INIT_HLIST_HEAD(&empty_rp);
 	hash = hash_ptr(tk, KPROBE_HASH_BITS);
 	head = &kretprobe_inst_table[hash];
 	kretprobe_table_lock(hash, &flags);
@@ -1085,7 +1086,6 @@
 			recycle_rp_inst(ri, &empty_rp);
 	}
 	kretprobe_table_unlock(hash, &flags);
-	INIT_HLIST_HEAD(&empty_rp);
 	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
 		hlist_del(&ri->hlist);
 		kfree(ri);
@@ -1650,18 +1650,22 @@
 
 	/*TODO: consider to only swap the RA after the last pre_handler fired */
 	hash = hash_ptr(current, KPROBE_HASH_BITS);
-	spin_lock_irqsave(&rp->lock, flags);
+	raw_spin_lock_irqsave(&rp->lock, flags);
 	if (!hlist_empty(&rp->free_instances)) {
 		ri = hlist_entry(rp->free_instances.first,
 				struct kretprobe_instance, hlist);
 		hlist_del(&ri->hlist);
-		spin_unlock_irqrestore(&rp->lock, flags);
+		raw_spin_unlock_irqrestore(&rp->lock, flags);
 
 		ri->rp = rp;
 		ri->task = current;
 
-		if (rp->entry_handler && rp->entry_handler(ri, regs))
+		if (rp->entry_handler && rp->entry_handler(ri, regs)) {
+			raw_spin_lock_irqsave(&rp->lock, flags);
+			hlist_add_head(&ri->hlist, &rp->free_instances);
+			raw_spin_unlock_irqrestore(&rp->lock, flags);
 			return 0;
+		}
 
 		arch_prepare_kretprobe(ri, regs);
 
@@ -1672,7 +1676,7 @@
 		kretprobe_table_unlock(hash, &flags);
 	} else {
 		rp->nmissed++;
-		spin_unlock_irqrestore(&rp->lock, flags);
+		raw_spin_unlock_irqrestore(&rp->lock, flags);
 	}
 	return 0;
 }
@@ -1708,7 +1712,7 @@
 		rp->maxactive = num_possible_cpus();
 #endif
 	}
-	spin_lock_init(&rp->lock);
+	raw_spin_lock_init(&rp->lock);
 	INIT_HLIST_HEAD(&rp->free_instances);
 	for (i = 0; i < rp->maxactive; i++) {
 		inst = kmalloc(sizeof(struct kretprobe_instance) +
@@ -1946,7 +1950,7 @@
 	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
 		INIT_HLIST_HEAD(&kprobe_table[i]);
 		INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
-		spin_lock_init(&(kretprobe_table_locks[i].lock));
+		raw_spin_lock_init(&(kretprobe_table_locks[i].lock));
 	}
 
 	/*
diff --git a/kernel/panic.c b/kernel/panic.c
index a136da2..564c7bc 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -242,8 +242,16 @@
 	 * Also we want to keep up lockdep for staging development and
 	 * post-warning case.
 	 */
-	if (flag != TAINT_CRAP && flag != TAINT_WARN && __debug_locks_off())
-		printk(KERN_WARNING "Disabling lock debugging due to kernel taint\n");
+	switch (flag) {
+	case TAINT_CRAP:
+	case TAINT_WARN:
+	case TAINT_FIRMWARE_WORKAROUND:
+		break;
+
+	default:
+		if (__debug_locks_off())
+			printk(KERN_WARNING "Disabling lock debugging due to kernel taint\n");
+	}
 
 	set_bit(flag, &tainted_mask);
 }
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..9b279cc 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -12,9 +12,12 @@
 #include <linux/string.h>
 #include <linux/resume-trace.h>
 #include <linux/workqueue.h>
+#include <linux/hrtimer.h>
 
 #include "power.h"
 
+#define MAX_BUF 100
+
 DEFINE_MUTEX(pm_mutex);
 
 #ifdef CONFIG_PM_SLEEP
@@ -23,6 +26,13 @@
 
 static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
 
+static void touch_event_fn(struct work_struct *work);
+static DECLARE_WORK(touch_event_struct, touch_event_fn);
+
+static struct hrtimer tc_ev_timer;
+static int tc_ev_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 +77,81 @@
 
 power_attr(pm_async);
 
+static ssize_t
+touch_event_show(struct kobject *kobj,
+		 struct kobj_attribute *attr, char *buf)
+{
+	if (tc_ev_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(&tc_ev_timer);
+	tc_ev_processed = 0;
+
+	/* set a timer to notify the userspace to stop processing
+	 * touch event
+	 */
+	hrtimer_start(&tc_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 void touch_event_fn(struct work_struct *work)
+{
+	/* wakeup the userspace poll */
+	tc_ev_processed = 1;
+	sysfs_notify(power_kobj, NULL, "touch_event");
+
+	return;
+}
+
+static enum hrtimer_restart tc_ev_stop(struct hrtimer *hrtimer)
+{
+
+	schedule_work(&touch_event_struct);
+
+	return HRTIMER_NORESTART;
+}
+
 #ifdef CONFIG_PM_DEBUG
 int pm_test_level = TEST_NONE;
 
@@ -313,7 +398,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 +445,12 @@
 		return error;
 	hibernate_image_size_init();
 	hibernate_reserved_size_init();
+
+	touch_evt_timer_val = ktime_set(2, 0);
+	hrtimer_init(&tc_ev_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	tc_ev_timer.function = &tc_ev_stop;
+	tc_ev_processed = 1;
+
 	power_kobj = kobject_create_and_add("power", NULL);
 	if (!power_kobj)
 		return -ENOMEM;
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 9046443..fc7e52b 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -308,7 +308,7 @@
  */
 int pm_suspend(suspend_state_t state)
 {
-	if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
+	if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX)
 		return enter_state(state);
 	return -EINVAL;
 }
diff --git a/kernel/printk.c b/kernel/printk.c
index 3c31395..e17de88 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -365,8 +365,10 @@
 			return 0;
 		/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
 		if (capable(CAP_SYS_ADMIN)) {
-			WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
-				 "but no CAP_SYSLOG (deprecated).\n");
+			printk_once(KERN_WARNING "%s (%d): "
+				 "Attempt to access syslog with CAP_SYS_ADMIN "
+				 "but no CAP_SYSLOG (deprecated).\n",
+				 current->comm, task_pid_nr(current));
 			return 0;
 		}
 		return -EPERM;
diff --git a/kernel/sched.c b/kernel/sched.c
index b85f675..f8289fc 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2324,7 +2324,7 @@
 		 * yield - it could be a while.
 		 */
 		if (unlikely(on_rq)) {
-			ktime_t to = ktime_set(0, NSEC_PER_SEC/HZ);
+			ktime_t to = ktime_set(0, NSEC_PER_MSEC);
 
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_hrtimeout(&to, HRTIMER_MODE_REL);
@@ -4149,8 +4149,6 @@
  */
 static noinline void __schedule_bug(struct task_struct *prev)
 {
-	struct pt_regs *regs = get_irq_regs();
-
 	printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n",
 		prev->comm, prev->pid, preempt_count());
 
@@ -4158,11 +4156,7 @@
 	print_modules();
 	if (irqs_disabled())
 		print_irqtrace_events(prev);
-
-	if (regs)
-		show_regs(regs);
-	else
-		dump_stack();
+	dump_stack();
 }
 
 /*
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index 17f2319..ac79f9e3 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -1390,6 +1390,11 @@
 	if (!next_task)
 		return 0;
 
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+       if (unlikely(task_running(rq, next_task)))
+               return 0;
+#endif
+
 retry:
 	if (unlikely(next_task == rq->curr)) {
 		WARN_ON(1);
diff --git a/kernel/signal.c b/kernel/signal.c
index 415d85d..43fee1c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1894,21 +1894,19 @@
 		 */
 		if (!(sig->flags & SIGNAL_STOP_STOPPED))
 			sig->group_exit_code = signr;
-		else
-			WARN_ON_ONCE(!task_ptrace(current));
 
 		current->group_stop &= ~GROUP_STOP_SIGMASK;
 		current->group_stop |= signr | gstop;
 		sig->group_stop_count = 1;
 		for (t = next_thread(current); t != current;
 		     t = next_thread(t)) {
-			t->group_stop &= ~GROUP_STOP_SIGMASK;
 			/*
 			 * Setting state to TASK_STOPPED for a group
 			 * stop is always done with the siglock held,
 			 * so this check has no races.
 			 */
 			if (!(t->flags & PF_EXITING) && !task_is_stopped(t)) {
+				t->group_stop &= ~GROUP_STOP_SIGMASK;
 				t->group_stop |= signr | gstop;
 				sig->group_stop_count++;
 				signal_wake_up(t, 0);
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 4406ba2..67520e8 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -1355,7 +1355,7 @@
 
 	fput(file);
 out_putname:
-	putname(pathname);
+	__putname(pathname);
 out:
 	return result;
 }
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index fc0f220..8d597b1 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -657,6 +657,7 @@
 	.cmd		= TASKSTATS_CMD_GET,
 	.doit		= taskstats_user_cmd,
 	.policy		= taskstats_cmd_get_policy,
+	.flags		= GENL_ADMIN_PERM,
 };
 
 static struct genl_ops cgroupstats_ops = {
diff --git a/kernel/time.c b/kernel/time.c
index 8e8dc6d..d776062 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -575,7 +575,7 @@
 /*
  * Convert jiffies/jiffies_64 to clock_t and back.
  */
-clock_t jiffies_to_clock_t(long x)
+clock_t jiffies_to_clock_t(unsigned long x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
 # if HZ < USER_HZ
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index ea5e1a9..8b70c76 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -181,7 +181,7 @@
 		struct alarm *alarm;
 		ktime_t expired = next->expires;
 
-		if (expired.tv64 >= now.tv64)
+		if (expired.tv64 > now.tv64)
 			break;
 
 		alarm = container_of(next, struct alarm, node);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index e0980f0..8b27006 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -531,7 +531,7 @@
 	 * note a margin of 12.5% is used because this can be computed with
 	 * a shift, versus say 10% which would require division.
 	 */
-	return max_nsecs - (max_nsecs >> 5);
+	return max_nsecs - (max_nsecs >> 3);
 }
 
 #ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
@@ -653,7 +653,7 @@
 	 * ~ 0.06ppm granularity for NTP. We apply the same 12.5%
 	 * margin as we do in clocksource_max_deferment()
 	 */
-	sec = (cs->mask - (cs->mask >> 5));
+	sec = (cs->mask - (cs->mask >> 3));
 	do_div(sec, freq);
 	do_div(sec, scale);
 	if (!sec)
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index c7218d1..7a90d02 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -71,7 +71,7 @@
 	     (dev->features & CLOCK_EVT_FEAT_C3STOP))
 		return 0;
 
-	clockevents_exchange_device(NULL, dev);
+	clockevents_exchange_device(tick_broadcast_device.evtdev, dev);
 	tick_broadcast_device.evtdev = dev;
 	if (!cpumask_empty(tick_get_broadcast_mask()))
 		tick_broadcast_start_periodic(dev);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 342408c..9b28d04 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -249,6 +249,8 @@
 		secs = xtime.tv_sec + wall_to_monotonic.tv_sec;
 		nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
 		nsecs += timekeeping_get_ns();
+		/* If arch requires, add in gettimeoffset() */
+		nsecs += arch_gettimeoffset();
 
 	} while (read_seqretry(&xtime_lock, seq));
 	/*
@@ -280,6 +282,8 @@
 		*ts = xtime;
 		tomono = wall_to_monotonic;
 		nsecs = timekeeping_get_ns();
+		/* If arch requires, add in gettimeoffset() */
+		nsecs += arch_gettimeoffset();
 
 	} while (read_seqretry(&xtime_lock, seq));
 
@@ -604,6 +608,12 @@
  */
 static void __timekeeping_inject_sleeptime(struct timespec *delta)
 {
+	if (!timespec_valid(delta)) {
+		printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid "
+					"sleep delta value!\n");
+		return;
+	}
+
 	xtime = timespec_add(xtime, *delta);
 	wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta);
 	total_sleep_time = timespec_add(total_sleep_time, *delta);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ef9271b..9f8e2e1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -952,7 +952,7 @@
 };
 
 enum {
-	FTRACE_ENABLE_CALLS		= (1 << 0),
+	FTRACE_UPDATE_CALLS		= (1 << 0),
 	FTRACE_DISABLE_CALLS		= (1 << 1),
 	FTRACE_UPDATE_TRACE_FUNC	= (1 << 2),
 	FTRACE_START_FUNC_RET		= (1 << 3),
@@ -1182,8 +1182,14 @@
 	return NULL;
 }
 
+static void
+ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash);
+static void
+ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash);
+
 static int
-ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)
+ftrace_hash_move(struct ftrace_ops *ops, int enable,
+		 struct ftrace_hash **dst, struct ftrace_hash *src)
 {
 	struct ftrace_func_entry *entry;
 	struct hlist_node *tp, *tn;
@@ -1193,9 +1199,16 @@
 	unsigned long key;
 	int size = src->count;
 	int bits = 0;
+	int ret;
 	int i;
 
 	/*
+	 * Remove the current set, update the hash and add
+	 * them back.
+	 */
+	ftrace_hash_rec_disable(ops, enable);
+
+	/*
 	 * If the new source is empty, just free dst and assign it
 	 * the empty_hash.
 	 */
@@ -1215,9 +1228,10 @@
 	if (bits > FTRACE_HASH_MAX_BITS)
 		bits = FTRACE_HASH_MAX_BITS;
 
+	ret = -ENOMEM;
 	new_hash = alloc_ftrace_hash(bits);
 	if (!new_hash)
-		return -ENOMEM;
+		goto out;
 
 	size = 1 << src->size_bits;
 	for (i = 0; i < size; i++) {
@@ -1236,7 +1250,16 @@
 	rcu_assign_pointer(*dst, new_hash);
 	free_ftrace_hash_rcu(old_hash);
 
-	return 0;
+	ret = 0;
+ out:
+	/*
+	 * Enable regardless of ret:
+	 *  On success, we enable the new hash.
+	 *  On failure, we re-enable the original hash.
+	 */
+	ftrace_hash_rec_enable(ops, enable);
+
+	return ret;
 }
 
 /*
@@ -1498,7 +1521,7 @@
 
 
 static int
-__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
+__ftrace_replace_code(struct dyn_ftrace *rec, int update)
 {
 	unsigned long ftrace_addr;
 	unsigned long flag = 0UL;
@@ -1506,17 +1529,17 @@
 	ftrace_addr = (unsigned long)FTRACE_ADDR;
 
 	/*
-	 * If we are enabling tracing:
+	 * If we are updating calls:
 	 *
 	 *   If the record has a ref count, then we need to enable it
 	 *   because someone is using it.
 	 *
 	 *   Otherwise we make sure its disabled.
 	 *
-	 * If we are disabling tracing, then disable all records that
+	 * If we are disabling calls, then disable all records that
 	 * are enabled.
 	 */
-	if (enable && (rec->flags & ~FTRACE_FL_MASK))
+	if (update && (rec->flags & ~FTRACE_FL_MASK))
 		flag = FTRACE_FL_ENABLED;
 
 	/* If the state of this record hasn't changed, then do nothing */
@@ -1532,7 +1555,7 @@
 	return ftrace_make_nop(NULL, rec, ftrace_addr);
 }
 
-static void ftrace_replace_code(int enable)
+static void ftrace_replace_code(int update)
 {
 	struct dyn_ftrace *rec;
 	struct ftrace_page *pg;
@@ -1546,7 +1569,7 @@
 		if (rec->flags & FTRACE_FL_FREE)
 			continue;
 
-		failed = __ftrace_replace_code(rec, enable);
+		failed = __ftrace_replace_code(rec, update);
 		if (failed) {
 			ftrace_bug(failed, rec->ip);
 			/* Stop processing */
@@ -1596,7 +1619,7 @@
 {
 	int *command = data;
 
-	if (*command & FTRACE_ENABLE_CALLS)
+	if (*command & FTRACE_UPDATE_CALLS)
 		ftrace_replace_code(1);
 	else if (*command & FTRACE_DISABLE_CALLS)
 		ftrace_replace_code(0);
@@ -1652,7 +1675,7 @@
 		return -ENODEV;
 
 	ftrace_start_up++;
-	command |= FTRACE_ENABLE_CALLS;
+	command |= FTRACE_UPDATE_CALLS;
 
 	/* ops marked global share the filter hashes */
 	if (ops->flags & FTRACE_OPS_FL_GLOBAL) {
@@ -1704,8 +1727,7 @@
 	if (ops != &global_ops || !global_start_up)
 		ops->flags &= ~FTRACE_OPS_FL_ENABLED;
 
-	if (!ftrace_start_up)
-		command |= FTRACE_DISABLE_CALLS;
+	command |= FTRACE_UPDATE_CALLS;
 
 	if (saved_ftrace_func != ftrace_trace_function) {
 		saved_ftrace_func = ftrace_trace_function;
@@ -1727,7 +1749,7 @@
 	saved_ftrace_func = NULL;
 	/* ftrace_start_up is true if we want ftrace running */
 	if (ftrace_start_up)
-		ftrace_run_update_code(FTRACE_ENABLE_CALLS);
+		ftrace_run_update_code(FTRACE_UPDATE_CALLS);
 }
 
 static void ftrace_shutdown_sysctl(void)
@@ -2877,7 +2899,11 @@
 		ftrace_match_records(hash, buf, len);
 
 	mutex_lock(&ftrace_lock);
-	ret = ftrace_hash_move(orig_hash, hash);
+	ret = ftrace_hash_move(ops, enable, orig_hash, hash);
+	if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED
+	    && ftrace_enabled)
+		ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+
 	mutex_unlock(&ftrace_lock);
 
 	mutex_unlock(&ftrace_regex_lock);
@@ -3060,18 +3086,12 @@
 			orig_hash = &iter->ops->notrace_hash;
 
 		mutex_lock(&ftrace_lock);
-		/*
-		 * Remove the current set, update the hash and add
-		 * them back.
-		 */
-		ftrace_hash_rec_disable(iter->ops, filter_hash);
-		ret = ftrace_hash_move(orig_hash, iter->hash);
-		if (!ret) {
-			ftrace_hash_rec_enable(iter->ops, filter_hash);
-			if (iter->ops->flags & FTRACE_OPS_FL_ENABLED
-			    && ftrace_enabled)
-				ftrace_run_update_code(FTRACE_ENABLE_CALLS);
-		}
+		ret = ftrace_hash_move(iter->ops, filter_hash,
+				       orig_hash, iter->hash);
+		if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED)
+		    && ftrace_enabled)
+			ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+
 		mutex_unlock(&ftrace_lock);
 	}
 	free_ftrace_hash(iter->hash);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index ee9c921..0731e81a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3704,8 +3704,6 @@
 	if (info->read < PAGE_SIZE)
 		goto read;
 
-	info->read = 0;
-
 	trace_access_lock(info->cpu);
 	ret = ring_buffer_read_page(info->tr->buffer,
 				    &info->spare,
@@ -3715,6 +3713,8 @@
 	if (ret < 0)
 		return 0;
 
+	info->read = 0;
+
 read:
 	size = PAGE_SIZE - info->read;
 	if (size > count)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 3e2a7c9..2d04936 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1096,7 +1096,6 @@
 	/* First see if we did not already create this dir */
 	list_for_each_entry(system, &event_subsystems, list) {
 		if (strcmp(system->name, name) == 0) {
-			__get_system(system);
 			system->nr_events++;
 			return system->entry;
 		}
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 256764e..bd3c636 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1766,7 +1766,7 @@
 		 * replace the filter for the call.
 		 */
 		filter = call->filter;
-		call->filter = filter_item->filter;
+		rcu_assign_pointer(call->filter, filter_item->filter);
 		filter_item->filter = filter;
 
 		fail = false;
@@ -1821,7 +1821,7 @@
 		filter = call->filter;
 		if (!filter)
 			goto out_unlock;
-		call->filter = NULL;
+		RCU_INIT_POINTER(call->filter, NULL);
 		/* Make sure the filter is not being used */
 		synchronize_sched();
 		__free_filter(filter);
@@ -1862,7 +1862,7 @@
 	 * string
 	 */
 	tmp = call->filter;
-	call->filter = filter;
+	rcu_assign_pointer(call->filter, filter);
 	if (tmp) {
 		/* Make sure the call is done with the filter */
 		synchronize_sched();
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 70af0a7..ad72a03 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -282,7 +282,7 @@
 							    kobj_bcast_filter,
 							    kobj);
 			/* ENOBUFS should be handled in userspace */
-			if (retval == -ENOBUFS)
+			if (retval == -ENOBUFS || retval == -ESRCH)
 				retval = 0;
 		} else
 			retval = -ENOMEM;
diff --git a/lib/nlattr.c b/lib/nlattr.c
index ac09f22..a8408b6 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -20,6 +20,7 @@
 	[NLA_U16]	= sizeof(u16),
 	[NLA_U32]	= sizeof(u32),
 	[NLA_U64]	= sizeof(u64),
+	[NLA_MSECS]	= sizeof(u64),
 	[NLA_NESTED]	= NLA_HDRLEN,
 };
 
diff --git a/mm/compaction.c b/mm/compaction.c
index 6cc604b..c4bc5ac 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -320,12 +320,34 @@
 		} else if (!locked)
 			spin_lock_irq(&zone->lru_lock);
 
+		/*
+		 * migrate_pfn does not necessarily start aligned to a
+		 * pageblock. Ensure that pfn_valid is called when moving
+		 * into a new MAX_ORDER_NR_PAGES range in case of large
+		 * memory holes within the zone
+		 */
+		if ((low_pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) {
+			if (!pfn_valid(low_pfn)) {
+				low_pfn += MAX_ORDER_NR_PAGES - 1;
+				continue;
+			}
+		}
+
 		if (!pfn_valid_within(low_pfn))
 			continue;
 		nr_scanned++;
 
-		/* Get the page and skip if free */
+		/*
+		 * Get the page and ensure the page is within the same zone.
+		 * See the comment in isolate_freepages about overlapping
+		 * nodes. It is deliberate that the new zone lock is not taken
+		 * as memory compaction should not move pages between nodes.
+		 */
 		page = pfn_to_page(low_pfn);
+		if (page_zone(page) != zone)
+			continue;
+
+		/* Skip if free */
 		if (PageBuddy(page))
 			continue;
 
diff --git a/mm/filemap.c b/mm/filemap.c
index a8251a8..b7d8603 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -396,24 +396,11 @@
 int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
 {
 	int error;
-	struct mem_cgroup *memcg = NULL;
 
 	VM_BUG_ON(!PageLocked(old));
 	VM_BUG_ON(!PageLocked(new));
 	VM_BUG_ON(new->mapping);
 
-	/*
-	 * This is not page migration, but prepare_migration and
-	 * end_migration does enough work for charge replacement.
-	 *
-	 * In the longer term we probably want a specialized function
-	 * for moving the charge from old to new in a more efficient
-	 * manner.
-	 */
-	error = mem_cgroup_prepare_migration(old, new, &memcg, gfp_mask);
-	if (error)
-		return error;
-
 	error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
 	if (!error) {
 		struct address_space *mapping = old->mapping;
@@ -435,13 +422,12 @@
 		if (PageSwapBacked(new))
 			__inc_zone_page_state(new, NR_SHMEM);
 		spin_unlock_irq(&mapping->tree_lock);
+		/* mem_cgroup codes must not be called under tree_lock */
+		mem_cgroup_replace_page_cache(old, new);
 		radix_tree_preload_end();
 		if (freepage)
 			freepage(old);
 		page_cache_release(old);
-		mem_cgroup_end_migration(memcg, old, new, true);
-	} else {
-		mem_cgroup_end_migration(memcg, old, new, false);
 	}
 
 	return error;
@@ -1393,15 +1379,12 @@
 	unsigned long seg = 0;
 	size_t count;
 	loff_t *ppos = &iocb->ki_pos;
-	struct blk_plug plug;
 
 	count = 0;
 	retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
 	if (retval)
 		return retval;
 
-	blk_start_plug(&plug);
-
 	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
 	if (filp->f_flags & O_DIRECT) {
 		loff_t size;
@@ -1417,8 +1400,12 @@
 			retval = filemap_write_and_wait_range(mapping, pos,
 					pos + iov_length(iov, nr_segs) - 1);
 			if (!retval) {
+				struct blk_plug plug;
+
+				blk_start_plug(&plug);
 				retval = mapping->a_ops->direct_IO(READ, iocb,
 							iov, pos, nr_segs);
+				blk_finish_plug(&plug);
 			}
 			if (retval > 0) {
 				*ppos = pos + retval;
@@ -1474,7 +1461,6 @@
 			break;
 	}
 out:
-	blk_finish_plug(&plug);
 	return retval;
 }
 EXPORT_SYMBOL(generic_file_aio_read);
@@ -1807,7 +1793,7 @@
 		page = __page_cache_alloc(gfp | __GFP_COLD);
 		if (!page)
 			return ERR_PTR(-ENOMEM);
-		err = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL);
+		err = add_to_page_cache_lru(page, mapping, index, gfp);
 		if (unlikely(err)) {
 			page_cache_release(page);
 			if (err == -EEXIST)
@@ -1904,10 +1890,7 @@
  * @gfp:	the page allocator flags to use if allocating
  *
  * This is the same as "read_mapping_page(mapping, index, NULL)", but with
- * any new page allocations done using the specified allocation flags. Note
- * that the Radix tree operations will still use GFP_KERNEL, so you can't
- * expect to do this atomically or anything like that - but you can pass in
- * other page requirements.
+ * any new page allocations done using the specified allocation flags.
  *
  * If the page does not get brought uptodate, return -EIO.
  */
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index 93356cd..dee9429 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -263,7 +263,12 @@
 							xip_pfn);
 		if (err == -ENOMEM)
 			return VM_FAULT_OOM;
-		BUG_ON(err);
+		/*
+		 * err == -EBUSY is fine, we've raced against another thread
+		 * that faulted-in the same page
+		 */
+		if (err != -EBUSY)
+			BUG_ON(err);
 		return VM_FAULT_NOPAGE;
 	} else {
 		int err, ret = VM_FAULT_OOM;
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 81532f2..78a83e7 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -989,7 +989,7 @@
 	page += (addr & ~HPAGE_PMD_MASK) >> PAGE_SHIFT;
 	VM_BUG_ON(!PageCompound(page));
 	if (flags & FOLL_GET)
-		get_page(page);
+		get_page_foll(page);
 
 out:
 	return page;
@@ -1156,6 +1156,7 @@
 	unsigned long head_index = page->index;
 	struct zone *zone = page_zone(page);
 	int zonestat;
+	int tail_count = 0;
 
 	/* prevent PageLRU to go away from under us, and freeze lru stats */
 	spin_lock_irq(&zone->lru_lock);
@@ -1164,11 +1165,27 @@
 	for (i = 1; i < HPAGE_PMD_NR; i++) {
 		struct page *page_tail = page + i;
 
-		/* tail_page->_count cannot change */
-		atomic_sub(atomic_read(&page_tail->_count), &page->_count);
-		BUG_ON(page_count(page) <= 0);
-		atomic_add(page_mapcount(page) + 1, &page_tail->_count);
-		BUG_ON(atomic_read(&page_tail->_count) <= 0);
+		/* tail_page->_mapcount cannot change */
+		BUG_ON(page_mapcount(page_tail) < 0);
+		tail_count += page_mapcount(page_tail);
+		/* check for overflow */
+		BUG_ON(tail_count < 0);
+		BUG_ON(atomic_read(&page_tail->_count) != 0);
+		/*
+		 * tail_page->_count is zero and not changing from
+		 * under us. But get_page_unless_zero() may be running
+		 * from under us on the tail_page. If we used
+		 * atomic_set() below instead of atomic_add(), we
+		 * would then run atomic_set() concurrently with
+		 * get_page_unless_zero(), and atomic_set() is
+		 * implemented in C not using locked ops. spin_unlock
+		 * on x86 sometime uses locked ops because of PPro
+		 * errata 66, 92, so unless somebody can guarantee
+		 * atomic_set() here would be safe on all archs (and
+		 * not only on x86), it's safer to use atomic_add().
+		 */
+		atomic_add(page_mapcount(page) + page_mapcount(page_tail) + 1,
+			   &page_tail->_count);
 
 		/* after clearing PageTail the gup refcount can be released */
 		smp_mb();
@@ -1186,10 +1203,7 @@
 				      (1L << PG_uptodate)));
 		page_tail->flags |= (1L << PG_dirty);
 
-		/*
-		 * 1) clear PageTail before overwriting first_page
-		 * 2) clear PageTail before clearing PageHead for VM_BUG_ON
-		 */
+		/* clear PageTail before overwriting first_page */
 		smp_wmb();
 
 		/*
@@ -1206,7 +1220,6 @@
 		 * status is achieved setting a reserved bit in the
 		 * pmd, not by clearing the present bit.
 		*/
-		BUG_ON(page_mapcount(page_tail));
 		page_tail->_mapcount = page->_mapcount;
 
 		BUG_ON(page_tail->mapping);
@@ -1223,6 +1236,8 @@
 
 		lru_add_page_tail(zone, page, page_tail);
 	}
+	atomic_sub(tail_count, &page->_count);
+	BUG_ON(atomic_read(&page->_count) <= 0);
 
 	__dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
 	__mod_zone_page_state(zone, NR_ANON_PAGES, HPAGE_PMD_NR);
@@ -2005,7 +2020,7 @@
 {
 	struct mm_struct *mm = mm_slot->mm;
 
-	VM_BUG_ON(!spin_is_locked(&khugepaged_mm_lock));
+	VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&khugepaged_mm_lock));
 
 	if (khugepaged_test_exit(mm)) {
 		/* free mm_slot */
@@ -2033,7 +2048,7 @@
 	int progress = 0;
 
 	VM_BUG_ON(!pages);
-	VM_BUG_ON(!spin_is_locked(&khugepaged_mm_lock));
+	VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&khugepaged_mm_lock));
 
 	if (khugepaged_scan.mm_slot)
 		mm_slot = khugepaged_scan.mm_slot;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index bfcf153..f9c5849 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -575,6 +575,7 @@
 	__SetPageHead(page);
 	for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
 		__SetPageTail(p);
+		set_page_count(p, 0);
 		p->first_page = page;
 	}
 }
@@ -900,7 +901,6 @@
 	h->resv_huge_pages += delta;
 	ret = 0;
 
-	spin_unlock(&hugetlb_lock);
 	/* Free the needed pages to the hugetlb pool */
 	list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
 		if ((--needed) < 0)
@@ -914,6 +914,7 @@
 		VM_BUG_ON(page_count(page));
 		enqueue_huge_page(h, page);
 	}
+	spin_unlock(&hugetlb_lock);
 
 	/* Free unnecessary surplus pages to the buddy allocator */
 free:
@@ -2415,6 +2416,8 @@
 	 * anon_vma prepared.
 	 */
 	if (unlikely(anon_vma_prepare(vma))) {
+		page_cache_release(new_page);
+		page_cache_release(old_page);
 		/* Caller expects lock to be held */
 		spin_lock(&mm->page_table_lock);
 		return VM_FAULT_OOM;
diff --git a/mm/internal.h b/mm/internal.h
index d071d38..2189af4 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -37,6 +37,52 @@
 	atomic_dec(&page->_count);
 }
 
+static inline void __get_page_tail_foll(struct page *page,
+					bool get_page_head)
+{
+	/*
+	 * If we're getting a tail page, the elevated page->_count is
+	 * required only in the head page and we will elevate the head
+	 * page->_count and tail page->_mapcount.
+	 *
+	 * We elevate page_tail->_mapcount for tail pages to force
+	 * page_tail->_count to be zero at all times to avoid getting
+	 * false positives from get_page_unless_zero() with
+	 * speculative page access (like in
+	 * page_cache_get_speculative()) on tail pages.
+	 */
+	VM_BUG_ON(atomic_read(&page->first_page->_count) <= 0);
+	VM_BUG_ON(atomic_read(&page->_count) != 0);
+	VM_BUG_ON(page_mapcount(page) < 0);
+	if (get_page_head)
+		atomic_inc(&page->first_page->_count);
+	atomic_inc(&page->_mapcount);
+}
+
+/*
+ * This is meant to be called as the FOLL_GET operation of
+ * follow_page() and it must be called while holding the proper PT
+ * lock while the pte (or pmd_trans_huge) is still mapping the page.
+ */
+static inline void get_page_foll(struct page *page)
+{
+	if (unlikely(PageTail(page)))
+		/*
+		 * This is safe only because
+		 * __split_huge_page_refcount() can't run under
+		 * get_page_foll() because we hold the proper PT lock.
+		 */
+		__get_page_tail_foll(page, true);
+	else {
+		/*
+		 * Getting a normal page or the head of a compound page
+		 * requires to already have an elevated page->_count.
+		 */
+		VM_BUG_ON(atomic_read(&page->_count) <= 0);
+		atomic_inc(&page->_count);
+	}
+}
+
 extern unsigned long highest_memmap_pfn;
 
 /*
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 59ac5d6..3791581 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3422,6 +3422,50 @@
 	return ret;
 }
 
+/*
+ * At replace page cache, newpage is not under any memcg but it's on
+ * LRU. So, this function doesn't touch res_counter but handles LRU
+ * in correct way. Both pages are locked so we cannot race with uncharge.
+ */
+void mem_cgroup_replace_page_cache(struct page *oldpage,
+				  struct page *newpage)
+{
+	struct mem_cgroup *memcg;
+	struct page_cgroup *pc;
+	struct zone *zone;
+	enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
+	unsigned long flags;
+
+	if (mem_cgroup_disabled())
+		return;
+
+	pc = lookup_page_cgroup(oldpage);
+	/* fix accounting on old pages */
+	lock_page_cgroup(pc);
+	memcg = pc->mem_cgroup;
+	mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -1);
+	ClearPageCgroupUsed(pc);
+	unlock_page_cgroup(pc);
+
+	if (PageSwapBacked(oldpage))
+		type = MEM_CGROUP_CHARGE_TYPE_SHMEM;
+
+	zone = page_zone(newpage);
+	pc = lookup_page_cgroup(newpage);
+	/*
+	 * Even if newpage->mapping was NULL before starting replacement,
+	 * the newpage may be on LRU(or pagevec for LRU) already. We lock
+	 * LRU while we overwrite pc->mem_cgroup.
+	 */
+	spin_lock_irqsave(&zone->lru_lock, flags);
+	if (PageLRU(newpage))
+		del_page_from_lru_list(zone, newpage, page_lru(newpage));
+	__mem_cgroup_commit_charge(memcg, newpage, 1, pc, type);
+	if (PageLRU(newpage))
+		add_page_to_lru_list(zone, newpage, page_lru(newpage));
+	spin_unlock_irqrestore(&zone->lru_lock, flags);
+}
+
 #ifdef CONFIG_DEBUG_VM
 static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
 {
@@ -4963,9 +5007,9 @@
 		int cpu;
 		enable_swap_cgroup();
 		parent = NULL;
-		root_mem_cgroup = mem;
 		if (mem_cgroup_soft_limit_tree_init())
 			goto free_out;
+		root_mem_cgroup = mem;
 		for_each_possible_cpu(cpu) {
 			struct memcg_stock_pcp *stock =
 						&per_cpu(memcg_stock, cpu);
@@ -5004,7 +5048,6 @@
 	return &mem->css;
 free_out:
 	__mem_cgroup_free(mem);
-	root_mem_cgroup = NULL;
 	return ERR_PTR(error);
 }
 
diff --git a/mm/memory.c b/mm/memory.c
index d961e19..95a7799 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1514,7 +1514,7 @@
 	}
 
 	if (flags & FOLL_GET)
-		get_page(page);
+		get_page_foll(page);
 	if (flags & FOLL_TOUCH) {
 		if ((flags & FOLL_WRITE) &&
 		    !pte_dirty(pte) && !PageDirty(page))
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 8093fc7..7c72487 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -162,7 +162,7 @@
 unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
 		      const nodemask_t *nodemask, unsigned long totalpages)
 {
-	int points;
+	long points;
 
 	if (oom_unkillable_task(p, mem, nodemask))
 		return 0;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 60ad5e9..38ddeeb 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -376,8 +376,8 @@
 	__SetPageHead(page);
 	for (i = 1; i < nr_pages; i++) {
 		struct page *p = page + i;
-
 		__SetPageTail(p);
+		set_page_count(p, 0);
 		p->first_page = page;
 	}
 }
@@ -3418,9 +3418,15 @@
 	unsigned long block_migratetype;
 	int reserve;
 
-	/* Get the start pfn, end pfn and the number of blocks to reserve */
+	/*
+	 * Get the start pfn, end pfn and the number of blocks to reserve
+	 * We have to be careful to be aligned to pageblock_nr_pages to
+	 * make sure that we always check pfn_valid for the first page in
+	 * the block.
+	 */
 	start_pfn = zone->zone_start_pfn;
 	end_pfn = start_pfn + zone->spanned_pages;
+	start_pfn = roundup(start_pfn, pageblock_nr_pages);
 	reserve = roundup(min_wmark_pages(zone), pageblock_nr_pages) >>
 							pageblock_order;
 
@@ -5592,6 +5598,17 @@
 bool is_pageblock_removable_nolock(struct page *page)
 {
 	struct zone *zone = page_zone(page);
+	unsigned long pfn = page_to_pfn(page);
+
+	/*
+	 * We have to be careful here because we are iterating over memory
+	 * sections which are not zone aware so we might end up outside of
+	 * the zone but still within the section.
+	 */
+	if (!zone || zone->zone_start_pfn > pfn ||
+			zone->zone_start_pfn + zone->spanned_pages <= pfn)
+		return false;
+
 	return __count_immobile_pages(zone, page, 0);
 }
 
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c
index ea53496..bfad724 100644
--- a/mm/percpu-vm.c
+++ b/mm/percpu-vm.c
@@ -143,8 +143,8 @@
 				 int page_start, int page_end)
 {
 	flush_cache_vunmap(
-		pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
-		pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+		pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
+		pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
 }
 
 static void __pcpu_unmap_pages(unsigned long addr, int nr_pages)
@@ -206,8 +206,8 @@
 				      int page_start, int page_end)
 {
 	flush_tlb_kernel_range(
-		pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
-		pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+		pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
+		pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
 }
 
 static int __pcpu_map_pages(unsigned long addr, struct page **pages,
@@ -284,8 +284,8 @@
 				int page_start, int page_end)
 {
 	flush_cache_vmap(
-		pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
-		pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+		pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
+		pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
 }
 
 /**
diff --git a/mm/percpu.c b/mm/percpu.c
index bf80e55..0ae7a09 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -116,9 +116,9 @@
 static int pcpu_nr_slots __read_mostly;
 static size_t pcpu_chunk_struct_size __read_mostly;
 
-/* cpus with the lowest and highest unit numbers */
-static unsigned int pcpu_first_unit_cpu __read_mostly;
-static unsigned int pcpu_last_unit_cpu __read_mostly;
+/* cpus with the lowest and highest unit addresses */
+static unsigned int pcpu_low_unit_cpu __read_mostly;
+static unsigned int pcpu_high_unit_cpu __read_mostly;
 
 /* the address of the first chunk which starts with the kernel static area */
 void *pcpu_base_addr __read_mostly;
@@ -984,19 +984,19 @@
 {
 	void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr);
 	bool in_first_chunk = false;
-	unsigned long first_start, first_end;
+	unsigned long first_low, first_high;
 	unsigned int cpu;
 
 	/*
-	 * The following test on first_start/end isn't strictly
+	 * The following test on unit_low/high isn't strictly
 	 * necessary but will speed up lookups of addresses which
 	 * aren't in the first chunk.
 	 */
-	first_start = pcpu_chunk_addr(pcpu_first_chunk, pcpu_first_unit_cpu, 0);
-	first_end = pcpu_chunk_addr(pcpu_first_chunk, pcpu_last_unit_cpu,
-				    pcpu_unit_pages);
-	if ((unsigned long)addr >= first_start &&
-	    (unsigned long)addr < first_end) {
+	first_low = pcpu_chunk_addr(pcpu_first_chunk, pcpu_low_unit_cpu, 0);
+	first_high = pcpu_chunk_addr(pcpu_first_chunk, pcpu_high_unit_cpu,
+				     pcpu_unit_pages);
+	if ((unsigned long)addr >= first_low &&
+	    (unsigned long)addr < first_high) {
 		for_each_possible_cpu(cpu) {
 			void *start = per_cpu_ptr(base, cpu);
 
@@ -1011,9 +1011,11 @@
 		if (!is_vmalloc_addr(addr))
 			return __pa(addr);
 		else
-			return page_to_phys(vmalloc_to_page(addr));
+			return page_to_phys(vmalloc_to_page(addr)) +
+			       offset_in_page(addr);
 	} else
-		return page_to_phys(pcpu_addr_to_page(addr));
+		return page_to_phys(pcpu_addr_to_page(addr)) +
+		       offset_in_page(addr);
 }
 
 /**
@@ -1233,7 +1235,9 @@
 
 	for (cpu = 0; cpu < nr_cpu_ids; cpu++)
 		unit_map[cpu] = UINT_MAX;
-	pcpu_first_unit_cpu = NR_CPUS;
+
+	pcpu_low_unit_cpu = NR_CPUS;
+	pcpu_high_unit_cpu = NR_CPUS;
 
 	for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) {
 		const struct pcpu_group_info *gi = &ai->groups[group];
@@ -1253,9 +1257,13 @@
 			unit_map[cpu] = unit + i;
 			unit_off[cpu] = gi->base_offset + i * ai->unit_size;
 
-			if (pcpu_first_unit_cpu == NR_CPUS)
-				pcpu_first_unit_cpu = cpu;
-			pcpu_last_unit_cpu = cpu;
+			/* determine low/high unit_cpu */
+			if (pcpu_low_unit_cpu == NR_CPUS ||
+			    unit_off[cpu] < unit_off[pcpu_low_unit_cpu])
+				pcpu_low_unit_cpu = cpu;
+			if (pcpu_high_unit_cpu == NR_CPUS ||
+			    unit_off[cpu] > unit_off[pcpu_high_unit_cpu])
+				pcpu_high_unit_cpu = cpu;
 		}
 	}
 	pcpu_nr_units = unit;
diff --git a/mm/swap.c b/mm/swap.c
index 3a442f1..4a1fc6d 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -78,39 +78,22 @@
 {
 	if (unlikely(PageTail(page))) {
 		/* __split_huge_page_refcount can run under us */
-		struct page *page_head = page->first_page;
-		smp_rmb();
-		/*
-		 * If PageTail is still set after smp_rmb() we can be sure
-		 * that the page->first_page we read wasn't a dangling pointer.
-		 * See __split_huge_page_refcount() smp_wmb().
-		 */
-		if (likely(PageTail(page) && get_page_unless_zero(page_head))) {
+		struct page *page_head = compound_trans_head(page);
+
+		if (likely(page != page_head &&
+			   get_page_unless_zero(page_head))) {
 			unsigned long flags;
 			/*
-			 * Verify that our page_head wasn't converted
-			 * to a a regular page before we got a
-			 * reference on it.
+			 * page_head wasn't a dangling pointer but it
+			 * may not be a head page anymore by the time
+			 * we obtain the lock. That is ok as long as it
+			 * can't be freed from under us.
 			 */
-			if (unlikely(!PageHead(page_head))) {
-				/* PageHead is cleared after PageTail */
-				smp_rmb();
-				VM_BUG_ON(PageTail(page));
-				goto out_put_head;
-			}
-			/*
-			 * Only run compound_lock on a valid PageHead,
-			 * after having it pinned with
-			 * get_page_unless_zero() above.
-			 */
-			smp_mb();
-			/* page_head wasn't a dangling pointer */
 			flags = compound_lock_irqsave(page_head);
 			if (unlikely(!PageTail(page))) {
 				/* __split_huge_page_refcount run before us */
 				compound_unlock_irqrestore(page_head, flags);
 				VM_BUG_ON(PageHead(page_head));
-			out_put_head:
 				if (put_page_testzero(page_head))
 					__put_single_page(page_head);
 			out_put_single:
@@ -121,16 +104,17 @@
 			VM_BUG_ON(page_head != page->first_page);
 			/*
 			 * We can release the refcount taken by
-			 * get_page_unless_zero now that
-			 * split_huge_page_refcount is blocked on the
-			 * compound_lock.
+			 * get_page_unless_zero() now that
+			 * __split_huge_page_refcount() is blocked on
+			 * the compound_lock.
 			 */
 			if (put_page_testzero(page_head))
 				VM_BUG_ON(1);
 			/* __split_huge_page_refcount will wait now */
-			VM_BUG_ON(atomic_read(&page->_count) <= 0);
-			atomic_dec(&page->_count);
+			VM_BUG_ON(page_mapcount(page) <= 0);
+			atomic_dec(&page->_mapcount);
 			VM_BUG_ON(atomic_read(&page_head->_count) <= 0);
+			VM_BUG_ON(atomic_read(&page->_count) != 0);
 			compound_unlock_irqrestore(page_head, flags);
 			if (put_page_testzero(page_head)) {
 				if (PageHead(page_head))
@@ -160,6 +144,45 @@
 }
 EXPORT_SYMBOL(put_page);
 
+/*
+ * This function is exported but must not be called by anything other
+ * than get_page(). It implements the slow path of get_page().
+ */
+bool __get_page_tail(struct page *page)
+{
+	/*
+	 * This takes care of get_page() if run on a tail page
+	 * returned by one of the get_user_pages/follow_page variants.
+	 * get_user_pages/follow_page itself doesn't need the compound
+	 * lock because it runs __get_page_tail_foll() under the
+	 * proper PT lock that already serializes against
+	 * split_huge_page().
+	 */
+	unsigned long flags;
+	bool got = false;
+	struct page *page_head = compound_trans_head(page);
+
+	if (likely(page != page_head && get_page_unless_zero(page_head))) {
+		/*
+		 * page_head wasn't a dangling pointer but it
+		 * may not be a head page anymore by the time
+		 * we obtain the lock. That is ok as long as it
+		 * can't be freed from under us.
+		 */
+		flags = compound_lock_irqsave(page_head);
+		/* here __split_huge_page_refcount won't run anymore */
+		if (likely(PageTail(page))) {
+			__get_page_tail_foll(page, false);
+			got = true;
+		}
+		compound_unlock_irqrestore(page_head, flags);
+		if (unlikely(!got))
+			put_page(page_head);
+	}
+	return got;
+}
+EXPORT_SYMBOL(__get_page_tail);
+
 /**
  * put_pages_list() - release a list of pages
  * @pages: list of pages threaded on page->lru
@@ -644,7 +667,7 @@
 	VM_BUG_ON(!PageHead(page));
 	VM_BUG_ON(PageCompound(page_tail));
 	VM_BUG_ON(PageLRU(page_tail));
-	VM_BUG_ON(!spin_is_locked(&zone->lru_lock));
+	VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&zone->lru_lock));
 
 	SetPageLRU(page_tail);
 
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index c33d2ae..960956c 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1267,18 +1267,22 @@
 DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
-static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
+static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
 			      unsigned long flags, void *caller)
 {
-	struct vm_struct *tmp, **p;
-
 	vm->flags = flags;
 	vm->addr = (void *)va->va_start;
 	vm->size = va->va_end - va->va_start;
 	vm->caller = caller;
 	va->private = vm;
 	va->flags |= VM_VM_AREA;
+}
 
+static void insert_vmalloc_vmlist(struct vm_struct *vm)
+{
+	struct vm_struct *tmp, **p;
+
+	vm->flags &= ~VM_UNLIST;
 	write_lock(&vmlist_lock);
 	for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
 		if (tmp->addr >= vm->addr)
@@ -1289,6 +1293,13 @@
 	write_unlock(&vmlist_lock);
 }
 
+static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
+			      unsigned long flags, void *caller)
+{
+	setup_vmalloc_vm(vm, va, flags, caller);
+	insert_vmalloc_vmlist(vm);
+}
+
 static struct vm_struct *__get_vm_area_node(unsigned long size,
 		unsigned long align, unsigned long flags, unsigned long start,
 		unsigned long end, int node, gfp_t gfp_mask, void *caller)
@@ -1327,7 +1338,18 @@
 		return NULL;
 	}
 
-	insert_vmalloc_vm(area, va, flags, caller);
+	/*
+	 * When this function is called from __vmalloc_node_range,
+	 * we do not add vm_struct to vmlist here to avoid
+	 * accessing uninitialized members of vm_struct such as
+	 * pages and nr_pages fields. They will be set later.
+	 * To distinguish it from others, we use a VM_UNLIST flag.
+	 */
+	if (flags & VM_UNLIST)
+		setup_vmalloc_vm(area, va, flags, caller);
+	else
+		insert_vmalloc_vm(area, va, flags, caller);
+
 	return area;
 }
 
@@ -1395,17 +1417,20 @@
 	va = find_vmap_area((unsigned long)addr);
 	if (va && va->flags & VM_VM_AREA) {
 		struct vm_struct *vm = va->private;
-		struct vm_struct *tmp, **p;
-		/*
-		 * remove from list and disallow access to this vm_struct
-		 * before unmap. (address range confliction is maintained by
-		 * vmap.)
-		 */
-		write_lock(&vmlist_lock);
-		for (p = &vmlist; (tmp = *p) != vm; p = &tmp->next)
-			;
-		*p = tmp->next;
-		write_unlock(&vmlist_lock);
+
+		if (!(vm->flags & VM_UNLIST)) {
+			struct vm_struct *tmp, **p;
+			/*
+			 * remove from list and disallow access to
+			 * this vm_struct before unmap. (address range
+			 * confliction is maintained by vmap.)
+			 */
+			write_lock(&vmlist_lock);
+			for (p = &vmlist; (tmp = *p) != vm; p = &tmp->next)
+				;
+			*p = tmp->next;
+			write_unlock(&vmlist_lock);
+		}
 
 		vmap_debug_free_range(va->va_start, va->va_end);
 		free_unmap_vmap_area(va);
@@ -1621,13 +1646,21 @@
 	if (!size || (size >> PAGE_SHIFT) > total_pages)
 		return NULL;
 
-	area = __get_vm_area_node(size, align, VM_ALLOC, start, end, node,
-				  gfp_mask, caller);
+	area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNLIST,
+				  start, end, node, gfp_mask, caller);
 
 	if (!area)
 		return NULL;
 
 	addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);
+	if (!addr)
+		return NULL;
+
+	/*
+	 * In this function, newly allocated vm_struct is not added
+	 * to vmlist at __get_vm_area_node(). so, it is added here.
+	 */
+	insert_vmalloc_vmlist(area);
 
 	/*
 	 * A ref_count = 3 is needed because the vm_struct and vmap_area
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 1d4be60..5889074 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -364,33 +364,37 @@
 				   struct net_device *dev)
 {
 	struct clip_priv *clip_priv = PRIV(dev);
+	struct dst_entry *dst = skb_dst(skb);
 	struct atmarp_entry *entry;
+	struct neighbour *n;
 	struct atm_vcc *vcc;
 	int old;
 	unsigned long flags;
 
 	pr_debug("(skb %p)\n", skb);
-	if (!skb_dst(skb)) {
+	if (!dst) {
 		pr_err("skb_dst(skb) == NULL\n");
 		dev_kfree_skb(skb);
 		dev->stats.tx_dropped++;
 		return NETDEV_TX_OK;
 	}
-	if (!skb_dst(skb)->neighbour) {
+	n = dst_get_neighbour(dst);
+	if (!n) {
 #if 0
-		skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1);
-		if (!skb_dst(skb)->neighbour) {
+		n = clip_find_neighbour(skb_dst(skb), 1);
+		if (!n) {
 			dev_kfree_skb(skb);	/* lost that one */
 			dev->stats.tx_dropped++;
 			return 0;
 		}
+		dst_set_neighbour(dst, n);
 #endif
 		pr_err("NO NEIGHBOUR !\n");
 		dev_kfree_skb(skb);
 		dev->stats.tx_dropped++;
 		return NETDEV_TX_OK;
 	}
-	entry = NEIGH2ENTRY(skb_dst(skb)->neighbour);
+	entry = NEIGH2ENTRY(n);
 	if (!entry->vccs) {
 		if (time_after(jiffies, entry->expires)) {
 			/* should be resolved */
@@ -407,7 +411,7 @@
 	}
 	pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
 	ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
-	pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc);
+	pr_debug("using neighbour %p, vcc %p\n", n, vcc);
 	if (entry->vccs->encap) {
 		void *here;
 
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 0a3b91d..df80c42 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -1,5 +1,5 @@
 /*
-   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
@@ -87,15 +87,15 @@
 	return found;
 }
 
-static struct amp_mgr *get_create_amp_mgr(struct l2cap_conn *conn,
+static struct amp_mgr *get_create_amp_mgr(struct hci_conn *hcon,
 						struct sk_buff *skb)
 {
 	struct amp_mgr *mgr;
 
 	write_lock(&amp_mgr_list_lock);
 	list_for_each_entry(mgr, &amp_mgr_list, list) {
-		if (mgr->l2cap_conn == conn) {
-			BT_DBG("conn %p found %p", conn, mgr);
+		if (mgr->l2cap_conn == hcon->l2cap_data) {
+			BT_DBG("found %p", mgr);
 			write_unlock(&amp_mgr_list_lock);
 			goto gc_finished;
 		}
@@ -106,13 +106,13 @@
 	if (!mgr)
 		return NULL;
 
-	mgr->l2cap_conn = conn;
+	mgr->l2cap_conn = hcon->l2cap_data;
 	mgr->next_ident = 1;
 	INIT_LIST_HEAD(&mgr->ctx_list);
 	rwlock_init(&mgr->ctx_list_lock);
 	mgr->skb = skb;
-	BT_DBG("conn %p mgr %p", conn, mgr);
-	mgr->a2mp_sock = open_fixed_channel(conn->src, conn->dst);
+	BT_DBG("hcon %p mgr %p", hcon, mgr);
+	mgr->a2mp_sock = open_fixed_channel(&hcon->hdev->bdaddr, &hcon->dst);
 	if (!mgr->a2mp_sock) {
 		kfree(mgr);
 		return NULL;
@@ -484,7 +484,7 @@
 	struct amp_ctx *ctx = NULL;
 
 	BT_DBG("conn %p", conn);
-	mgr = get_create_amp_mgr(conn, NULL);
+	mgr = get_create_amp_mgr(conn->hcon, NULL);
 	if (!mgr)
 		goto cp_finished;
 	BT_DBG("mgr %p", mgr);
@@ -514,7 +514,7 @@
 	if (!hdev)
 		goto ap_finished;
 	BT_DBG("hdev %p", hdev);
-	mgr = get_create_amp_mgr(lcon, NULL);
+	mgr = get_create_amp_mgr(lcon->hcon, NULL);
 	if (!mgr)
 		goto ap_finished;
 	BT_DBG("mgr %p", mgr);
@@ -1773,12 +1773,13 @@
 static void conn_ind_worker(struct work_struct *w)
 {
 	struct amp_work_conn_ind *work = (struct amp_work_conn_ind *) w;
-	struct l2cap_conn *conn = work->conn;
+	struct hci_conn *hcon = work->hcon;
 	struct sk_buff *skb = work->skb;
 	struct amp_mgr *mgr;
 
-	mgr = get_create_amp_mgr(conn, skb);
+	mgr = get_create_amp_mgr(hcon, skb);
 	BT_DBG("mgr %p", mgr);
+	hci_conn_put(hcon);
 	kfree(work);
 }
 
@@ -1804,17 +1805,20 @@
 
 /* L2CAP Fixed Channel interface */
 
-void amp_conn_ind(struct l2cap_conn *conn, struct sk_buff *skb)
+void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb)
 {
 	struct amp_work_conn_ind *work;
-	BT_DBG("conn %p, skb %p", conn, skb);
+	BT_DBG("hcon %p, skb %p", hcon, skb);
 	work = kmalloc(sizeof(*work), GFP_ATOMIC);
 	if (work) {
 		INIT_WORK((struct work_struct *) work, conn_ind_worker);
-		work->conn = conn;
+		hci_conn_hold(hcon);
+		work->hcon = hcon;
 		work->skb = skb;
-		if (queue_work(amp_workqueue, (struct work_struct *) work) == 0)
+		if (!queue_work(amp_workqueue, (struct work_struct *) work)) {
+			hci_conn_put(hcon);
 			kfree(work);
+		}
 	}
 }
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 899c538..f87be20 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -225,6 +225,18 @@
 }
 EXPORT_SYMBOL(hci_le_conn_update);
 
+void hci_read_rssi(struct hci_conn *conn)
+{
+	struct hci_cp_read_rssi cp;
+	struct hci_dev *hdev = conn->hdev;
+
+	memset(&cp, 0, sizeof(cp));
+	cp.handle   = cpu_to_le16(conn->handle);
+
+	hci_send_cmd(hdev, HCI_OP_READ_RSSI, sizeof(cp), &cp);
+}
+EXPORT_SYMBOL(hci_read_rssi);
+
 void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 							__u8 ltk[16])
 {
@@ -340,6 +352,18 @@
 	hci_conn_enter_sniff_mode(conn);
 }
 
+static void hci_conn_rssi_update(struct work_struct *work)
+{
+	struct delayed_work *delayed =
+		container_of(work, struct delayed_work, work);
+	struct hci_conn *conn =
+		container_of(delayed, struct hci_conn, rssi_update_work);
+
+	BT_DBG("conn %p mode %d", conn, conn->mode);
+
+	hci_read_rssi(conn);
+}
+
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
 					__u16 pkt_type, bdaddr_t *dst)
 {
@@ -392,6 +416,7 @@
 
 	setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
 	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
+	INIT_DELAYED_WORK(&conn->rssi_update_work, hci_conn_rssi_update);
 
 	atomic_set(&conn->refcnt, 0);
 
@@ -434,6 +459,7 @@
 	del_timer(&conn->idle_timer);
 	del_timer(&conn->disc_timer);
 	del_timer(&conn->smp_timer);
+	__cancel_delayed_work(&conn->rssi_update_work);
 
 	if (conn->type == ACL_LINK) {
 		struct hci_conn *sco = conn->link;
@@ -494,6 +520,7 @@
 
 	return chan;
 }
+EXPORT_SYMBOL(hci_chan_add);
 
 int hci_chan_del(struct hci_chan *chan)
 {
@@ -728,7 +755,7 @@
 {
 	BT_DBG("conn %p", conn);
 
-	hci_proto_disconn_cfm(conn, reason);
+	hci_proto_disconn_cfm(conn, reason, 0);
 }
 EXPORT_SYMBOL(hci_disconnect);
 
@@ -787,6 +814,10 @@
 
 	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 		struct hci_cp_auth_requested cp;
+
+		/* encrypt must be pending if auth is also pending */
+		set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+
 		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
 							sizeof(cp), &cp);
@@ -817,7 +848,7 @@
 		return 0;
 	} else if (conn->link_mode & HCI_LM_ENCRYPT) {
 		return hci_conn_auth(conn, sec_level, auth_type);
-	} else if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+	} else if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
 		return 0;
 	}
 
@@ -896,6 +927,43 @@
 			jiffies + msecs_to_jiffies(hdev->idle_timeout));
 }
 
+static inline void hci_conn_stop_rssi_timer(struct hci_conn *conn)
+{
+	BT_DBG("conn %p", conn);
+	cancel_delayed_work(&conn->rssi_update_work);
+}
+
+static inline void hci_conn_start_rssi_timer(struct hci_conn *conn,
+	u16 interval)
+{
+	struct hci_dev *hdev = conn->hdev;
+	BT_DBG("conn %p, pending %d", conn,
+			delayed_work_pending(&conn->rssi_update_work));
+	if (!delayed_work_pending(&conn->rssi_update_work)) {
+		queue_delayed_work(hdev->workqueue, &conn->rssi_update_work,
+				msecs_to_jiffies(interval));
+	}
+}
+
+void hci_conn_set_rssi_reporter(struct hci_conn *conn,
+	s8 rssi_threshold, u16 interval, u8 updateOnThreshExceed)
+{
+	if (conn) {
+		conn->rssi_threshold = rssi_threshold;
+		conn->rssi_update_interval = interval;
+		conn->rssi_update_thresh_exceed = updateOnThreshExceed;
+		hci_conn_start_rssi_timer(conn, interval);
+	}
+}
+
+void hci_conn_unset_rssi_reporter(struct hci_conn *conn)
+{
+	if (conn) {
+		BT_DBG("Deleting the rssi_update_timer");
+		hci_conn_stop_rssi_timer(conn);
+	}
+}
+
 /* Enter sniff mode */
 void hci_conn_enter_sniff_mode(struct hci_conn *conn)
 {
@@ -934,18 +1002,12 @@
 	}
 }
 
-struct hci_chan *hci_chan_accept(struct hci_conn *conn,
+struct hci_chan *hci_chan_create(struct hci_chan *chan,
 			struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
 {
-	struct hci_chan *chan;
 	struct hci_cp_create_logical_link cp;
 
-	chan = hci_chan_add(conn->hdev);
-	if (!chan)
-		return NULL;
-
 	chan->state = BT_CONNECT;
-	chan->conn = conn;
 	chan->tx_fs = *tx_fs;
 	chan->rx_fs = *rx_fs;
 	cp.phy_handle = chan->conn->handle;
@@ -962,40 +1024,12 @@
 	cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency);
 	cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to);
 	hci_conn_hold(chan->conn);
-	hci_send_cmd(conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), &cp);
-	return chan;
-}
-EXPORT_SYMBOL(hci_chan_accept);
-
-struct hci_chan *hci_chan_create(struct hci_conn *conn,
-			struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
-{
-	struct hci_chan *chan;
-	struct hci_cp_create_logical_link cp;
-
-	chan = hci_chan_add(conn->hdev);
-	if (!chan)
-		return NULL;
-
-	chan->state = BT_CONNECT;
-	chan->conn = conn;
-	chan->tx_fs = *tx_fs;
-	chan->rx_fs = *rx_fs;
-	cp.phy_handle = chan->conn->handle;
-	cp.tx_fs.id = chan->tx_fs.id;
-	cp.tx_fs.type = chan->tx_fs.type;
-	cp.tx_fs.max_sdu = cpu_to_le16(chan->tx_fs.max_sdu);
-	cp.tx_fs.sdu_arr_time = cpu_to_le32(chan->tx_fs.sdu_arr_time);
-	cp.tx_fs.acc_latency = cpu_to_le32(chan->tx_fs.acc_latency);
-	cp.tx_fs.flush_to = cpu_to_le32(chan->tx_fs.flush_to);
-	cp.rx_fs.id = chan->rx_fs.id;
-	cp.rx_fs.type = chan->rx_fs.type;
-	cp.rx_fs.max_sdu = cpu_to_le16(chan->rx_fs.max_sdu);
-	cp.rx_fs.sdu_arr_time = cpu_to_le32(chan->rx_fs.sdu_arr_time);
-	cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency);
-	cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to);
-	hci_conn_hold(chan->conn);
-	hci_send_cmd(conn->hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), &cp);
+	if (chan->conn->out)
+		hci_send_cmd(chan->conn->hdev, HCI_OP_CREATE_LOGICAL_LINK,
+							sizeof(cp), &cp);
+	else
+		hci_send_cmd(chan->conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK,
+							sizeof(cp), &cp);
 	return chan;
 }
 EXPORT_SYMBOL(hci_chan_create);
@@ -1027,7 +1061,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 +1077,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
old mode 100644
new mode 100755
index fec6f32..f57113b
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -940,6 +940,21 @@
 	hci_dev_unlock(hdev);
 }
 
+static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_conn *conn;
+	struct hci_rp_read_rssi *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	BT_DBG("%s rssi : %d handle : %d", hdev->name, rp->rssi, rp->handle);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+	if (conn)
+		mgmt_read_rssi_complete(hdev->id, rp->rssi, &conn->dst,
+			__le16_to_cpu(rp->handle), rp->status);
+}
+
 static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
 							struct sk_buff *skb)
 {
@@ -1106,9 +1121,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;
 	}
@@ -1517,7 +1548,7 @@
 
 	BT_DBG("%s status %d", hdev->name, status);
 
-	if (!lmp_le_capable(hdev))
+	if (!hdev->disco_state)
 		clear_bit(HCI_INQUIRY, &hdev->flags);
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY, status);
@@ -1643,6 +1674,15 @@
 	hci_conn_check_pending(hdev);
 }
 
+static inline bool is_sco_active(struct hci_dev *hdev)
+{
+	if (hci_conn_hash_lookup_state(hdev, SCO_LINK, BT_CONNECTED) ||
+			(hci_conn_hash_lookup_state(hdev, ESCO_LINK,
+						    BT_CONNECTED)))
+		return true;
+	return false;
+}
+
 static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_conn_request *ev = (void *) skb->data;
@@ -1688,7 +1728,8 @@
 
 			bacpy(&cp.bdaddr, &ev->bdaddr);
 
-			if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
+			if (lmp_rswitch_capable(hdev) && ((mask & HCI_LM_MASTER)
+						|| is_sco_active(hdev)))
 				cp.role = 0x00; /* Become master */
 			else
 				cp.role = 0x01; /* Remain slave */
@@ -1748,7 +1789,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 +1965,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;
@@ -1937,6 +1980,9 @@
 		hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES,
 							sizeof(cp), &cp);
 		goto unlock;
+	} else  if (!(lmp_ssp_capable(conn)) && conn->auth_initiator &&
+		(conn->pending_sec_level == BT_SECURITY_HIGH)) {
+		conn->pending_sec_level = BT_SECURITY_MEDIUM;
 	}
 
 	if (!ev->status) {
@@ -2159,6 +2205,10 @@
 		hci_cc_le_read_buffer_size(hdev, skb);
 		break;
 
+	case HCI_OP_READ_RSSI:
+		hci_cc_read_rssi(hdev, skb);
+		break;
+
 	case HCI_OP_USER_CONFIRM_REPLY:
 		hci_cc_user_confirm_reply(hdev, skb);
 		break;
@@ -2730,7 +2780,7 @@
 		conn->ssp_mode = (ev->features[0] & 0x01);
 		/*In case if remote device ssp supported/2.0 device
 		reduce the security level to MEDIUM if it is HIGH*/
-		if (!conn->ssp_mode &&
+		if (!conn->ssp_mode && conn->auth_initiator &&
 			(conn->pending_sec_level == BT_SECURITY_HIGH))
 			conn->pending_sec_level = BT_SECURITY_MEDIUM;
 	}
@@ -3289,7 +3339,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..de3ab22 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);
 
@@ -559,17 +559,16 @@
 		read_unlock(&l->lock);
 	}
 
-	if (l2cap_pi(sk)->ampcon) {
-		l2cap_pi(sk)->ampcon->l2cap_data = NULL;
-		l2cap_pi(sk)->ampcon = NULL;
-		l2cap_pi(sk)->amp_id = 0;
-	}
-
 	if (l2cap_pi(sk)->ampchan) {
 		struct hci_chan *ampchan = l2cap_pi(sk)->ampchan;
+		struct hci_conn *ampcon = l2cap_pi(sk)->ampcon;
 		l2cap_pi(sk)->ampchan = NULL;
-		if (!hci_chan_put(ampchan))
-			l2cap_deaggregate(l2cap_pi(sk)->ampchan, l2cap_pi(sk));
+		l2cap_pi(sk)->ampcon = NULL;
+		l2cap_pi(sk)->amp_id = 0;
+		if (hci_chan_put(ampchan))
+			ampcon->l2cap_data = NULL;
+		else
+			l2cap_deaggregate(ampchan, l2cap_pi(sk));
 	}
 
 	sk->sk_state = BT_CLOSED;
@@ -1160,7 +1159,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 +1180,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
@@ -3181,8 +3186,9 @@
 	return 1;
 }
 
-static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct l2cap_pinfo *pi)
+static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct sock *sk)
 {
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct hci_dev *hdev;
 	struct hci_conn *hcon;
 	struct hci_chan *chan;
@@ -3202,19 +3208,23 @@
 	chan = hci_chan_list_lookup_id(hdev, hcon->handle);
 	if (chan) {
 		l2cap_aggregate(chan, pi);
+		sock_hold(sk);
+		chan->l2cap_sk = sk;
+		hci_chan_hold(chan);
+		pi->ampchan = chan;
 		goto done;
 	}
 
-	if (bt_sk(pi)->parent) {
-		/* Incoming connection */
-		chan = hci_chan_accept(hcon,
-					(struct hci_ext_fs *) &pi->local_fs,
-					(struct hci_ext_fs *) &pi->remote_fs);
-	} else {
-		/* Outgoing connection */
-		chan = hci_chan_create(hcon,
-					(struct hci_ext_fs *) &pi->local_fs,
-					(struct hci_ext_fs *) &pi->remote_fs);
+	chan = hci_chan_add(hdev);
+	if (chan) {
+		chan->conn = hcon;
+		sock_hold(sk);
+		chan->l2cap_sk = sk;
+		hci_chan_hold(chan);
+		pi->ampchan = chan;
+		hci_chan_create(chan,
+			(struct hci_ext_fs *) &pi->local_fs,
+			(struct hci_ext_fs *) &pi->remote_fs);
 	}
 done:
 	hci_dev_put(hdev);
@@ -3620,14 +3630,10 @@
 				struct hci_chan *chan;
 				/* Trigger logical link creation only on AMP */
 
-				chan = l2cap_chan_admit(pi->amp_id, pi);
+				chan = l2cap_chan_admit(pi->amp_id, sk);
 				if (!chan)
 					return -ECONNREFUSED;
 
-				hci_chan_hold(chan);
-				pi->ampchan = chan;
-				chan->l2cap_sk = sk;
-
 				if (chan->state == BT_CONNECTED)
 					l2cap_create_cfm(chan, 0);
 			}
@@ -4461,17 +4467,13 @@
 			/* Already sent a 'pending' response, so set up
 			 * the logical link now
 			 */
-			chan = l2cap_chan_admit(pi->amp_id, pi);
+			chan = l2cap_chan_admit(pi->amp_id, sk);
 			if (!chan) {
 				l2cap_send_disconn_req(pi->conn, sk,
 							ECONNRESET);
 				goto done;
 			}
 
-			hci_chan_hold(chan);
-			pi->ampchan = chan;
-			chan->l2cap_sk = sk;
-
 			if (chan->state == BT_CONNECTED)
 				l2cap_create_cfm(chan, 0);
 		}
@@ -4962,15 +4964,16 @@
 			 */
 			pi->amp_move_state =
 				L2CAP_AMP_STATE_WAIT_LOGICAL_CONFIRM;
-		} else if (result == L2CAP_MOVE_CHAN_SUCCESS &&
-			pi->amp_move_state ==
+		} else if (pi->amp_move_state ==
 				L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS) {
-			/* Logical link is up or moving to BR/EDR,
-			 * proceed with move */
-			if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+			if (result == L2CAP_MOVE_CHAN_PENDING) {
+				break;
+			} else if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 				pi->amp_move_state =
 					L2CAP_AMP_STATE_WAIT_LOCAL_BUSY;
 			} else {
+				/* Logical link is up or moving to BR/EDR,
+				 * proceed with move */
 				pi->amp_move_state =
 					L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP;
 				l2cap_send_move_chan_cfm(conn, pi, pi->scid,
@@ -4998,7 +5001,7 @@
 			}
 			pi->remote_fs = default_fs;
 			pi->local_fs = default_fs;
-			chan = l2cap_chan_admit(pi->amp_move_id, pi);
+			chan = l2cap_chan_admit(pi->amp_move_id, sk);
 			if (!chan) {
 				/* Logical link not available */
 				l2cap_send_move_chan_cfm(conn, pi, pi->scid,
@@ -5006,10 +5009,6 @@
 				break;
 			}
 
-			hci_chan_hold(chan);
-			pi->ampchan = chan;
-			chan->l2cap_sk = sk;
-
 			if (chan->state == BT_CONNECTED) {
 				/* Logical link is already ready to go */
 				pi->ampcon = chan->conn;
@@ -5031,6 +5030,10 @@
 			}
 		} else {
 			/* Any other amp move state means the move failed. */
+			pi->amp_move_id = pi->amp_id;
+			pi->amp_move_state = L2CAP_AMP_STATE_STABLE;
+			l2cap_amp_move_revert(sk);
+			pi->amp_move_role = L2CAP_AMP_MOVE_NONE;
 			l2cap_send_move_chan_cfm(conn, pi, pi->scid,
 						L2CAP_MOVE_CHAN_UNCONFIRMED);
 			l2cap_sock_set_timer(sk, L2CAP_MOVE_TIMEOUT);
@@ -5109,14 +5112,14 @@
 			pi->amp_id = pi->amp_move_id;
 			if (!pi->amp_id && pi->ampchan) {
 				struct hci_chan *ampchan = pi->ampchan;
+				struct hci_conn *ampcon = pi->ampcon;
 				/* Have moved off of AMP, free the channel */
 				pi->ampchan = NULL;
-				if (pi->ampcon)
-					pi->ampcon->l2cap_data = NULL;
 				pi->ampcon = NULL;
-
-				if (!hci_chan_put(ampchan))
-					l2cap_deaggregate(pi->ampchan, pi);
+				if (hci_chan_put(ampchan))
+					ampcon->l2cap_data = NULL;
+				else
+					l2cap_deaggregate(ampchan, pi);
 			}
 			l2cap_amp_move_success(sk);
 		} else {
@@ -5169,16 +5172,15 @@
 		pi->amp_move_state = L2CAP_AMP_STATE_STABLE;
 		pi->amp_id = pi->amp_move_id;
 
-		if (!pi->amp_id) {
+		if (!pi->amp_id && pi->ampchan) {
 			struct hci_chan *ampchan = pi->ampchan;
-
+			struct hci_conn *ampcon = pi->ampcon;
 			/* Have moved off of AMP, free the channel */
 			pi->ampchan = NULL;
-			if (pi->ampcon)
-				pi->ampcon->l2cap_data = NULL;
 			pi->ampcon = NULL;
-
-			if (ampchan && !hci_chan_put(ampchan))
+			if (hci_chan_put(ampchan))
+				ampcon->l2cap_data = NULL;
+			else
 				l2cap_deaggregate(ampchan, pi);
 		}
 
@@ -5314,12 +5316,8 @@
 				0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
 		pi->remote_fs = default_fs;
 		pi->local_fs = default_fs;
-		chan = l2cap_chan_admit(local_id, pi);
+		chan = l2cap_chan_admit(local_id, sk);
 		if (chan) {
-			hci_chan_hold(chan);
-			pi->ampchan = chan;
-			chan->l2cap_sk = sk;
-
 			if (chan->state == BT_CONNECTED) {
 				/* Logical link is ready to go */
 				pi->ampcon = chan->conn;
@@ -5378,6 +5376,7 @@
 	struct l2cap_pinfo *pi;
 	struct sock *sk;
 	struct hci_chan *ampchan;
+	struct hci_conn *ampcon;
 
 	BT_DBG("status %d, chan %p, conn %p", (int) status, chan, chan->conn);
 
@@ -5399,6 +5398,8 @@
 		pi->ampcon = chan->conn;
 		pi->ampcon->l2cap_data = pi->conn;
 
+		BT_DBG("amp_move_state %d", pi->amp_move_state);
+
 		if (sk->sk_state != BT_CONNECTED) {
 			struct l2cap_conf_rsp rsp;
 
@@ -5450,19 +5451,24 @@
 					pi->amp_move_cmd_ident, pi->dcid,
 					L2CAP_MOVE_CHAN_SUCCESS);
 			}
-		} else {
+		} else if ((pi->amp_move_state !=
+				L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS) &&
+			(pi->amp_move_state !=
+				L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM) &&
+			(pi->amp_move_state !=
+				L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP)) {
+			/* Move was not in expected state, free the channel */
 			ampchan = pi->ampchan;
-
-			/* Move was not in expected state, free the
-			 * logical link
-			 */
+			ampcon = pi->ampcon;
 			pi->ampchan = NULL;
-			if (pi->ampcon)
-				pi->ampcon->l2cap_data = NULL;
 			pi->ampcon = NULL;
-
-			if (ampchan && !hci_chan_put(ampchan))
-				l2cap_deaggregate(ampchan, pi);
+			if (ampchan) {
+				if (hci_chan_put(ampchan))
+					ampcon->l2cap_data = NULL;
+				else
+					l2cap_deaggregate(ampchan, pi);
+			}
+			pi->amp_move_state = L2CAP_AMP_STATE_STABLE;
 		}
 	} else {
 		/* Logical link setup failed. */
@@ -5497,16 +5503,16 @@
 						L2CAP_MOVE_CHAN_UNCONFIRMED);
 			l2cap_sock_set_timer(sk, L2CAP_MOVE_TIMEOUT);
 		}
-
 		ampchan = pi->ampchan;
-
+		ampcon = pi->ampcon;
 		pi->ampchan = NULL;
-		if (pi->ampcon)
-			pi->ampcon->l2cap_data = NULL;
 		pi->ampcon = NULL;
-
-		if (ampchan && !hci_chan_put(ampchan))
-			l2cap_deaggregate(ampchan, pi);
+		if (ampchan) {
+			if (hci_chan_put(ampchan))
+				ampcon->l2cap_data = NULL;
+			else
+				l2cap_deaggregate(ampchan, pi);
+		}
 	}
 
 	release_sock(sk);
@@ -5529,9 +5535,7 @@
 {
 	struct l2cap_logical_link_work *amp_work;
 
-	if (chan->l2cap_sk) {
-		sock_hold(chan->l2cap_sk);
-	} else {
+	if (!chan->l2cap_sk) {
 		BT_ERR("Expected l2cap_sk to point to connecting socket");
 		return -EFAULT;
 	}
@@ -5587,15 +5591,13 @@
 		bh_lock_sock(sk);
 		/* TODO MM/PK - What to do if connection is LOCAL_BUSY?  */
 		if (l2cap_pi(sk)->ampchan == chan) {
-			struct hci_chan *ampchan = l2cap_pi(sk)->ampchan;
-
+			struct hci_conn *ampcon = l2cap_pi(sk)->ampcon;
 			l2cap_pi(sk)->ampchan = NULL;
-			if (l2cap_pi(sk)->ampcon)
-				l2cap_pi(sk)->ampcon->l2cap_data = NULL;
 			l2cap_pi(sk)->ampcon = NULL;
-
-			if (ampchan && !hci_chan_put(ampchan))
-				l2cap_deaggregate(ampchan, l2cap_pi(sk));
+			if (hci_chan_put(chan))
+				ampcon->l2cap_data = NULL;
+			else
+				l2cap_deaggregate(chan, l2cap_pi(sk));
 
 			l2cap_amp_move_init(sk);
 		}
@@ -7332,7 +7334,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:
@@ -7348,7 +7350,7 @@
 			bh_unlock_sock(sk);
 		} else if (cid == L2CAP_CID_A2MP) {
 			BT_DBG("A2MP");
-			amp_conn_ind(conn, skb);
+			amp_conn_ind(conn->hcon, skb);
 		} else {
 			BT_DBG("unknown cid 0x%4.4x", cid);
 			kfree_skb(skb);
@@ -7407,7 +7409,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 +7426,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..52c1fe6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1613,9 +1613,8 @@
 
 	hci_dev_lock_bh(hdev);
 
-	BT_DBG("SSP Cap is %d", cp->ssp_cap);
 	io_cap = cp->io_cap;
-	if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
+	if (io_cap == 0x03) {
 		sec_level = BT_SECURITY_MEDIUM;
 		auth_type = HCI_AT_DEDICATED_BONDING;
 	} else {
@@ -1633,6 +1632,7 @@
 			io_cap = 0x01;
 		conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
 								auth_type);
+		conn->auth_initiator = 1;
 	}
 
 	if (IS_ERR(conn)) {
@@ -1810,6 +1810,81 @@
 	return err;
 }
 
+static int set_rssi_reporter(struct sock *sk, u16 index,
+				unsigned char *data, u16 len)
+{
+	struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
+	struct hci_dev *hdev;
+	struct hci_conn *conn;
+	int err = 0;
+
+	if (len != sizeof(*cp))
+		return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
+								EINVAL);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
+							ENODEV);
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+
+	if (!conn) {
+		err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
+						ENOTCONN);
+		goto failed;
+	}
+
+	BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
+	hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
+			__le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
+
+failed:
+	hci_dev_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int unset_rssi_reporter(struct sock *sk, u16 index,
+			unsigned char *data, u16 len)
+{
+	struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
+	struct hci_dev *hdev;
+	struct hci_conn *conn;
+	int err = 0;
+
+	if (len != sizeof(*cp))
+		return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
+					EINVAL);
+
+	hdev = hci_dev_get(index);
+
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
+					ENODEV);
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+
+	if (!conn) {
+		err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
+					ENOTCONN);
+		goto failed;
+	}
+
+	hci_conn_unset_rssi_reporter(conn);
+
+failed:
+	hci_dev_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
 								u16 len)
 {
@@ -2365,6 +2440,12 @@
 	case MGMT_OP_SET_CONNECTION_PARAMS:
 		err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_SET_RSSI_REPORTER:
+		err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
+		break;
+	case MGMT_OP_UNSET_RSSI_REPORTER:
+		err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
+		break;
 	case MGMT_OP_READ_LOCAL_OOB_DATA:
 		err = read_local_oob_data(sk, index);
 		break;
@@ -2672,8 +2753,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))
@@ -2814,6 +2898,57 @@
 	return err;
 }
 
+void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
+		u16 handle, u8 status)
+{
+	struct mgmt_ev_rssi_update ev;
+	struct hci_conn *conn;
+	struct hci_dev *hdev;
+
+	if (status)
+		return;
+
+	hdev = hci_dev_get(index);
+	conn = hci_conn_hash_lookup_handle(hdev, handle);
+
+	if (!conn)
+		return;
+
+	BT_DBG("rssi_update_thresh_exceed : %d ",
+		   conn->rssi_update_thresh_exceed);
+	BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
+			conn->rssi_threshold, rssi);
+
+	if (conn->rssi_update_thresh_exceed == 1) {
+		BT_DBG("rssi_update_thresh_exceed == 1");
+		if (rssi > conn->rssi_threshold) {
+			memset(&ev, 0, sizeof(ev));
+			bacpy(&ev.bdaddr, bdaddr);
+			ev.rssi = rssi;
+			mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
+				sizeof(ev), NULL);
+		} else {
+			hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
+				conn->rssi_update_interval,
+				conn->rssi_update_thresh_exceed);
+		}
+	} else {
+		BT_DBG("rssi_update_thresh_exceed == 0");
+		if (rssi < conn->rssi_threshold) {
+			memset(&ev, 0, sizeof(ev));
+			bacpy(&ev.bdaddr, bdaddr);
+			ev.rssi = rssi;
+			mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
+				sizeof(ev), NULL);
+		} else {
+			hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
+				conn->rssi_update_interval,
+				conn->rssi_update_thresh_exceed);
+		}
+	}
+}
+
+
 int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
 			u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
 {
@@ -2929,3 +3064,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/net/bridge/br_device.c b/net/bridge/br_device.c
index a9dd166..dac6a21 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -92,7 +92,6 @@
 {
 	struct net_bridge *br = netdev_priv(dev);
 
-	netif_carrier_off(dev);
 	netdev_update_features(dev);
 	netif_start_queue(dev);
 	br_stp_enable_bridge(br);
@@ -109,8 +108,6 @@
 {
 	struct net_bridge *br = netdev_priv(dev);
 
-	netif_carrier_off(dev);
-
 	br_stp_disable_bridge(br);
 	br_multicast_stop(br);
 
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 6f156c1..4490873 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -161,9 +161,10 @@
 	call_rcu(&p->rcu, destroy_nbp_rcu);
 }
 
-/* called with RTNL */
-static void del_br(struct net_bridge *br, struct list_head *head)
+/* Delete bridge device */
+void br_dev_delete(struct net_device *dev, struct list_head *head)
 {
+	struct net_bridge *br = netdev_priv(dev);
 	struct net_bridge_port *p, *n;
 
 	list_for_each_entry_safe(p, n, &br->port_list, list) {
@@ -268,7 +269,7 @@
 	}
 
 	else
-		del_br(netdev_priv(dev), NULL);
+		br_dev_delete(dev, NULL);
 
 	rtnl_unlock();
 	return ret;
@@ -445,7 +446,7 @@
 	rtnl_lock();
 	for_each_netdev(net, dev)
 		if (dev->priv_flags & IFF_EBRIDGE)
-			del_br(netdev_priv(dev), &list);
+			br_dev_delete(dev, &list);
 
 	unregister_netdevice_many(&list);
 	rtnl_unlock();
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 56149ec..3dc7f54 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -343,24 +343,26 @@
 static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
 {
 	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+	struct neighbour *neigh;
 	struct dst_entry *dst;
 
 	skb->dev = bridge_parent(skb->dev);
 	if (!skb->dev)
 		goto free_skb;
 	dst = skb_dst(skb);
+	neigh = dst_get_neighbour(dst);
 	if (dst->hh) {
 		neigh_hh_bridge(dst->hh, skb);
 		skb->dev = nf_bridge->physindev;
 		return br_handle_frame_finish(skb);
-	} else if (dst->neighbour) {
+	} else if (neigh) {
 		/* the neighbour function below overwrites the complete
 		 * MAC header, so we save the Ethernet source address and
 		 * protocol number. */
 		skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
 		/* tell br_dev_xmit to continue with forwarding */
 		nf_bridge->mask |= BRNF_BRIDGED_DNAT;
-		return dst->neighbour->output(skb);
+		return neigh->output(skb);
 	}
 free_skb:
 	kfree_skb(skb);
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index ffb0dc4..2c16055 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -208,6 +208,7 @@
 	.priv_size	= sizeof(struct net_bridge),
 	.setup		= br_dev_setup,
 	.validate	= br_validate,
+	.dellink	= br_dev_delete,
 };
 
 int __init br_netlink_init(void)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 78cc364..857a021 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -294,6 +294,7 @@
 
 /* br_device.c */
 extern void br_dev_setup(struct net_device *dev);
+extern void br_dev_delete(struct net_device *dev, struct list_head *list);
 extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
 			       struct net_device *dev);
 #ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index 682c0fe..5ba4366 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -53,7 +53,6 @@
 	struct caif_net *caifn;
 	BUG_ON(!net);
 	caifn = net_generic(net, caif_net_id);
-	BUG_ON(!caifn);
 	return caifn->cfg;
 }
 EXPORT_SYMBOL(get_cfcnfg);
@@ -63,7 +62,6 @@
 	struct caif_net *caifn;
 	BUG_ON(!net);
 	caifn = net_generic(net, caif_net_id);
-	BUG_ON(!caifn);
 	return &caifn->caifdevs;
 }
 
@@ -92,7 +90,6 @@
 	struct caif_device_entry *caifd;
 
 	caifdevs = caif_device_list(dev_net(dev));
-	BUG_ON(!caifdevs);
 
 	caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC);
 	if (!caifd)
@@ -108,7 +105,7 @@
 	struct caif_device_entry_list *caifdevs =
 	    caif_device_list(dev_net(dev));
 	struct caif_device_entry *caifd;
-	BUG_ON(!caifdevs);
+
 	list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
 		if (caifd->netdev == dev)
 			return caifd;
@@ -209,8 +206,7 @@
 	enum cfcnfg_phy_preference pref;
 	enum cfcnfg_phy_type phy_type;
 	struct cfcnfg *cfg;
-	struct caif_device_entry_list *caifdevs =
-	    caif_device_list(dev_net(dev));
+	struct caif_device_entry_list *caifdevs;
 
 	if (dev->type != ARPHRD_CAIF)
 		return 0;
@@ -219,6 +215,8 @@
 	if (cfg == NULL)
 		return 0;
 
+	caifdevs = caif_device_list(dev_net(dev));
+
 	switch (what) {
 	case NETDEV_REGISTER:
 		caifd = caif_device_alloc(dev);
@@ -348,7 +346,7 @@
 static int caif_init_net(struct net *net)
 {
 	struct caif_net *caifn = net_generic(net, caif_net_id);
-	BUG_ON(!caifn);
+
 	INIT_LIST_HEAD(&caifn->caifdevs.list);
 	mutex_init(&caifn->caifdevs.lock);
 
@@ -413,7 +411,7 @@
 {
 	int result;
 
-	result = register_pernet_device(&caif_net_ops);
+	result = register_pernet_subsys(&caif_net_ops);
 
 	if (result)
 		return result;
@@ -426,7 +424,7 @@
 
 static void __exit caif_device_exit(void)
 {
-	unregister_pernet_device(&caif_net_ops);
+	unregister_pernet_subsys(&caif_net_ops);
 	unregister_netdevice_notifier(&caif_device_notifier);
 	dev_remove_pack(&caif_packet_type);
 }
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index 52fe33b..bca32d7 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -313,7 +313,6 @@
 	int err;
 	struct cfctrl_link_param param;
 	struct cfcnfg *cfg = get_cfcnfg(net);
-	caif_assert(cfg != NULL);
 
 	rcu_read_lock();
 	err = caif_connect_req_to_link_param(cfg, conn_req, &param);
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 184a657..c6cc66f 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -343,6 +343,18 @@
 	}
 }
 
+static void bcm_tx_start_timer(struct bcm_op *op)
+{
+	if (op->kt_ival1.tv64 && op->count)
+		hrtimer_start(&op->timer,
+			      ktime_add(ktime_get(), op->kt_ival1),
+			      HRTIMER_MODE_ABS);
+	else if (op->kt_ival2.tv64)
+		hrtimer_start(&op->timer,
+			      ktime_add(ktime_get(), op->kt_ival2),
+			      HRTIMER_MODE_ABS);
+}
+
 static void bcm_tx_timeout_tsklet(unsigned long data)
 {
 	struct bcm_op *op = (struct bcm_op *)data;
@@ -364,26 +376,12 @@
 
 			bcm_send_to_user(op, &msg_head, NULL, 0);
 		}
-	}
-
-	if (op->kt_ival1.tv64 && (op->count > 0)) {
-
-		/* send (next) frame */
 		bcm_can_tx(op);
-		hrtimer_start(&op->timer,
-			      ktime_add(ktime_get(), op->kt_ival1),
-			      HRTIMER_MODE_ABS);
 
-	} else {
-		if (op->kt_ival2.tv64) {
+	} else if (op->kt_ival2.tv64)
+		bcm_can_tx(op);
 
-			/* send (next) frame */
-			bcm_can_tx(op);
-			hrtimer_start(&op->timer,
-				      ktime_add(ktime_get(), op->kt_ival2),
-				      HRTIMER_MODE_ABS);
-		}
-	}
+	bcm_tx_start_timer(op);
 }
 
 /*
@@ -963,23 +961,20 @@
 			hrtimer_cancel(&op->timer);
 	}
 
-	if ((op->flags & STARTTIMER) &&
-	    ((op->kt_ival1.tv64 && op->count) || op->kt_ival2.tv64)) {
-
+	if (op->flags & STARTTIMER) {
+		hrtimer_cancel(&op->timer);
 		/* spec: send can_frame when starting timer */
 		op->flags |= TX_ANNOUNCE;
-
-		if (op->kt_ival1.tv64 && (op->count > 0)) {
-			/* op->count-- is done in bcm_tx_timeout_handler */
-			hrtimer_start(&op->timer, op->kt_ival1,
-				      HRTIMER_MODE_REL);
-		} else
-			hrtimer_start(&op->timer, op->kt_ival2,
-				      HRTIMER_MODE_REL);
 	}
 
-	if (op->flags & TX_ANNOUNCE)
+	if (op->flags & TX_ANNOUNCE) {
 		bcm_can_tx(op);
+		if (op->count)
+			op->count--;
+	}
+
+	if (op->flags & STARTTIMER)
+		bcm_tx_start_timer(op);
 
 	return msg_head->nframes * CFSIZ + MHSIZ;
 }
diff --git a/net/core/dev.c b/net/core/dev.c
index 9c58c1e..f14f601 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6105,6 +6105,7 @@
 	*/
 	call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
 	call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
+	rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
 
 	/*
 	 *	Flush the unicast and multicast chains
diff --git a/net/core/dst.c b/net/core/dst.c
index 6135f36..8246d47 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -171,7 +171,7 @@
 	dst_init_metrics(dst, dst_default_metrics, true);
 	dst->expires = 0UL;
 	dst->path = dst;
-	dst->neighbour = NULL;
+	RCU_INIT_POINTER(dst->_neighbour, NULL);
 	dst->hh = NULL;
 #ifdef CONFIG_XFRM
 	dst->xfrm = NULL;
@@ -231,7 +231,7 @@
 	smp_rmb();
 
 again:
-	neigh = dst->neighbour;
+	neigh = rcu_dereference_protected(dst->_neighbour, 1);
 	hh = dst->hh;
 	child = dst->child;
 
@@ -240,7 +240,7 @@
 		hh_cache_put(hh);
 
 	if (neigh) {
-		dst->neighbour = NULL;
+		RCU_INIT_POINTER(dst->_neighbour, NULL);
 		neigh_release(neigh);
 	}
 
@@ -367,14 +367,19 @@
 	if (!unregister) {
 		dst->input = dst->output = dst_discard;
 	} else {
+		struct neighbour *neigh;
+
 		dst->dev = dev_net(dst->dev)->loopback_dev;
 		dev_hold(dst->dev);
 		dev_put(dev);
-		if (dst->neighbour && dst->neighbour->dev == dev) {
-			dst->neighbour->dev = dst->dev;
+		rcu_read_lock();
+		neigh = dst_get_neighbour(dst);
+		if (neigh && neigh->dev == dev) {
+			neigh->dev = dst->dev;
 			dev_hold(dst->dev);
 			dev_put(dev);
 		}
+		rcu_read_unlock();
 	}
 }
 
diff --git a/net/core/flow.c b/net/core/flow.c
index 990703b..a6bda2a 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -172,29 +172,26 @@
 
 static u32 flow_hash_code(struct flow_cache *fc,
 			  struct flow_cache_percpu *fcp,
-			  const struct flowi *key)
+			  const struct flowi *key,
+			  size_t keysize)
 {
 	const u32 *k = (const u32 *) key;
+	const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32);
 
-	return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd)
+	return jhash2(k, length, fcp->hash_rnd)
 		& (flow_cache_hash_size(fc) - 1);
 }
 
-typedef unsigned long flow_compare_t;
-
 /* I hear what you're saying, use memcmp.  But memcmp cannot make
- * important assumptions that we can here, such as alignment and
- * constant size.
+ * important assumptions that we can here, such as alignment.
  */
-static int flow_key_compare(const struct flowi *key1, const struct flowi *key2)
+static int flow_key_compare(const struct flowi *key1, const struct flowi *key2,
+			    size_t keysize)
 {
 	const flow_compare_t *k1, *k1_lim, *k2;
-	const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t);
-
-	BUILD_BUG_ON(sizeof(struct flowi) % sizeof(flow_compare_t));
 
 	k1 = (const flow_compare_t *) key1;
-	k1_lim = k1 + n_elem;
+	k1_lim = k1 + keysize;
 
 	k2 = (const flow_compare_t *) key2;
 
@@ -215,6 +212,7 @@
 	struct flow_cache_entry *fle, *tfle;
 	struct hlist_node *entry;
 	struct flow_cache_object *flo;
+	size_t keysize;
 	unsigned int hash;
 
 	local_bh_disable();
@@ -222,6 +220,11 @@
 
 	fle = NULL;
 	flo = NULL;
+
+	keysize = flow_key_size(family);
+	if (!keysize)
+		goto nocache;
+
 	/* Packet really early in init?  Making flow_cache_init a
 	 * pre-smp initcall would solve this.  --RR */
 	if (!fcp->hash_table)
@@ -230,11 +233,11 @@
 	if (fcp->hash_rnd_recalc)
 		flow_new_hash_rnd(fc, fcp);
 
-	hash = flow_hash_code(fc, fcp, key);
+	hash = flow_hash_code(fc, fcp, key, keysize);
 	hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) {
 		if (tfle->family == family &&
 		    tfle->dir == dir &&
-		    flow_key_compare(key, &tfle->key) == 0) {
+		    flow_key_compare(key, &tfle->key, keysize) == 0) {
 			fle = tfle;
 			break;
 		}
@@ -248,7 +251,7 @@
 		if (fle) {
 			fle->family = family;
 			fle->dir = dir;
-			memcpy(&fle->key, key, sizeof(*key));
+			memcpy(&fle->key, key, keysize * sizeof(flow_compare_t));
 			fle->object = NULL;
 			hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]);
 			fcp->hash_count++;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 16db887..8c54aff 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1173,12 +1173,17 @@
 
 		while (neigh->nud_state & NUD_VALID &&
 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
-			struct neighbour *n1 = neigh;
+			struct dst_entry *dst = skb_dst(skb);
+			struct neighbour *n2, *n1 = neigh;
 			write_unlock_bh(&neigh->lock);
+
+			rcu_read_lock();
 			/* On shaper/eql skb->dst->neighbour != neigh :( */
-			if (skb_dst(skb) && skb_dst(skb)->neighbour)
-				n1 = skb_dst(skb)->neighbour;
+			if (dst && (n2 = dst_get_neighbour(dst)) != NULL)
+				n1 = n2;
 			n1->output(skb);
+			rcu_read_unlock();
+
 			write_lock_bh(&neigh->lock);
 		}
 		skb_queue_purge(&neigh->arp_queue);
@@ -1300,10 +1305,10 @@
 int neigh_resolve_output(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
-	struct neighbour *neigh;
+	struct neighbour *neigh = dst_get_neighbour(dst);
 	int rc = 0;
 
-	if (!dst || !(neigh = dst->neighbour))
+	if (!dst)
 		goto discard;
 
 	__skb_pull(skb, skb_network_offset(skb));
@@ -1333,7 +1338,7 @@
 	return rc;
 discard:
 	NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
-		      dst, dst ? dst->neighbour : NULL);
+		      dst, neigh);
 out_kfree_skb:
 	rc = -EINVAL;
 	kfree_skb(skb);
@@ -1347,7 +1352,7 @@
 {
 	int err;
 	struct dst_entry *dst = skb_dst(skb);
-	struct neighbour *neigh = dst->neighbour;
+	struct neighbour *neigh = dst_get_neighbour(dst);
 	struct net_device *dev = neigh->dev;
 	unsigned int seq;
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index ea489db..0b0211d 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -29,6 +29,20 @@
 
 #define INITIAL_NET_GEN_PTRS	13 /* +1 for len +2 for rcu_head */
 
+static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS;
+
+static struct net_generic *net_alloc_generic(void)
+{
+	struct net_generic *ng;
+	size_t generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]);
+
+	ng = kzalloc(generic_size, GFP_KERNEL);
+	if (ng)
+		ng->len = max_gen_ptrs;
+
+	return ng;
+}
+
 static int net_assign_generic(struct net *net, int id, void *data)
 {
 	struct net_generic *ng, *old_ng;
@@ -42,8 +56,7 @@
 	if (old_ng->len >= id)
 		goto assign;
 
-	ng = kzalloc(sizeof(struct net_generic) +
-			id * sizeof(void *), GFP_KERNEL);
+	ng = net_alloc_generic();
 	if (ng == NULL)
 		return -ENOMEM;
 
@@ -58,7 +71,6 @@
 	 * the old copy for kfree after a grace period.
 	 */
 
-	ng->len = id;
 	memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
 
 	rcu_assign_pointer(net->gen, ng);
@@ -159,18 +171,6 @@
 	goto out;
 }
 
-static struct net_generic *net_alloc_generic(void)
-{
-	struct net_generic *ng;
-	size_t generic_size = sizeof(struct net_generic) +
-		INITIAL_NET_GEN_PTRS * sizeof(void *);
-
-	ng = kzalloc(generic_size, GFP_KERNEL);
-	if (ng)
-		ng->len = INITIAL_NET_GEN_PTRS;
-
-	return ng;
-}
 
 #ifdef CONFIG_NET_NS
 static struct kmem_cache *net_cachep;
@@ -481,6 +481,7 @@
 			}
 			return error;
 		}
+		max_gen_ptrs = max_t(unsigned int, max_gen_ptrs, *ops->id);
 	}
 	error = __register_pernet_operations(list, ops);
 	if (error) {
diff --git a/net/core/sock.c b/net/core/sock.c
index 6e81978..aebb419 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1257,6 +1257,7 @@
 			/* It is still raw copy of parent, so invalidate
 			 * destructor and make plain sk_free() */
 			newsk->sk_destruct = NULL;
+			bh_unlock_sock(newsk);
 			sk_free(newsk);
 			newsk = NULL;
 			goto out;
diff --git a/net/core/timestamping.c b/net/core/timestamping.c
index 7e7ca37..97d036a 100644
--- a/net/core/timestamping.c
+++ b/net/core/timestamping.c
@@ -57,9 +57,13 @@
 	case PTP_CLASS_V2_VLAN:
 		phydev = skb->dev->phydev;
 		if (likely(phydev->drv->txtstamp)) {
-			clone = skb_clone(skb, GFP_ATOMIC);
-			if (!clone)
+			if (!atomic_inc_not_zero(&sk->sk_refcnt))
 				return;
+			clone = skb_clone(skb, GFP_ATOMIC);
+			if (!clone) {
+				sock_put(sk);
+				return;
+			}
 			clone->sk = sk;
 			phydev->drv->txtstamp(phydev, clone, type);
 		}
@@ -76,8 +80,11 @@
 	struct sock_exterr_skb *serr;
 	int err;
 
-	if (!hwtstamps)
+	if (!hwtstamps) {
+		sock_put(sk);
+		kfree_skb(skb);
 		return;
+	}
 
 	*skb_hwtstamps(skb) = *hwtstamps;
 	serr = SKB_EXT_ERR(skb);
@@ -86,6 +93,7 @@
 	serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
 	skb->sk = NULL;
 	err = sock_queue_err_skb(sk, skb);
+	sock_put(sk);
 	if (err)
 		kfree_skb(skb);
 }
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index 602dade..9810610 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -208,7 +208,7 @@
 {
 	struct dst_entry *dst = skb_dst(skb);
 	struct dn_route *rt = (struct dn_route *)dst;
-	struct neighbour *neigh = dst->neighbour;
+	struct neighbour *neigh = dst_get_neighbour(dst);
 	struct net_device *dev = neigh->dev;
 	char mac_addr[ETH_ALEN];
 
@@ -227,7 +227,7 @@
 static int dn_long_output(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
-	struct neighbour *neigh = dst->neighbour;
+	struct neighbour *neigh = dst_get_neighbour(dst);
 	struct net_device *dev = neigh->dev;
 	int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
 	unsigned char *data;
@@ -274,7 +274,7 @@
 static int dn_short_output(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
-	struct neighbour *neigh = dst->neighbour;
+	struct neighbour *neigh = dst_get_neighbour(dst);
 	struct net_device *dev = neigh->dev;
 	int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
 	struct dn_short_packet *sp;
@@ -318,7 +318,7 @@
 static int dn_phase3_output(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
-	struct neighbour *neigh = dst->neighbour;
+	struct neighbour *neigh = dst_get_neighbour(dst);
 	struct net_device *dev = neigh->dev;
 	int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
 	struct dn_short_packet *sp;
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 74544bc..b91b603 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -241,9 +241,11 @@
  */
 static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
+	struct neighbour *n = dst_get_neighbour(dst);
 	u32 min_mtu = 230;
-	struct dn_dev *dn = dst->neighbour ?
-			    rcu_dereference_raw(dst->neighbour->dev->dn_ptr) : NULL;
+	struct dn_dev *dn;
+
+	dn = n ? rcu_dereference_raw(n->dev->dn_ptr) : NULL;
 
 	if (dn && dn->use_long == 0)
 		min_mtu -= 6;
@@ -715,7 +717,7 @@
 
 	int err = -EINVAL;
 
-	if ((neigh = dst->neighbour) == NULL)
+	if ((neigh = dst_get_neighbour(dst)) == NULL)
 		goto error;
 
 	skb->dev = dev;
@@ -750,7 +752,7 @@
 	struct dst_entry *dst = skb_dst(skb);
 	struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr);
 	struct dn_route *rt;
-	struct neighbour *neigh = dst->neighbour;
+	struct neighbour *neigh = dst_get_neighbour(dst);
 	int header_len;
 #ifdef CONFIG_NETFILTER
 	struct net_device *dev = skb->dev;
@@ -833,11 +835,11 @@
 	}
 	rt->rt_type = res->type;
 
-	if (dev != NULL && rt->dst.neighbour == NULL) {
+	if (dev != NULL && dst_get_neighbour(&rt->dst) == NULL) {
 		n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev);
 		if (IS_ERR(n))
 			return PTR_ERR(n);
-		rt->dst.neighbour = n;
+		dst_set_neighbour(&rt->dst, n);
 	}
 
 	if (dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
@@ -1144,7 +1146,7 @@
 	rt->rt_dst_map    = fld.daddr;
 	rt->rt_src_map    = fld.saddr;
 
-	rt->dst.neighbour = neigh;
+	dst_set_neighbour(&rt->dst, neigh);
 	neigh = NULL;
 
 	rt->dst.lastuse = jiffies;
@@ -1416,7 +1418,7 @@
 	rt->fld.flowidn_iif  = in_dev->ifindex;
 	rt->fld.flowidn_mark = fld.flowidn_mark;
 
-	rt->dst.neighbour = neigh;
+	dst_set_neighbour(&rt->dst, neigh);
 	rt->dst.lastuse = jiffies;
 	rt->dst.output = dn_rt_bug;
 	switch(res.type) {
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index c1f4154..36d1440 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -136,8 +136,6 @@
 		memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
 	}
 
-	err = ah->nexthdr;
-
 	kfree(AH_SKB_CB(skb)->tmp);
 	xfrm_output_resume(skb, err);
 }
@@ -264,12 +262,12 @@
 	if (err)
 		goto out;
 
+	err = ah->nexthdr;
+
 	skb->network_header += ah_hlen;
 	memcpy(skb_network_header(skb), work_iph, ihl);
 	__skb_pull(skb, ah_hlen + ihl);
 	skb_set_transport_header(skb, -ihl);
-
-	err = ah->nexthdr;
 out:
 	kfree(AH_SKB_CB(skb)->tmp);
 	xfrm_input_resume(skb, err);
@@ -371,8 +369,6 @@
 		if (err == -EINPROGRESS)
 			goto out;
 
-		if (err == -EBUSY)
-			err = NET_XMIT_DROP;
 		goto out_free;
 	}
 
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 1b74d3b..1d5675e 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -518,26 +518,32 @@
 
 /* END OF OBSOLETE FUNCTIONS */
 
+struct neighbour *__arp_bind_neighbour(struct dst_entry *dst, __be32 nexthop)
+{
+	struct net_device *dev = dst->dev;
+
+	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
+		nexthop = 0;
+	return __neigh_lookup_errno(
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+		dev->type == ARPHRD_ATM ?
+		clip_tbl_hook :
+#endif
+		&arp_tbl, &nexthop, dev);
+}
+
 int arp_bind_neighbour(struct dst_entry *dst)
 {
 	struct net_device *dev = dst->dev;
-	struct neighbour *n = dst->neighbour;
+	struct neighbour *n = dst_get_neighbour(dst);
 
 	if (dev == NULL)
 		return -EINVAL;
 	if (n == NULL) {
-		__be32 nexthop = ((struct rtable *)dst)->rt_gateway;
-		if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
-			nexthop = 0;
-		n = __neigh_lookup_errno(
-#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-					 dev->type == ARPHRD_ATM ?
-					 clip_tbl_hook :
-#endif
-					 &arp_tbl, &nexthop, dev);
+		n = __arp_bind_neighbour(dst, ((struct rtable *)dst)->rt_gateway);
 		if (IS_ERR(n))
 			return PTR_ERR(n);
-		dst->neighbour = n;
+		dst_set_neighbour(dst, n);
 	}
 	return 0;
 }
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 66439a7..c48323a 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1496,7 +1496,9 @@
 			     void __user *buffer,
 			     size_t *lenp, loff_t *ppos)
 {
+	int old_value = *(int *)ctl->data;
 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+	int new_value = *(int *)ctl->data;
 
 	if (write) {
 		struct ipv4_devconf *cnf = ctl->extra1;
@@ -1507,6 +1509,9 @@
 
 		if (cnf == net->ipv4.devconf_dflt)
 			devinet_copy_dflt_conf(net, i);
+		if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1)
+			if ((new_value == 0) && (old_value != 0))
+				rt_cache_flush(net, 0);
 	}
 
 	return ret;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index d577199..e0d42db 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -875,6 +875,8 @@
 		 * to be intended in a v3 query.
 		 */
 		max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
+		if (!max_delay)
+			max_delay = 1;	/* can't mod w/ 0 */
 	} else { /* v3 */
 		if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)))
 			return;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 8871067..d7bb94c 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -731,9 +731,9 @@
 		}
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 		else if (skb->protocol == htons(ETH_P_IPV6)) {
+			struct neighbour *neigh = dst_get_neighbour(skb_dst(skb));
 			const struct in6_addr *addr6;
 			int addr_type;
-			struct neighbour *neigh = skb_dst(skb)->neighbour;
 
 			if (neigh == NULL)
 				goto tx_error;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 0c99db4..51a3eec 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -182,6 +182,8 @@
 	struct rtable *rt = (struct rtable *)dst;
 	struct net_device *dev = dst->dev;
 	unsigned int hh_len = LL_RESERVED_SPACE(dev);
+	struct neighbour *neigh;
+	int res;
 
 	if (rt->rt_type == RTN_MULTICAST) {
 		IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);
@@ -203,10 +205,22 @@
 		skb = skb2;
 	}
 
-	if (dst->hh)
-		return neigh_hh_output(dst->hh, skb);
-	else if (dst->neighbour)
-		return dst->neighbour->output(skb);
+	rcu_read_lock();
+	if (dst->hh) {
+		int res = neigh_hh_output(dst->hh, skb);
+
+		rcu_read_unlock();
+		return res;
+	} else {
+		neigh = dst_get_neighbour(dst);
+		if (neigh) {
+			res = neigh->output(skb);
+
+			rcu_read_unlock();
+			return res;
+		}
+		rcu_read_unlock();
+	}
 
 	if (net_ratelimit())
 		printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index ab7e554..7fbcaba 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -252,6 +252,10 @@
 		}
 	}
 
+	/* no point in waiting if we could not bring up at least one device */
+	if (!ic_first_dev)
+		goto have_carrier;
+
 	/* wait for a carrier on at least one device */
 	start = jiffies;
 	while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) {
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 378b20b..6f06f7f 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -285,6 +285,8 @@
 	if (register_netdevice(dev) < 0)
 		goto failed_free;
 
+	strcpy(nt->parms.name, dev->name);
+
 	dev_hold(dev);
 	ipip_tunnel_link(ipn, nt);
 	return nt;
@@ -759,7 +761,6 @@
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 
 	tunnel->dev = dev;
-	strcpy(tunnel->parms.name, dev->name);
 
 	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
@@ -825,6 +826,7 @@
 static int __net_init ipip_init_net(struct net *net)
 {
 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
+	struct ip_tunnel *t;
 	int err;
 
 	ipn->tunnels[0] = ipn->tunnels_wc;
@@ -848,6 +850,9 @@
 	if ((err = register_netdev(ipn->fb_tunnel_dev)))
 		goto err_reg_dev;
 
+	t = netdev_priv(ipn->fb_tunnel_dev);
+
+	strcpy(t->parms.name, ipn->fb_tunnel_dev->name);
 	return 0;
 
 err_reg_dev:
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 75ef66f..65ff2e5 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -91,6 +91,7 @@
 #include <linux/rcupdate.h>
 #include <linux/times.h>
 #include <linux/slab.h>
+#include <linux/prefetch.h>
 #include <net/dst.h>
 #include <net/net_namespace.h>
 #include <net/protocol.h>
@@ -132,6 +133,9 @@
 static int ip_rt_min_advmss __read_mostly	= 256;
 static int rt_chain_length_max __read_mostly	= 20;
 
+static struct delayed_work expires_work;
+static unsigned long expires_ljiffies;
+
 /*
  *	Interface to generic destination cache.
  */
@@ -412,7 +416,13 @@
 			   "HHUptod\tSpecDst");
 	else {
 		struct rtable *r = v;
-		int len;
+		struct neighbour *n;
+		int len, HHUptod;
+
+		rcu_read_lock();
+		n = dst_get_neighbour(&r->dst);
+		HHUptod = (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0;
+		rcu_read_unlock();
 
 		seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t"
 			      "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
@@ -427,8 +437,7 @@
 			      dst_metric(&r->dst, RTAX_RTTVAR)),
 			r->rt_key_tos,
 			r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1,
-			r->dst.hh ? (r->dst.hh->hh_output ==
-				       dev_queue_xmit) : 0,
+			HHUptod,
 			r->rt_spec_dst, &len);
 
 		seq_printf(seq, "%*s\n", 127 - len, "");
@@ -821,6 +830,97 @@
 	return ONE;
 }
 
+static void rt_check_expire(void)
+{
+	static unsigned int rover;
+	unsigned int i = rover, goal;
+	struct rtable *rth;
+	struct rtable __rcu **rthp;
+	unsigned long samples = 0;
+	unsigned long sum = 0, sum2 = 0;
+	unsigned long delta;
+	u64 mult;
+
+	delta = jiffies - expires_ljiffies;
+	expires_ljiffies = jiffies;
+	mult = ((u64)delta) << rt_hash_log;
+	if (ip_rt_gc_timeout > 1)
+		do_div(mult, ip_rt_gc_timeout);
+	goal = (unsigned int)mult;
+	if (goal > rt_hash_mask)
+		goal = rt_hash_mask + 1;
+	for (; goal > 0; goal--) {
+		unsigned long tmo = ip_rt_gc_timeout;
+		unsigned long length;
+
+		i = (i + 1) & rt_hash_mask;
+		rthp = &rt_hash_table[i].chain;
+
+		if (need_resched())
+			cond_resched();
+
+		samples++;
+
+		if (rcu_dereference_raw(*rthp) == NULL)
+			continue;
+		length = 0;
+		spin_lock_bh(rt_hash_lock_addr(i));
+		while ((rth = rcu_dereference_protected(*rthp,
+					lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) {
+			prefetch(rth->dst.rt_next);
+			if (rt_is_expired(rth)) {
+				*rthp = rth->dst.rt_next;
+				rt_free(rth);
+				continue;
+			}
+			if (rth->dst.expires) {
+				/* Entry is expired even if it is in use */
+				if (time_before_eq(jiffies, rth->dst.expires)) {
+nofree:
+					tmo >>= 1;
+					rthp = &rth->dst.rt_next;
+					/*
+					 * We only count entries on
+					 * a chain with equal hash inputs once
+					 * so that entries for different QOS
+					 * levels, and other non-hash input
+					 * attributes don't unfairly skew
+					 * the length computation
+					 */
+					length += has_noalias(rt_hash_table[i].chain, rth);
+					continue;
+				}
+			} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
+				goto nofree;
+
+			/* Cleanup aged off entries. */
+			*rthp = rth->dst.rt_next;
+			rt_free(rth);
+		}
+		spin_unlock_bh(rt_hash_lock_addr(i));
+		sum += length;
+		sum2 += length*length;
+	}
+	if (samples) {
+		unsigned long avg = sum / samples;
+		unsigned long sd = int_sqrt(sum2 / samples - avg*avg);
+		rt_chain_length_max = max_t(unsigned long,
+					ip_rt_gc_elasticity,
+					(avg + 4*sd) >> FRACT_BITS);
+	}
+	rover = i;
+}
+
+/*
+ * rt_worker_func() is run in process context.
+ * we call rt_check_expire() to scan part of the hash table
+ */
+static void rt_worker_func(struct work_struct *work)
+{
+	rt_check_expire();
+	schedule_delayed_work(&expires_work, ip_rt_gc_interval);
+}
+
 /*
  * Perturbation of rt_genid by a small quantity [1..256]
  * Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
@@ -1593,23 +1693,25 @@
 {
 	struct rtable *rt = (struct rtable *) dst;
 	__be32 orig_gw = rt->rt_gateway;
+	struct neighbour *n, *old_n;
 
 	dst_confirm(&rt->dst);
 
-	neigh_release(rt->dst.neighbour);
-	rt->dst.neighbour = NULL;
-
 	rt->rt_gateway = peer->redirect_learned.a4;
-	if (arp_bind_neighbour(&rt->dst) ||
-	    !(rt->dst.neighbour->nud_state & NUD_VALID)) {
-		if (rt->dst.neighbour)
-			neigh_event_send(rt->dst.neighbour, NULL);
+	n = __arp_bind_neighbour(&rt->dst, rt->rt_gateway);
+	if (IS_ERR(n))
+		return PTR_ERR(n);
+	old_n = xchg(&rt->dst._neighbour, n);
+	if (old_n)
+		neigh_release(old_n);
+	if (!n || !(n->nud_state & NUD_VALID)) {
+		if (n)
+			neigh_event_send(n, NULL);
 		rt->rt_gateway = orig_gw;
 		return -EAGAIN;
 	} else {
 		rt->rt_flags |= RTCF_REDIRECTED;
-		call_netevent_notifiers(NETEVENT_NEIGH_UPDATE,
-					rt->dst.neighbour);
+		call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
 	}
 	return 0;
 }
@@ -3088,6 +3190,13 @@
 		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
+		.procname	= "gc_interval",
+		.data		= &ip_rt_gc_interval,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_jiffies,
+	},
+	{
 		.procname	= "redirect_load",
 		.data		= &ip_rt_redirect_load,
 		.maxlen		= sizeof(int),
@@ -3297,6 +3406,11 @@
 	devinet_init();
 	ip_fib_init();
 
+	INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func);
+	expires_ljiffies = jiffies;
+	schedule_delayed_work(&expires_work,
+		net_random() % ip_rt_gc_interval + ip_rt_gc_interval);
+
 	if (ip_rt_proc_init())
 		printk(KERN_ERR "Unable to create route proc files\n");
 #ifdef CONFIG_XFRM
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index b6771f9..c68040f 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1380,9 +1380,7 @@
 
 	BUG_ON(!pcount);
 
-	/* Tweak before seqno plays */
-	if (!tcp_is_fack(tp) && tcp_is_sack(tp) && tp->lost_skb_hint &&
-	    !before(TCP_SKB_CB(tp->lost_skb_hint)->seq, TCP_SKB_CB(skb)->seq))
+	if (skb == tp->lost_skb_hint)
 		tp->lost_cnt_hint += pcount;
 
 	TCP_SKB_CB(prev)->end_seq += shifted;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 33ffa13..3c37353 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -630,7 +630,7 @@
 	arg.iov[0].iov_len  = sizeof(rep.th);
 
 #ifdef CONFIG_TCP_MD5SIG
-	key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr) : NULL;
+	key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL;
 	if (key) {
 		rep.opt[0] = htonl((TCPOPT_NOP << 24) |
 				   (TCPOPT_NOP << 16) |
@@ -909,18 +909,21 @@
 			}
 			sk_nocaps_add(sk, NETIF_F_GSO_MASK);
 		}
-		if (tcp_alloc_md5sig_pool(sk) == NULL) {
+
+		md5sig = tp->md5sig_info;
+		if (md5sig->entries4 == 0 &&
+		    tcp_alloc_md5sig_pool(sk) == NULL) {
 			kfree(newkey);
 			return -ENOMEM;
 		}
-		md5sig = tp->md5sig_info;
 
 		if (md5sig->alloced4 == md5sig->entries4) {
 			keys = kmalloc((sizeof(*keys) *
 					(md5sig->entries4 + 1)), GFP_ATOMIC);
 			if (!keys) {
 				kfree(newkey);
-				tcp_free_md5sig_pool();
+				if (md5sig->entries4 == 0)
+					tcp_free_md5sig_pool();
 				return -ENOMEM;
 			}
 
@@ -964,6 +967,7 @@
 				kfree(tp->md5sig_info->keys4);
 				tp->md5sig_info->keys4 = NULL;
 				tp->md5sig_info->alloced4 = 0;
+				tcp_free_md5sig_pool();
 			} else if (tp->md5sig_info->entries4 != i) {
 				/* Need to do some manipulation */
 				memmove(&tp->md5sig_info->keys4[i],
@@ -971,7 +975,6 @@
 					(tp->md5sig_info->entries4 - i) *
 					 sizeof(struct tcp4_md5sig_key));
 			}
-			tcp_free_md5sig_pool();
 			return 0;
 		}
 	}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 882e0b0..faf257b 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1134,11 +1134,9 @@
 	sk_mem_uncharge(sk, len);
 	sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
 
-	/* Any change of skb->len requires recalculation of tso
-	 * factor and mss.
-	 */
+	/* Any change of skb->len requires recalculation of tso factor. */
 	if (tcp_skb_pcount(skb) > 1)
-		tcp_set_skb_tso_segs(sk, skb, tcp_current_mss(sk));
+		tcp_set_skb_tso_segs(sk, skb, tcp_skb_mss(skb));
 
 	return 0;
 }
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 981e43e..581fe0a 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -79,13 +79,13 @@
 	struct rtable *rt = (struct rtable *)xdst->route;
 	const struct flowi4 *fl4 = &fl->u.ip4;
 
-	rt->rt_key_dst = fl4->daddr;
-	rt->rt_key_src = fl4->saddr;
-	rt->rt_key_tos = fl4->flowi4_tos;
-	rt->rt_route_iif = fl4->flowi4_iif;
-	rt->rt_iif = fl4->flowi4_iif;
-	rt->rt_oif = fl4->flowi4_oif;
-	rt->rt_mark = fl4->flowi4_mark;
+	xdst->u.rt.rt_key_dst = fl4->daddr;
+	xdst->u.rt.rt_key_src = fl4->saddr;
+	xdst->u.rt.rt_key_tos = fl4->flowi4_tos;
+	xdst->u.rt.rt_route_iif = fl4->flowi4_iif;
+	xdst->u.rt.rt_iif = fl4->flowi4_iif;
+	xdst->u.rt.rt_oif = fl4->flowi4_oif;
+	xdst->u.rt.rt_mark = fl4->flowi4_mark;
 
 	xdst->u.dst.dev = dev;
 	dev_hold(dev);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 713e09d..7c4a2c5 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -656,7 +656,7 @@
 	 * layer address of our nexhop router
 	 */
 
-	if (rt->rt6i_nexthop == NULL)
+	if (dst_get_neighbour_raw(&rt->dst) == NULL)
 		ifa->flags &= ~IFA_F_OPTIMISTIC;
 
 	ifa->idev = idev;
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 2195ae6..4c0f894 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -324,8 +324,6 @@
 #endif
 	}
 
-	err = ah->nexthdr;
-
 	kfree(AH_SKB_CB(skb)->tmp);
 	xfrm_output_resume(skb, err);
 }
@@ -466,12 +464,12 @@
 	if (err)
 		goto out;
 
+	err = ah->nexthdr;
+
 	skb->network_header += ah_hlen;
 	memcpy(skb_network_header(skb), work_iph, hdr_len);
 	__skb_pull(skb, ah_hlen + hdr_len);
 	skb_set_transport_header(skb, -hdr_len);
-
-	err = ah->nexthdr;
 out:
 	kfree(AH_SKB_CB(skb)->tmp);
 	xfrm_input_resume(skb, err);
@@ -583,8 +581,6 @@
 		if (err == -EINPROGRESS)
 			goto out;
 
-		if (err == -EBUSY)
-			err = NET_XMIT_DROP;
 		goto out_free;
 	}
 
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 4076a0b..0f9b37a 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1455,7 +1455,7 @@
 			RT6_TRACE("aging clone %p\n", rt);
 			return -1;
 		} else if ((rt->rt6i_flags & RTF_GATEWAY) &&
-			   (!(rt->rt6i_nexthop->flags & NTF_ROUTER))) {
+			   (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) {
 			RT6_TRACE("purging route %p via non-router but gateway\n",
 				  rt);
 			return -1;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 79d6e82..d1f049b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -100,6 +100,8 @@
 {
 	struct dst_entry *dst = skb_dst(skb);
 	struct net_device *dev = dst->dev;
+	struct neighbour *neigh;
+	int res;
 
 	skb->protocol = htons(ETH_P_IPV6);
 	skb->dev = dev;
@@ -134,10 +136,22 @@
 				skb->len);
 	}
 
-	if (dst->hh)
-		return neigh_hh_output(dst->hh, skb);
-	else if (dst->neighbour)
-		return dst->neighbour->output(skb);
+	rcu_read_lock();
+	if (dst->hh) {
+		res = neigh_hh_output(dst->hh, skb);
+
+		rcu_read_unlock();
+		return res;
+	} else {
+		neigh = dst_get_neighbour(dst);
+		if (neigh) {
+			res = neigh->output(skb);
+
+			rcu_read_unlock();
+			return res;
+		}
+		rcu_read_unlock();
+	}
 
 	IP6_INC_STATS_BH(dev_net(dst->dev),
 			 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
@@ -385,6 +399,7 @@
 	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct inet6_skb_parm *opt = IP6CB(skb);
 	struct net *net = dev_net(dst->dev);
+	struct neighbour *n;
 	u32 mtu;
 
 	if (net->ipv6.devconf_all->forwarding == 0)
@@ -460,11 +475,10 @@
 	   send redirects to source routed frames.
 	   We don't send redirects to frames decapsulated from IPsec.
 	 */
-	if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 &&
-	    !skb_sec_path(skb)) {
+	n = dst_get_neighbour(dst);
+	if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) {
 		struct in6_addr *target = NULL;
 		struct rt6_info *rt;
-		struct neighbour *n = dst->neighbour;
 
 		/*
 		 *	incoming and outgoing devices are the same
@@ -950,8 +964,11 @@
 static int ip6_dst_lookup_tail(struct sock *sk,
 			       struct dst_entry **dst, struct flowi6 *fl6)
 {
-	int err;
 	struct net *net = sock_net(sk);
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+	struct neighbour *n;
+#endif
+	int err;
 
 	if (*dst == NULL)
 		*dst = ip6_route_output(net, sk, fl6);
@@ -977,11 +994,14 @@
 	 * dst entry and replace it instead with the
 	 * dst entry of the nexthop router
 	 */
-	if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) {
+	rcu_read_lock();
+	n = dst_get_neighbour(*dst);
+	if (n && !(n->nud_state & NUD_VALID)) {
 		struct inet6_ifaddr *ifp;
 		struct flowi6 fl_gw6;
 		int redirect;
 
+		rcu_read_unlock();
 		ifp = ipv6_get_ifaddr(net, &fl6->saddr,
 				      (*dst)->dev, 1);
 
@@ -1001,6 +1021,8 @@
 			if ((err = (*dst)->error))
 				goto out_err_release;
 		}
+	} else {
+		rcu_read_unlock();
 	}
 #endif
 
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 36c2842..848e494 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -289,6 +289,8 @@
 	if ((err = register_netdevice(dev)) < 0)
 		goto failed_free;
 
+	strcpy(t->parms.name, dev->name);
+
 	dev_hold(dev);
 	ip6_tnl_link(ip6n, t);
 	return t;
@@ -1397,7 +1399,6 @@
 	struct ip6_tnl *t = netdev_priv(dev);
 
 	t->dev = dev;
-	strcpy(t->parms.name, dev->name);
 	dev->tstats = alloc_percpu(struct pcpu_tstats);
 	if (!dev->tstats)
 		return -ENOMEM;
@@ -1477,6 +1478,7 @@
 static int __net_init ip6_tnl_init_net(struct net *net)
 {
 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+	struct ip6_tnl *t = NULL;
 	int err;
 
 	ip6n->tnls[0] = ip6n->tnls_wc;
@@ -1497,6 +1499,10 @@
 	err = register_netdev(ip6n->fb_tnl_dev);
 	if (err < 0)
 		goto err_register;
+
+	t = netdev_priv(ip6n->fb_tnl_dev);
+
+	strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
 	return 0;
 
 err_register:
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 7596f07..10a8d41 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1244,7 +1244,7 @@
 	rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
 
 	if (rt)
-		neigh = rt->rt6i_nexthop;
+		neigh = dst_get_neighbour(&rt->dst);
 
 	if (rt && lifetime == 0) {
 		neigh_clone(neigh);
@@ -1265,7 +1265,7 @@
 			return;
 		}
 
-		neigh = rt->rt6i_nexthop;
+		neigh = dst_get_neighbour(&rt->dst);
 		if (neigh == NULL) {
 			ND_PRINTK0(KERN_ERR
 				   "ICMPv6 RA: %s() got default router without neighbour.\n",
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 0ef1f08..e70e902 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -356,7 +356,7 @@
 #ifdef CONFIG_IPV6_ROUTER_PREF
 static void rt6_probe(struct rt6_info *rt)
 {
-	struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL;
+	struct neighbour *neigh;
 	/*
 	 * Okay, this does not seem to be appropriate
 	 * for now, however, we need to check if it
@@ -365,8 +365,10 @@
 	 * Router Reachability Probe MUST be rate-limited
 	 * to no more than one per minute.
 	 */
+	rcu_read_lock();
+	neigh = rt ? dst_get_neighbour(&rt->dst) : NULL;
 	if (!neigh || (neigh->nud_state & NUD_VALID))
-		return;
+		goto out;
 	read_lock_bh(&neigh->lock);
 	if (!(neigh->nud_state & NUD_VALID) &&
 	    time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
@@ -379,8 +381,11 @@
 		target = (struct in6_addr *)&neigh->primary_key;
 		addrconf_addr_solict_mult(target, &mcaddr);
 		ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL);
-	} else
+	} else {
 		read_unlock_bh(&neigh->lock);
+	}
+out:
+	rcu_read_unlock();
 }
 #else
 static inline void rt6_probe(struct rt6_info *rt)
@@ -404,8 +409,11 @@
 
 static inline int rt6_check_neigh(struct rt6_info *rt)
 {
-	struct neighbour *neigh = rt->rt6i_nexthop;
+	struct neighbour *neigh;
 	int m;
+
+	rcu_read_lock();
+	neigh = dst_get_neighbour(&rt->dst);
 	if (rt->rt6i_flags & RTF_NONEXTHOP ||
 	    !(rt->rt6i_flags & RTF_GATEWAY))
 		m = 1;
@@ -422,6 +430,7 @@
 		read_unlock_bh(&neigh->lock);
 	} else
 		m = 0;
+	rcu_read_unlock();
 	return m;
 }
 
@@ -745,8 +754,7 @@
 			dst_free(&rt->dst);
 			return NULL;
 		}
-		rt->rt6i_nexthop = neigh;
-
+		dst_set_neighbour(&rt->dst, neigh);
 	}
 
 	return rt;
@@ -760,7 +768,7 @@
 		rt->rt6i_dst.plen = 128;
 		rt->rt6i_flags |= RTF_CACHE;
 		rt->dst.flags |= DST_HOST;
-		rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
+		dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst)));
 	}
 	return rt;
 }
@@ -794,7 +802,7 @@
 	dst_hold(&rt->dst);
 	read_unlock_bh(&table->tb6_lock);
 
-	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+	if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
 		nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
 	else if (!(rt->dst.flags & DST_HOST))
 		nrt = rt6_alloc_clone(rt, &fl6->daddr);
@@ -1058,7 +1066,7 @@
 	}
 
 	rt->rt6i_idev     = idev;
-	rt->rt6i_nexthop  = neigh;
+	dst_set_neighbour(&rt->dst, neigh);
 	atomic_set(&rt->dst.__refcnt, 1);
 	dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
 	rt->dst.output  = ip6_output;
@@ -1338,12 +1346,12 @@
 		rt->rt6i_prefsrc.plen = 0;
 
 	if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
-		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
-		if (IS_ERR(rt->rt6i_nexthop)) {
-			err = PTR_ERR(rt->rt6i_nexthop);
-			rt->rt6i_nexthop = NULL;
+		struct neighbour *neigh = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
+		if (IS_ERR(neigh)) {
+			err = PTR_ERR(neigh);
 			goto out;
 		}
+		dst_set_neighbour(&rt->dst, neigh);
 	}
 
 	rt->rt6i_flags = cfg->fc_flags;
@@ -1574,7 +1582,7 @@
 	dst_confirm(&rt->dst);
 
 	/* Duplicate redirect: silently ignore. */
-	if (neigh == rt->dst.neighbour)
+	if (neigh == dst_get_neighbour_raw(&rt->dst))
 		goto out;
 
 	nrt = ip6_rt_copy(rt);
@@ -1590,7 +1598,7 @@
 	nrt->dst.flags |= DST_HOST;
 
 	ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
-	nrt->rt6i_nexthop = neigh_clone(neigh);
+	dst_set_neighbour(&nrt->dst, neigh_clone(neigh));
 
 	if (ip6_ins_rt(nrt))
 		goto out;
@@ -1670,7 +1678,7 @@
 	   1. It is connected route. Action: COW
 	   2. It is gatewayed route or NONEXTHOP route. Action: clone it.
 	 */
-	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+	if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
 		nrt = rt6_alloc_cow(rt, daddr, saddr);
 	else
 		nrt = rt6_alloc_clone(rt, daddr);
@@ -2035,7 +2043,7 @@
 
 		return ERR_CAST(neigh);
 	}
-	rt->rt6i_nexthop = neigh;
+	dst_set_neighbour(&rt->dst, neigh);
 
 	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
 	rt->rt6i_dst.plen = 128;
@@ -2312,6 +2320,7 @@
 	struct nlmsghdr *nlh;
 	long expires;
 	u32 table;
+	struct neighbour *n;
 
 	if (prefix) {	/* user wants prefix routes only */
 		if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
@@ -2400,8 +2409,11 @@
 	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
 		goto nla_put_failure;
 
-	if (rt->dst.neighbour)
-		NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key);
+	rcu_read_lock();
+	n = dst_get_neighbour(&rt->dst);
+	if (n)
+		NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key);
+	rcu_read_unlock();
 
 	if (rt->dst.dev)
 		NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex);
@@ -2585,6 +2597,7 @@
 static int rt6_info_route(struct rt6_info *rt, void *p_arg)
 {
 	struct seq_file *m = p_arg;
+	struct neighbour *n;
 
 	seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
 
@@ -2593,12 +2606,14 @@
 #else
 	seq_puts(m, "00000000000000000000000000000000 00 ");
 #endif
-
-	if (rt->rt6i_nexthop) {
-		seq_printf(m, "%pi6", rt->rt6i_nexthop->primary_key);
+	rcu_read_lock();
+	n = dst_get_neighbour(&rt->dst);
+	if (n) {
+		seq_printf(m, "%pi6", n->primary_key);
 	} else {
 		seq_puts(m, "00000000000000000000000000000000");
 	}
+	rcu_read_unlock();
 	seq_printf(m, " %08x %08x %08x %08x %8s\n",
 		   rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
 		   rt->dst.__use, rt->rt6i_flags,
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 1cca576..f56acd0 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -263,6 +263,8 @@
 	if (register_netdevice(dev) < 0)
 		goto failed_free;
 
+	strcpy(nt->parms.name, dev->name);
+
 	dev_hold(dev);
 
 	ipip6_tunnel_link(sitn, nt);
@@ -677,7 +679,7 @@
 		struct neighbour *neigh = NULL;
 
 		if (skb_dst(skb))
-			neigh = skb_dst(skb)->neighbour;
+			neigh = dst_get_neighbour(skb_dst(skb));
 
 		if (neigh == NULL) {
 			if (net_ratelimit())
@@ -702,7 +704,7 @@
 		struct neighbour *neigh = NULL;
 
 		if (skb_dst(skb))
-			neigh = skb_dst(skb)->neighbour;
+			neigh = dst_get_neighbour(skb_dst(skb));
 
 		if (neigh == NULL) {
 			if (net_ratelimit())
@@ -1141,7 +1143,6 @@
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 
 	tunnel->dev = dev;
-	strcpy(tunnel->parms.name, dev->name);
 
 	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
@@ -1204,6 +1205,7 @@
 static int __net_init sit_init_net(struct net *net)
 {
 	struct sit_net *sitn = net_generic(net, sit_net_id);
+	struct ip_tunnel *t;
 	int err;
 
 	sitn->tunnels[0] = sitn->tunnels_wc;
@@ -1228,6 +1230,9 @@
 	if ((err = register_netdev(sitn->fb_tunnel_dev)))
 		goto err_reg_dev;
 
+	t = netdev_priv(sitn->fb_tunnel_dev);
+
+	strcpy(t->parms.name, sitn->fb_tunnel_dev->name);
 	return 0;
 
 err_reg_dev:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 7c43e86..51587a0 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -605,7 +605,8 @@
 			}
 			sk_nocaps_add(sk, NETIF_F_GSO_MASK);
 		}
-		if (tcp_alloc_md5sig_pool(sk) == NULL) {
+		if (tp->md5sig_info->entries6 == 0 &&
+			tcp_alloc_md5sig_pool(sk) == NULL) {
 			kfree(newkey);
 			return -ENOMEM;
 		}
@@ -614,8 +615,9 @@
 				       (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
 
 			if (!keys) {
-				tcp_free_md5sig_pool();
 				kfree(newkey);
+				if (tp->md5sig_info->entries6 == 0)
+					tcp_free_md5sig_pool();
 				return -ENOMEM;
 			}
 
@@ -661,6 +663,7 @@
 				kfree(tp->md5sig_info->keys6);
 				tp->md5sig_info->keys6 = NULL;
 				tp->md5sig_info->alloced6 = 0;
+				tcp_free_md5sig_pool();
 			} else {
 				/* shrink the database */
 				if (tp->md5sig_info->entries6 != i)
@@ -669,7 +672,6 @@
 						(tp->md5sig_info->entries6 - i)
 						* sizeof (tp->md5sig_info->keys6[0]));
 			}
-			tcp_free_md5sig_pool();
 			return 0;
 		}
 	}
@@ -1094,7 +1096,7 @@
 
 #ifdef CONFIG_TCP_MD5SIG
 	if (sk)
-		key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
+		key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr);
 #endif
 
 	if (th->ack)
@@ -1407,6 +1409,8 @@
 		newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
 #endif
 
+		newnp->ipv6_ac_list = NULL;
+		newnp->ipv6_fl_list = NULL;
 		newnp->pktoptions  = NULL;
 		newnp->opt	   = NULL;
 		newnp->mcast_oif   = inet6_iif(skb);
@@ -1471,6 +1475,7 @@
 	   First: no IPv4 options.
 	 */
 	newinet->inet_opt = NULL;
+	newnp->ipv6_ac_list = NULL;
 	newnp->ipv6_fl_list = NULL;
 
 	/* Clone RX bits */
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index ed8a233..71c292e 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1045,8 +1045,10 @@
 	headroom = NET_SKB_PAD + sizeof(struct iphdr) +
 		uhlen + hdr_len;
 	old_headroom = skb_headroom(skb);
-	if (skb_cow_head(skb, headroom))
+	if (skb_cow_head(skb, headroom)) {
+		dev_kfree_skb(skb);
 		goto abort;
+	}
 
 	new_headroom = skb_headroom(skb);
 	skb_orphan(skb);
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index b6466e7..858ca23 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -393,11 +393,6 @@
 {
 	int rc;
 
-	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
-		goto drop;
-
-	nf_reset(skb);
-
 	/* Charge it to the socket, dropping if the queue is full. */
 	rc = sock_queue_rcv_skb(sk, skb);
 	if (rc < 0)
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index dfd3a64..a18e6c3 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -833,15 +833,15 @@
 		copied += used;
 		len -= used;
 
+		/* For non stream protcols we get one packet per recvmsg call */
+		if (sk->sk_type != SOCK_STREAM)
+			goto copy_uaddr;
+
 		if (!(flags & MSG_PEEK)) {
 			sk_eat_skb(sk, skb, 0);
 			*seq = 0;
 		}
 
-		/* For non stream protcols we get one packet per recvmsg call */
-		if (sk->sk_type != SOCK_STREAM)
-			goto copy_uaddr;
-
 		/* Partial read */
 		if (used + offset < skb->len)
 			continue;
@@ -857,6 +857,12 @@
 	}
 	if (llc_sk(sk)->cmsg_flags)
 		llc_cmsg_rcv(msg, skb);
+
+	if (!(flags & MSG_PEEK)) {
+			sk_eat_skb(sk, skb, 0);
+			*seq = 0;
+	}
+
 	goto out;
 }
 
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index c8be8ef..b7f4f5c 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -162,6 +162,12 @@
 		return -ENOENT;
 	}
 
+	/* if we're already stopping ignore any new requests to stop */
+	if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+		spin_unlock_bh(&sta->lock);
+		return -EALREADY;
+	}
+
 	if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
 		/* not even started yet! */
 		ieee80211_assign_tid_tx(sta, tid, NULL);
@@ -170,6 +176,8 @@
 		return 0;
 	}
 
+	set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
+
 	spin_unlock_bh(&sta->lock);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -177,8 +185,6 @@
 	       sta->sta.addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-	set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
-
 	del_timer_sync(&tid_tx->addba_resp_timer);
 
 	/*
@@ -188,6 +194,20 @@
 	 */
 	clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
 
+	/*
+	 * There might be a few packets being processed right now (on
+	 * another CPU) that have already gotten past the aggregation
+	 * check when it was still OPERATIONAL and consequently have
+	 * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
+	 * call into the driver at the same time or even before the
+	 * TX paths calls into it, which could confuse the driver.
+	 *
+	 * Wait for all currently running TX paths to finish before
+	 * telling the driver. New packets will not go through since
+	 * the aggregation session is no longer OPERATIONAL.
+	 */
+	synchronize_net();
+
 	tid_tx->stop_initiator = initiator;
 	tid_tx->tx_stop = tx;
 
@@ -284,6 +304,38 @@
 	__release(agg_queue);
 }
 
+/*
+ * splice packets from the STA's pending to the local pending,
+ * requires a call to ieee80211_agg_splice_finish later
+ */
+static void __acquires(agg_queue)
+ieee80211_agg_splice_packets(struct ieee80211_local *local,
+			     struct tid_ampdu_tx *tid_tx, u16 tid)
+{
+	int queue = ieee80211_ac_from_tid(tid);
+	unsigned long flags;
+
+	ieee80211_stop_queue_agg(local, tid);
+
+	if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
+			  " from the pending queue\n", tid))
+		return;
+
+	if (!skb_queue_empty(&tid_tx->pending)) {
+		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+		/* copy over remaining packets */
+		skb_queue_splice_tail_init(&tid_tx->pending,
+					   &local->pending[queue]);
+		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+	}
+}
+
+static void __releases(agg_queue)
+ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
+{
+	ieee80211_wake_queue_agg(local, tid);
+}
+
 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 {
 	struct tid_ampdu_tx *tid_tx;
@@ -295,19 +347,17 @@
 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
 	/*
-	 * While we're asking the driver about the aggregation,
-	 * stop the AC queue so that we don't have to worry
-	 * about frames that came in while we were doing that,
-	 * which would require us to put them to the AC pending
-	 * afterwards which just makes the code more complex.
+	 * Start queuing up packets for this aggregation session.
+	 * We're going to release them once the driver is OK with
+	 * that.
 	 */
-	ieee80211_stop_queue_agg(local, tid);
-
 	clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
 
 	/*
-	 * make sure no packets are being processed to get
-	 * valid starting sequence number
+	 * Make sure no packets are being processed. This ensures that
+	 * we have a valid starting sequence number and that in-flight
+	 * packets have been flushed out and no packets for this TID
+	 * will go into the driver during the ampdu_action call.
 	 */
 	synchronize_net();
 
@@ -321,17 +371,15 @@
 					" tid %d\n", tid);
 #endif
 		spin_lock_bh(&sta->lock);
+		ieee80211_agg_splice_packets(local, tid_tx, tid);
 		ieee80211_assign_tid_tx(sta, tid, NULL);
+		ieee80211_agg_splice_finish(local, tid);
 		spin_unlock_bh(&sta->lock);
 
-		ieee80211_wake_queue_agg(local, tid);
 		kfree_rcu(tid_tx, rcu_head);
 		return;
 	}
 
-	/* we can take packets again now */
-	ieee80211_wake_queue_agg(local, tid);
-
 	/* activate the timer for the recipient's addBA response */
 	mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -451,38 +499,6 @@
 }
 EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
 
-/*
- * splice packets from the STA's pending to the local pending,
- * requires a call to ieee80211_agg_splice_finish later
- */
-static void __acquires(agg_queue)
-ieee80211_agg_splice_packets(struct ieee80211_local *local,
-			     struct tid_ampdu_tx *tid_tx, u16 tid)
-{
-	int queue = ieee80211_ac_from_tid(tid);
-	unsigned long flags;
-
-	ieee80211_stop_queue_agg(local, tid);
-
-	if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
-			  " from the pending queue\n", tid))
-		return;
-
-	if (!skb_queue_empty(&tid_tx->pending)) {
-		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-		/* copy over remaining packets */
-		skb_queue_splice_tail_init(&tid_tx->pending,
-					   &local->pending[queue]);
-		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-	}
-}
-
-static void __releases(agg_queue)
-ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
-{
-	ieee80211_wake_queue_agg(local, tid);
-}
-
 static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
 					 struct sta_info *sta, u16 tid)
 {
@@ -772,12 +788,27 @@
 		goto out;
 	}
 
-	del_timer(&tid_tx->addba_resp_timer);
+	del_timer_sync(&tid_tx->addba_resp_timer);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
 #endif
 
+	/*
+	 * addba_resp_timer may have fired before we got here, and
+	 * caused WANT_STOP to be set. If the stop then was already
+	 * processed further, STOPPING might be set.
+	 */
+	if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
+	    test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG
+		       "got addBA resp for tid %d but we already gave up\n",
+		       tid);
+#endif
+		goto out;
+	}
+
 	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
 			== WLAN_STATUS_SUCCESS) {
 		/*
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index be70c70..143a006 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1798,7 +1798,7 @@
 	 * so in that case userspace will have to deal with it.
 	 */
 
-	if (wk->offchan_tx.wait && wk->offchan_tx.frame)
+	if (wk->offchan_tx.wait && !wk->offchan_tx.status)
 		cfg80211_mgmt_tx_status(wk->sdata->dev,
 					(unsigned long) wk->offchan_tx.frame,
 					wk->ie, wk->ie_len, false, GFP_KERNEL);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 090b0ec..3fdac77 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -328,6 +328,7 @@
 		struct {
 			struct sk_buff *frame;
 			u32 wait;
+			bool status;
 		} offchan_tx;
 	};
 
@@ -372,6 +373,7 @@
 
 	unsigned long timers_running; /* used for quiesce/restart */
 	bool powersave; /* powersave requested for this iface */
+	bool broken_ap; /* AP is broken -- turn off powersave */
 	enum ieee80211_smps_mode req_smps, /* requested smps mode */
 				 ap_smps, /* smps mode AP thinks we're in */
 				 driver_smps_mode; /* smps mode request */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7a334fd..1563250 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -613,6 +613,9 @@
 	if (!mgd->powersave)
 		return false;
 
+	if (mgd->broken_ap)
+		return false;
+
 	if (!mgd->associated)
 		return false;
 
@@ -1450,10 +1453,21 @@
 	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
 
 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-		printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
-		       "set\n", sdata->name, aid);
+		printk(KERN_DEBUG
+		       "%s: invalid AID value 0x%x; bits 15:14 not set\n",
+		       sdata->name, aid);
 	aid &= ~(BIT(15) | BIT(14));
 
+	ifmgd->broken_ap = false;
+
+	if (aid == 0 || aid > IEEE80211_MAX_AID) {
+		printk(KERN_DEBUG
+		       "%s: invalid AID value %d (out of range), turn off PS\n",
+		       sdata->name, aid);
+		aid = 0;
+		ifmgd->broken_ap = true;
+	}
+
 	pos = mgmt->u.assoc_resp.variable;
 	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 7fa8c6b..378bd67 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -140,8 +140,9 @@
 	pos++;
 
 	/* IEEE80211_RADIOTAP_RATE */
-	if (status->flag & RX_FLAG_HT) {
+	if (!rate || status->flag & RX_FLAG_HT) {
 		/*
+		 * Without rate information don't add it. If we have,
 		 * MCS information is a separate field in radiotap,
 		 * added below. The byte here is needed as padding
 		 * for the channel though, so initialise it to 0.
@@ -162,12 +163,14 @@
 	else if (status->flag & RX_FLAG_HT)
 		put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
 				   pos);
-	else if (rate->flags & IEEE80211_RATE_ERP_G)
+	else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
 		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
 				   pos);
-	else
+	else if (rate)
 		put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
 				   pos);
+	else
+		put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos);
 	pos += 2;
 
 	/* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 1658efa..04cdbaf 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -336,7 +336,7 @@
 				continue;
 			if (wk->offchan_tx.frame != skb)
 				continue;
-			wk->offchan_tx.frame = NULL;
+			wk->offchan_tx.status = true;
 			break;
 		}
 		rcu_read_unlock();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d3fe2d2..2124db8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1047,6 +1047,8 @@
 	skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
 				     ssid, ssid_len,
 				     buf, buf_len);
+	if (!skb)
+		goto out;
 
 	if (dst) {
 		mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1055,6 +1057,8 @@
 	}
 
 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+ out:
 	kfree(buf);
 
 	return skb;
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index d2e7f0e..52b758d 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -553,7 +553,7 @@
 		/*
 		 * After this, offchan_tx.frame remains but now is no
 		 * longer a valid pointer -- we still need it as the
-		 * cookie for canceling this work.
+		 * cookie for canceling this work/status matching.
 		 */
 		ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
 
@@ -1060,14 +1060,13 @@
 			continue;
 		if (wk->chan != local->tmp_channel)
 			continue;
-		if (ieee80211_work_ct_coexists(wk->chan_type,
-					       local->tmp_channel_type))
+		if (!ieee80211_work_ct_coexists(wk->chan_type,
+						local->tmp_channel_type))
 			continue;
 		remain_off_channel = true;
 	}
 
 	if (!remain_off_channel && local->tmp_channel) {
-		bool on_oper_chan = ieee80211_cfg_on_oper_channel(local);
 		local->tmp_channel = NULL;
 		/* If tmp_channel wasn't operating channel, then
 		 * we need to go back on-channel.
@@ -1077,7 +1076,7 @@
 		 * we still need to do a hardware config.  Currently,
 		 * we cannot be here while scanning, however.
 		 */
-		if (ieee80211_cfg_on_oper_channel(local) && !on_oper_chan)
+		if (!ieee80211_cfg_on_oper_channel(local))
 			ieee80211_hw_config(local, 0);
 
 		/* At the least, we need to disable offchannel_ps,
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 8f6a302..aa1c40a 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -109,7 +109,7 @@
 		if (status->flag & RX_FLAG_MMIC_ERROR)
 			goto mic_fail;
 
-		if (!(status->flag & RX_FLAG_IV_STRIPPED))
+		if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key)
 			goto update_iv;
 
 		return RX_CONTINUE;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index c0c3cda..fafb968 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -654,7 +654,10 @@
 	return 0;
 
 drop_n_acct:
-	po->stats.tp_drops = atomic_inc_return(&sk->sk_drops);
+	spin_lock(&sk->sk_receive_queue.lock);
+	po->stats.tp_drops++;
+	atomic_inc(&sk->sk_drops);
+	spin_unlock(&sk->sk_receive_queue.lock);
 
 drop_n_restore:
 	if (skb_head != skb->data && skb_shared(skb)) {
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
index bb6ad81..424ff62 100644
--- a/net/rds/af_rds.c
+++ b/net/rds/af_rds.c
@@ -68,7 +68,6 @@
 {
 	struct sock *sk = sock->sk;
 	struct rds_sock *rs;
-	unsigned long flags;
 
 	if (!sk)
 		goto out;
@@ -94,10 +93,10 @@
 	rds_rdma_drop_keys(rs);
 	rds_notify_queue_get(rs, NULL);
 
-	spin_lock_irqsave(&rds_sock_lock, flags);
+	spin_lock_bh(&rds_sock_lock);
 	list_del_init(&rs->rs_item);
 	rds_sock_count--;
-	spin_unlock_irqrestore(&rds_sock_lock, flags);
+	spin_unlock_bh(&rds_sock_lock);
 
 	rds_trans_put(rs->rs_transport);
 
@@ -409,7 +408,6 @@
 
 static int __rds_create(struct socket *sock, struct sock *sk, int protocol)
 {
-	unsigned long flags;
 	struct rds_sock *rs;
 
 	sock_init_data(sock, sk);
@@ -426,10 +424,10 @@
 	spin_lock_init(&rs->rs_rdma_lock);
 	rs->rs_rdma_keys = RB_ROOT;
 
-	spin_lock_irqsave(&rds_sock_lock, flags);
+	spin_lock_bh(&rds_sock_lock);
 	list_add_tail(&rs->rs_item, &rds_sock_list);
 	rds_sock_count++;
-	spin_unlock_irqrestore(&rds_sock_lock, flags);
+	spin_unlock_bh(&rds_sock_lock);
 
 	return 0;
 }
@@ -471,12 +469,11 @@
 {
 	struct rds_sock *rs;
 	struct rds_incoming *inc;
-	unsigned long flags;
 	unsigned int total = 0;
 
 	len /= sizeof(struct rds_info_message);
 
-	spin_lock_irqsave(&rds_sock_lock, flags);
+	spin_lock_bh(&rds_sock_lock);
 
 	list_for_each_entry(rs, &rds_sock_list, rs_item) {
 		read_lock(&rs->rs_recv_lock);
@@ -492,7 +489,7 @@
 		read_unlock(&rs->rs_recv_lock);
 	}
 
-	spin_unlock_irqrestore(&rds_sock_lock, flags);
+	spin_unlock_bh(&rds_sock_lock);
 
 	lens->nr = total;
 	lens->each = sizeof(struct rds_info_message);
@@ -504,11 +501,10 @@
 {
 	struct rds_info_socket sinfo;
 	struct rds_sock *rs;
-	unsigned long flags;
 
 	len /= sizeof(struct rds_info_socket);
 
-	spin_lock_irqsave(&rds_sock_lock, flags);
+	spin_lock_bh(&rds_sock_lock);
 
 	if (len < rds_sock_count)
 		goto out;
@@ -529,7 +525,7 @@
 	lens->nr = rds_sock_count;
 	lens->each = sizeof(struct rds_info_socket);
 
-	spin_unlock_irqrestore(&rds_sock_lock, flags);
+	spin_unlock_bh(&rds_sock_lock);
 }
 
 static void rds_exit(void)
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index b9493a0..6cd8ddf 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -385,7 +385,7 @@
 	struct gred_sched_data *q;
 
 	if (table->tab[dp] == NULL) {
-		table->tab[dp] = kzalloc(sizeof(*q), GFP_KERNEL);
+		table->tab[dp] = kzalloc(sizeof(*q), GFP_ATOMIC);
 		if (table->tab[dp] == NULL)
 			return -ENOMEM;
 	}
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index ea17cbe..59b26b8 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -106,7 +106,7 @@
 	if (!netif_is_multiqueue(dev))
 		return -EOPNOTSUPP;
 
-	if (nla_len(opt) < sizeof(*qopt))
+	if (!opt || nla_len(opt) < sizeof(*qopt))
 		return -EINVAL;
 
 	qopt = nla_data(opt);
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 45cd300..4f4c52c 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -225,11 +225,11 @@
 
 
 static int
-__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
+__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
+	       struct net_device *dev, struct netdev_queue *txq,
+	       struct neighbour *mn)
 {
-	struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0);
-	struct teql_sched_data *q = qdisc_priv(dev_queue->qdisc);
-	struct neighbour *mn = skb_dst(skb)->neighbour;
+	struct teql_sched_data *q = qdisc_priv(txq->qdisc);
 	struct neighbour *n = q->ncache;
 
 	if (mn->tbl == NULL)
@@ -262,17 +262,26 @@
 }
 
 static inline int teql_resolve(struct sk_buff *skb,
-			       struct sk_buff *skb_res, struct net_device *dev)
+			       struct sk_buff *skb_res,
+			       struct net_device *dev,
+			       struct netdev_queue *txq)
 {
-	struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+	struct dst_entry *dst = skb_dst(skb);
+	struct neighbour *mn;
+	int res;
+
 	if (txq->qdisc == &noop_qdisc)
 		return -ENODEV;
 
-	if (dev->header_ops == NULL ||
-	    skb_dst(skb) == NULL ||
-	    skb_dst(skb)->neighbour == NULL)
+	if (!dev->header_ops || !dst)
 		return 0;
-	return __teql_resolve(skb, skb_res, dev);
+
+	rcu_read_lock();
+	mn = dst_get_neighbour(dst);
+	res = mn ? __teql_resolve(skb, skb_res, dev, txq, mn) : 0;
+	rcu_read_unlock();
+
+	return res;
 }
 
 static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -307,7 +316,7 @@
 			continue;
 		}
 
-		switch (teql_resolve(skb, skb_res, slave)) {
+		switch (teql_resolve(skb, skb_res, slave, slave_txq)) {
 		case 0:
 			if (__netif_tx_trylock(slave_txq)) {
 				unsigned int length = qdisc_pkt_len(skb);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 4a62888..17a6e65 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -173,7 +173,7 @@
 	asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
 	asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay;
 	asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
-		(unsigned long)sp->autoclose * HZ;
+		min_t(unsigned long, sp->autoclose, sctp_max_autoclose) * HZ;
 
 	/* Initializes the timers */
 	for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i)
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 08b3cea..817174e 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -697,13 +697,7 @@
 	/* Keep track of how many bytes are in flight to the receiver. */
 	asoc->outqueue.outstanding_bytes += datasize;
 
-	/* Update our view of the receiver's rwnd. Include sk_buff overhead
-	 * while updating peer.rwnd so that it reduces the chances of a
-	 * receiver running out of receive buffer space even when receive
-	 * window is still open. This can happen when a sender is sending
-	 * sending small messages.
-	 */
-	datasize += sizeof(struct sk_buff);
+	/* Update our view of the receiver's rwnd. */
 	if (datasize < rwnd)
 		rwnd -= datasize;
 	else
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index d036821..1f2938f 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -411,8 +411,7 @@
 					chunk->transport->flight_size -=
 							sctp_data_size(chunk);
 				q->outstanding_bytes -= sctp_data_size(chunk);
-				q->asoc->peer.rwnd += (sctp_data_size(chunk) +
-							sizeof(struct sk_buff));
+				q->asoc->peer.rwnd += sctp_data_size(chunk);
 			}
 			continue;
 		}
@@ -432,8 +431,7 @@
 			 * (Section 7.2.4)), add the data size of those
 			 * chunks to the rwnd.
 			 */
-			q->asoc->peer.rwnd += (sctp_data_size(chunk) +
-						sizeof(struct sk_buff));
+			q->asoc->peer.rwnd += sctp_data_size(chunk);
 			q->outstanding_bytes -= sctp_data_size(chunk);
 			if (chunk->transport)
 				transport->flight_size -= sctp_data_size(chunk);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 207175b..946afd6 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1144,6 +1144,9 @@
 	sctp_max_instreams    		= SCTP_DEFAULT_INSTREAMS;
 	sctp_max_outstreams   		= SCTP_DEFAULT_OUTSTREAMS;
 
+	/* Initialize maximum autoclose timeout. */
+	sctp_max_autoclose		= INT_MAX / HZ;
+
 	/* Initialize handle used for association ids. */
 	idr_init(&sctp_assocs_id);
 
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index d3ccf79..fa9b5c7 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2129,8 +2129,6 @@
 		return -EINVAL;
 	if (copy_from_user(&sp->autoclose, optval, optlen))
 		return -EFAULT;
-	/* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */
-	sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ);
 
 	return 0;
 }
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 50cb57f..6752f48 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -53,6 +53,10 @@
 static int sack_timer_max = 500;
 static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */
 static int rwnd_scale_max = 16;
+static unsigned long max_autoclose_min = 0;
+static unsigned long max_autoclose_max =
+	(MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX)
+	? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ;
 
 extern long sysctl_sctp_mem[3];
 extern int sysctl_sctp_rmem[3];
@@ -251,6 +255,15 @@
 		.extra1		= &one,
 		.extra2		= &rwnd_scale_max,
 	},
+	{
+		.procname	= "max_autoclose",
+		.data		= &sctp_max_autoclose,
+		.maxlen		= sizeof(unsigned long),
+		.mode		= 0644,
+		.proc_handler	= &proc_doulongvec_minmax,
+		.extra1		= &max_autoclose_min,
+		.extra2		= &max_autoclose_max,
+	},
 
 	{ /* sentinel */ }
 };
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 4cb70dc..e50502d 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -129,6 +129,9 @@
 	for (i = 0; i < groups ; i++)
 		if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
 			return 0;
+	if (groups < NFS_NGROUPS &&
+	    cred->uc_gids[groups] != NOGROUP)
+		return 0;
 	return 1;
 }
 
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 2b90292..ce5f111 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -167,6 +167,7 @@
 
 fail_free:
 	kfree(m->to_pool);
+	m->to_pool = NULL;
 fail:
 	return -ENOMEM;
 }
@@ -287,7 +288,9 @@
 	if (!--m->count) {
 		m->mode = SVC_POOL_DEFAULT;
 		kfree(m->to_pool);
+		m->to_pool = NULL;
 		kfree(m->pool_to);
+		m->pool_to = NULL;
 		m->npools = 0;
 	}
 
@@ -472,17 +475,20 @@
 		printk("svc_destroy: no threads for serv=%p!\n", serv);
 
 	del_timer_sync(&serv->sv_temptimer);
-
-	svc_close_all(&serv->sv_tempsocks);
+	/*
+	 * The set of xprts (contained in the sv_tempsocks and
+	 * sv_permsocks lists) is now constant, since it is modified
+	 * only by accepting new sockets (done by service threads in
+	 * svc_recv) or aging old ones (done by sv_temptimer), or
+	 * configuration changes (excluded by whatever locking the
+	 * caller is using--nfsd_mutex in the case of nfsd).  So it's
+	 * safe to traverse those lists and shut everything down:
+	 */
+	svc_close_all(serv);
 
 	if (serv->sv_shutdown)
 		serv->sv_shutdown(serv);
 
-	svc_close_all(&serv->sv_permsocks);
-
-	BUG_ON(!list_empty(&serv->sv_permsocks));
-	BUG_ON(!list_empty(&serv->sv_tempsocks));
-
 	cache_clean_deferred(serv);
 
 	if (svc_serv_is_pooled(serv))
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index bd31208..9d7ed0b 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -901,14 +901,7 @@
 	spin_lock_bh(&serv->sv_lock);
 	if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
 		list_del_init(&xprt->xpt_list);
-	/*
-	 * The only time we're called while xpt_ready is still on a list
-	 * is while the list itself is about to be destroyed (in
-	 * svc_destroy).  BUT svc_xprt_enqueue could still be attempting
-	 * to add new entries to the sp_sockets list, so we can't leave
-	 * a freed xprt on it.
-	 */
-	list_del_init(&xprt->xpt_ready);
+	BUG_ON(!list_empty(&xprt->xpt_ready));
 	if (test_bit(XPT_TEMP, &xprt->xpt_flags))
 		serv->sv_tmpcnt--;
 	spin_unlock_bh(&serv->sv_lock);
@@ -936,24 +929,50 @@
 }
 EXPORT_SYMBOL_GPL(svc_close_xprt);
 
-void svc_close_all(struct list_head *xprt_list)
+static void svc_close_list(struct list_head *xprt_list)
 {
 	struct svc_xprt *xprt;
-	struct svc_xprt *tmp;
 
-	/*
-	 * The server is shutting down, and no more threads are running.
-	 * svc_xprt_enqueue() might still be running, but at worst it
-	 * will re-add the xprt to sp_sockets, which will soon get
-	 * freed.  So we don't bother with any more locking, and don't
-	 * leave the close to the (nonexistent) server threads:
-	 */
-	list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
+	list_for_each_entry(xprt, xprt_list, xpt_list) {
 		set_bit(XPT_CLOSE, &xprt->xpt_flags);
-		svc_delete_xprt(xprt);
+		set_bit(XPT_BUSY, &xprt->xpt_flags);
 	}
 }
 
+void svc_close_all(struct svc_serv *serv)
+{
+	struct svc_pool *pool;
+	struct svc_xprt *xprt;
+	struct svc_xprt *tmp;
+	int i;
+
+	svc_close_list(&serv->sv_tempsocks);
+	svc_close_list(&serv->sv_permsocks);
+
+	for (i = 0; i < serv->sv_nrpools; i++) {
+		pool = &serv->sv_pools[i];
+
+		spin_lock_bh(&pool->sp_lock);
+		while (!list_empty(&pool->sp_sockets)) {
+			xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready);
+			list_del_init(&xprt->xpt_ready);
+		}
+		spin_unlock_bh(&pool->sp_lock);
+	}
+	/*
+	 * At this point the sp_sockets lists will stay empty, since
+	 * svc_enqueue will not add new entries without taking the
+	 * sp_lock and checking XPT_BUSY.
+	 */
+	list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list)
+		svc_delete_xprt(xprt);
+	list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list)
+		svc_delete_xprt(xprt);
+
+	BUG_ON(!list_empty(&serv->sv_permsocks));
+	BUG_ON(!list_empty(&serv->sv_tempsocks));
+}
+
 /*
  * Handle defer and revisit of requests
  */
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 72abb73..ea75079 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -485,7 +485,7 @@
 	struct rpc_rqst *req = task->tk_rqstp;
 	struct rpc_xprt *xprt = req->rq_xprt;
 	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
-	int ret = 0;
+	int ret = -EAGAIN;
 
 	dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
 			task->tk_pid, req->rq_slen - req->rq_bytes_sent,
@@ -497,7 +497,6 @@
 	/* Don't race with disconnect */
 	if (xprt_connected(xprt)) {
 		if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
-			ret = -EAGAIN;
 			/*
 			 * Notify TCP that we're limited by the application
 			 * window size
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 17a80bf..78f12b3 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -447,6 +447,9 @@
 		      enum nl80211_channel_type channel_type);
 
 u16 cfg80211_calculate_bitrate(struct rate_info *rate);
+int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
+			   const u8 *rates, unsigned int n_rates,
+			   u32 *mask);
 
 int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 				 u32 beacon_int);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1a84262..bf6915b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -89,8 +89,8 @@
 	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
 
-	[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
-	[NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
+	[NL80211_ATTR_MAC] = { .len = ETH_ALEN },
+	[NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },
 
 	[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
 	[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
@@ -132,8 +132,7 @@
 	[NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
 	[NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
 
-	[NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
-					 .len = NL80211_HT_CAPABILITY_LEN },
+	[NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
 
 	[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
 	[NL80211_ATTR_IE] = { .type = NLA_BINARY,
@@ -183,10 +182,12 @@
 	[NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
 	[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
 	[NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
+	[NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
 	[NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
 					 .len = IEEE80211_MAX_DATA_LEN },
 	[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
 					 .len = IEEE80211_MAX_DATA_LEN },
+	[NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -3378,7 +3379,6 @@
 	struct nlattr *attr;
 	struct wiphy *wiphy;
 	int err, tmp, n_ssids = 0, n_channels, i;
-	enum ieee80211_band band;
 	size_t ie_len;
 
 	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
@@ -3398,6 +3398,7 @@
 		if (!n_channels)
 			return -EINVAL;
 	} else {
+		enum ieee80211_band band;
 		n_channels = 0;
 
 		for (band = 0; band < IEEE80211_NUM_BANDS; band++)
@@ -3458,6 +3459,8 @@
 			i++;
 		}
 	} else {
+		enum ieee80211_band band;
+
 		/* all channels */
 		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 			int j;
@@ -3503,9 +3506,32 @@
 		       nla_data(info->attrs[NL80211_ATTR_IE]),
 		       request->ie_len);
 	}
+	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+		if (wiphy->bands[i])
+			request->rates[i] =
+				(1 << wiphy->bands[i]->n_bitrates) - 1;
+	if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
+		nla_for_each_nested(attr,
+				    info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
+				    tmp) {
+			enum ieee80211_band band = nla_type(attr);
+			if (band < 0 || band >= IEEE80211_NUM_BANDS) {
+				err = -EINVAL;
+				goto out_free;
+			}
+			err = ieee80211_get_ratemask(wiphy->bands[band],
+						     nla_data(attr),
+						     nla_len(attr),
+						     &request->rates[band]);
+			if (err)
+				goto out_free;
+		}
+	}
 
 	request->dev = dev;
 	request->wiphy = &rdev->wiphy;
+	request->no_cck =
+		nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
 	rdev->scan_req = request;
 	err = rdev->ops->scan(&rdev->wiphy, dev, request);
@@ -4360,25 +4386,11 @@
 			nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
 		struct ieee80211_supported_band *sband =
 			wiphy->bands[ibss.channel->band];
-		int i, j;
-
-		if (n_rates == 0)
-			return -EINVAL;
-
-		for (i = 0; i < n_rates; i++) {
-			int rate = (rates[i] & 0x7f) * 5;
-			bool found = false;
-
-			for (j = 0; j < sband->n_bitrates; j++) {
-				if (sband->bitrates[j].bitrate == rate) {
-					found = true;
-					ibss.basic_rates |= BIT(j);
-					break;
-				}
-			}
-			if (!found)
-				return -EINVAL;
-		}
+		int err;
+		err = ieee80211_get_ratemask(sband, rates, n_rates,
+					     &ibss.basic_rates);
+		if (err)
+			return err;
 	}
 
 	if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 379574c..72f7fee 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -57,8 +57,17 @@
 #define REG_DBG_PRINT(args...)
 #endif
 
+static struct regulatory_request core_request_world = {
+	.initiator = NL80211_REGDOM_SET_BY_CORE,
+	.alpha2[0] = '0',
+	.alpha2[1] = '0',
+	.intersect = false,
+	.processed = true,
+	.country_ie_env = ENVIRON_ANY,
+};
+
 /* Receipt of information from last regulatory request */
-static struct regulatory_request *last_request;
+static struct regulatory_request *last_request = &core_request_world;
 
 /* To trigger userspace events */
 static struct platform_device *reg_pdev;
@@ -150,7 +159,7 @@
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-static void reset_regdomains(void)
+static void reset_regdomains(bool full_reset)
 {
 	/* avoid freeing static information or freeing something twice */
 	if (cfg80211_regdomain == cfg80211_world_regdom)
@@ -165,6 +174,13 @@
 
 	cfg80211_world_regdom = &world_regdom;
 	cfg80211_regdomain = NULL;
+
+	if (!full_reset)
+		return;
+
+	if (last_request != &core_request_world)
+		kfree(last_request);
+	last_request = &core_request_world;
 }
 
 /*
@@ -175,7 +191,7 @@
 {
 	BUG_ON(!last_request);
 
-	reset_regdomains();
+	reset_regdomains(false);
 
 	cfg80211_world_regdom = rd;
 	cfg80211_regdomain = rd;
@@ -1396,7 +1412,8 @@
 	}
 
 new_request:
-	kfree(last_request);
+	if (last_request != &core_request_world)
+		kfree(last_request);
 
 	last_request = pending_request;
 	last_request->intersect = intersect;
@@ -1566,9 +1583,6 @@
 {
 	struct regulatory_request *request;
 
-	kfree(last_request);
-	last_request = NULL;
-
 	request = kzalloc(sizeof(struct regulatory_request),
 			  GFP_KERNEL);
 	if (!request)
@@ -1759,6 +1773,7 @@
 static void restore_regulatory_settings(bool reset_user)
 {
 	char alpha2[2];
+	char world_alpha2[2];
 	struct reg_beacon *reg_beacon, *btmp;
 	struct regulatory_request *reg_request, *tmp;
 	LIST_HEAD(tmp_reg_req_list);
@@ -1766,7 +1781,7 @@
 	mutex_lock(&cfg80211_mutex);
 	mutex_lock(&reg_mutex);
 
-	reset_regdomains();
+	reset_regdomains(true);
 	restore_alpha2(alpha2, reset_user);
 
 	/*
@@ -1809,11 +1824,13 @@
 
 	/* First restore to the basic regulatory settings */
 	cfg80211_regdomain = cfg80211_world_regdom;
+	world_alpha2[0] = cfg80211_regdomain->alpha2[0];
+	world_alpha2[1] = cfg80211_regdomain->alpha2[1];
 
 	mutex_unlock(&reg_mutex);
 	mutex_unlock(&cfg80211_mutex);
 
-	regulatory_hint_core(cfg80211_regdomain->alpha2);
+	regulatory_hint_core(world_alpha2);
 
 	/*
 	 * This restores the ieee80211_regdom module parameter
@@ -2026,12 +2043,18 @@
 	}
 
 	request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+	if (!request_wiphy &&
+	    (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+	     last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+		schedule_delayed_work(&reg_timeout, 0);
+		return -ENODEV;
+	}
 
 	if (!last_request->intersect) {
 		int r;
 
 		if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
-			reset_regdomains();
+			reset_regdomains(false);
 			cfg80211_regdomain = rd;
 			return 0;
 		}
@@ -2052,7 +2075,7 @@
 		if (r)
 			return r;
 
-		reset_regdomains();
+		reset_regdomains(false);
 		cfg80211_regdomain = rd;
 		return 0;
 	}
@@ -2077,7 +2100,7 @@
 
 		rd = NULL;
 
-		reset_regdomains();
+		reset_regdomains(false);
 		cfg80211_regdomain = intersected_rd;
 
 		return 0;
@@ -2097,7 +2120,7 @@
 	kfree(rd);
 	rd = NULL;
 
-	reset_regdomains();
+	reset_regdomains(false);
 	cfg80211_regdomain = intersected_rd;
 
 	return 0;
@@ -2250,9 +2273,9 @@
 	mutex_lock(&cfg80211_mutex);
 	mutex_lock(&reg_mutex);
 
-	reset_regdomains();
+	reset_regdomains(true);
 
-	kfree(last_request);
+	dev_set_uevent_suppress(&reg_pdev->dev, true);
 
 	platform_device_unregister(reg_pdev);
 
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index cbbc927..0aa09bd 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -862,6 +862,8 @@
 		if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
 			creq->n_ssids = 0;
 	}
+	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+		creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
 
 	rdev->scan_req = creq;
 	err = rdev->ops->scan(wiphy, dev, creq);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index c69e653..c87358b 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1014,3 +1014,32 @@
 
 	return -EBUSY;
 }
+
+int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
+			   const u8 *rates, unsigned int n_rates,
+			   u32 *mask)
+{
+	int i, j;
+	if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES)
+		return -EINVAL;
+	*mask = 0;
+	for (i = 0; i < n_rates; i++) {
+		int rate = (rates[i] & 0x7f) * 5;
+		bool found = false;
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].bitrate == rate) {
+				found = true;
+				*mask |= BIT(j);
+				break;
+			}
+		}
+		if (!found)
+			return -EINVAL;
+	}
+	/*
+	 * mask must have at least one bit set here since we
+	 * didn't accept a 0-length rates array nor allowed
+	 * entries in the array that didn't exist
+	 */
+	return 0;
+}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 5ce74a3..7803eb6 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1497,7 +1497,7 @@
 		goto free_dst;
 
 	/* Copy neighbour for reachability confirmation */
-	dst0->neighbour = neigh_clone(dst->neighbour);
+	dst_set_neighbour(dst0, neigh_clone(dst_get_neighbour(dst)));
 
 	xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len);
 	xfrm_init_pmtu(dst_prev);
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0d41625..46a49e7 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 " .
@@ -2800,8 +2848,11 @@
 # unbounded string functions are overflow risks
 		my %str_fns = (
 			"sprintf" => "snprintf",
-			"strcpy"  => "strncpy",
-			"strcat"  => "strncat",
+			"strcpy"  => "strlcpy",
+			"strncpy"  => "strlcpy",
+			"strcat"  => "strlcat",
+			"strncat"  => "strlcat",
+			"vsprintf"  => "vsnprintf",
 			"strcmp"  => "strncmp",
 			"strcasecmp" => "strncasecmp",
 			"strchr" => "strnchr",
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 0104f1a..d3d393d 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -44,6 +44,8 @@
     "alignment.c:720",
     "async.c:122",
     "async.c:270",
+    "block.c:835",
+    "block.c:836",
     "dir.c:43",
     "dm.c:1053",
     "dm.c:1080",
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 5fdf10d..b1a3cee 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -596,11 +596,10 @@
 	struct symbol *sym = menu->sym;
 
 	if (menu_has_help(menu)) {
-		if (sym->name) {
+		if (sym->name)
 			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
-			str_append(help, _(menu_get_help(menu)));
-			str_append(help, "\n");
-		}
+		str_append(help, _(menu_get_help(menu)));
+		str_append(help, "\n");
 	} else {
 		str_append(help, nohelp_text);
 	}
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index a4fe923..25f1e71 100644
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -242,33 +242,61 @@
     read_kconfig($kconfig);
 }
 
+sub convert_vars {
+    my ($line, %vars) = @_;
+
+    my $process = "";
+
+    while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
+	my $start = $1;
+	my $variable = $2;
+	my $var = $3;
+
+	if (defined($vars{$var})) {
+	    $process .= $start . $vars{$var};
+	} else {
+	    $process .= $start . $variable;
+	}
+    }
+
+    $process .= $line;
+
+    return $process;
+}
+
 # Read all Makefiles to map the configs to the objects
 foreach my $makefile (@makefiles) {
 
-    my $cont = 0;
+    my $line = "";
+    my %make_vars;
 
     open(MIN,$makefile) || die "Can't open $makefile";
     while (<MIN>) {
+	# if this line ends with a backslash, continue
+	chomp;
+	if (/^(.*)\\$/) {
+	    $line .= $1;
+	    next;
+	}
+
+	$line .= $_;
+	$_ = $line;
+	$line = "";
+
 	my $objs;
 
-	# is this a line after a line with a backslash?
-	if ($cont && /(\S.*)$/) {
-	    $objs = $1;
-	}
-	$cont = 0;
+	$_ = convert_vars($_, %make_vars);
 
 	# collect objects after obj-$(CONFIG_FOO_BAR)
 	if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
 	    $var = $1;
 	    $objs = $2;
+
+	# check if variables are set
+	} elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
+	    $make_vars{$1} = $2;
 	}
 	if (defined($objs)) {
-	    # test if the line ends with a backslash
-	    if ($objs =~ m,(.*)\\$,) {
-		$objs = $1;
-		$cont = 1;
-	    }
-
 	    foreach my $obj (split /\s+/,$objs) {
 		$obj =~ s/-/_/g;
 		if ($obj =~ /(.*)\.o$/) {
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index f40a6af6..54e35c1 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -462,7 +462,7 @@
 		succeed_file();
 	}
 	if (w(txthdr->sh_type) != SHT_PROGBITS ||
-	    !(w(txthdr->sh_flags) & SHF_EXECINSTR))
+	    !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
 		return NULL;
 	return txtname;
 }
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 4d40384..3b6d5b7 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -47,7 +47,20 @@
 
 		# If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
 		# it, because this version is defined in the top level Makefile.
-		if [ -z "`git describe --exact-match 2>/dev/null`" ]; then
+		if atag="`git describe --exact-match --abbrev=0 2>/dev/null`"; then
+			# Make sure we're at the tag that matches the Makefile.
+			# If not place the hash of the tag as well for
+			# v2.6.30-rc5-g314aef
+			if [ "x$atag" != "x$VERSION" ]; then
+				# If only the short version is requested,
+				# don't bother running further git commands
+				if $short; then
+					echo "+"
+					return
+				fi
+				printf '%s%s' -g "`git show-ref -s --abbrev --tags $atag 2>/dev/null`"
+			fi
+		else
 
 			# If only the short version is requested, don't bother
 			# running further git commands
@@ -56,10 +69,12 @@
 				return
 			fi
 			# If we are past a tagged commit (like
-			# "v2.6.30-rc5-302-g72357d5"), we pretty print it.
+			# "v2.6.30-rc5-302-g72357d5"), we pretty print it and
+			# include the hash of any new tag on top.
 			if atag="`git describe 2>/dev/null`"; then
-				echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
-
+				tag="`git describe --abbrev=0 2>/dev/null`"
+				commit="`echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'`"
+				printf '%s%s%s' -g "`git show-ref -s --abbrev --tags $tag 2>/dev/null`" $commit
 			# If we don't have a tag at all we print -g{commitish}.
 			else
 				printf '%s%s' -g $head
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index 36cc0cc..b566eba 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -57,23 +57,44 @@
 static int d_namespace_path(struct path *path, char *buf, int buflen,
 			    char **name, int flags)
 {
-	struct path root, tmp;
 	char *res;
-	int connected, error = 0;
+	int error = 0;
+	int connected = 1;
 
-	/* Get the root we want to resolve too, released below */
-	if (flags & PATH_CHROOT_REL) {
-		/* resolve paths relative to chroot */
-		get_fs_root(current->fs, &root);
-	} else {
-		/* resolve paths relative to namespace */
-		root.mnt = current->nsproxy->mnt_ns->root;
-		root.dentry = root.mnt->mnt_root;
-		path_get(&root);
+	if (path->mnt->mnt_flags & MNT_INTERNAL) {
+		/* it's not mounted anywhere */
+		res = dentry_path(path->dentry, buf, buflen);
+		*name = res;
+		if (IS_ERR(res)) {
+			*name = buf;
+			return PTR_ERR(res);
+		}
+		if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
+		    strncmp(*name, "/sys/", 5) == 0) {
+			/* TODO: convert over to using a per namespace
+			 * control instead of hard coded /proc
+			 */
+			return prepend(name, *name - buf, "/proc", 5);
+		}
+		return 0;
 	}
 
-	tmp = root;
-	res = __d_path(path, &tmp, buf, buflen);
+	/* resolve paths relative to chroot?*/
+	if (flags & PATH_CHROOT_REL) {
+		struct path root;
+		get_fs_root(current->fs, &root);
+		res = __d_path(path, &root, buf, buflen);
+		if (res && !IS_ERR(res)) {
+			/* everything's fine */
+			*name = res;
+			path_put(&root);
+			goto ok;
+		}
+		path_put(&root);
+		connected = 0;
+	}
+
+	res = d_absolute_path(path, buf, buflen);
 
 	*name = res;
 	/* handle error conditions - and still allow a partial path to
@@ -84,7 +105,10 @@
 		*name = buf;
 		goto out;
 	}
+	if (!our_mnt(path->mnt))
+		connected = 0;
 
+ok:
 	/* Handle two cases:
 	 * 1. A deleted dentry && profile is not allowing mediation of deleted
 	 * 2. On some filesystems, newly allocated dentries appear to the
@@ -97,10 +121,7 @@
 			goto out;
 	}
 
-	/* Determine if the path is connected to the expected root */
-	connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;
-
-	/* If the path is not connected,
+	/* If the path is not connected to the expected root,
 	 * check if it is a sysctl and handle specially else remove any
 	 * leading / that __d_path may have returned.
 	 * Unless
@@ -112,17 +133,9 @@
 	 *     namespace root.
 	 */
 	if (!connected) {
-		/* is the disconnect path a sysctl? */
-		if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
-		    strncmp(*name, "/sys/", 5) == 0) {
-			/* TODO: convert over to using a per namespace
-			 * control instead of hard coded /proc
-			 */
-			error = prepend(name, *name - buf, "/proc", 5);
-		} else if (!(flags & PATH_CONNECT_PATH) &&
+		if (!(flags & PATH_CONNECT_PATH) &&
 			   !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
-			     (tmp.mnt == current->nsproxy->mnt_ns->root &&
-			      tmp.dentry == tmp.mnt->mnt_root))) {
+			     our_mnt(path->mnt))) {
 			/* disconnected path, don't return pathname starting
 			 * with '/'
 			 */
@@ -133,8 +146,6 @@
 	}
 
 out:
-	path_put(&root);
-
 	return error;
 }
 
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index da36d2c..5335605 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -177,8 +177,8 @@
 	strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
 
 	result = ima_store_template(entry, violation, inode);
-	if (!result)
+	if (!result || result == -EEXIST)
 		iint->flags |= IMA_MEASURED;
-	else
+	if (result < 0)
 		kfree(entry);
 }
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 8e28f04..55a6271 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -23,6 +23,8 @@
 #include <linux/slab.h>
 #include "ima.h"
 
+#define AUDIT_CAUSE_LEN_MAX 32
+
 LIST_HEAD(ima_measurements);	/* list of all measurements */
 
 /* key: inode (before secure-hashing a file) */
@@ -94,7 +96,8 @@
 
 	result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
 	if (result != 0)
-		pr_err("IMA: Error Communicating to TPM chip\n");
+		pr_err("IMA: Error Communicating to TPM chip, result: %d\n",
+		       result);
 	return result;
 }
 
@@ -106,14 +109,16 @@
 {
 	u8 digest[IMA_DIGEST_SIZE];
 	const char *audit_cause = "hash_added";
+	char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
 	int audit_info = 1;
-	int result = 0;
+	int result = 0, tpmresult = 0;
 
 	mutex_lock(&ima_extend_list_mutex);
 	if (!violation) {
 		memcpy(digest, entry->digest, sizeof digest);
 		if (ima_lookup_digest_entry(digest)) {
 			audit_cause = "hash_exists";
+			result = -EEXIST;
 			goto out;
 		}
 	}
@@ -128,9 +133,11 @@
 	if (violation)		/* invalidate pcr */
 		memset(digest, 0xff, sizeof digest);
 
-	result = ima_pcr_extend(digest);
-	if (result != 0) {
-		audit_cause = "TPM error";
+	tpmresult = ima_pcr_extend(digest);
+	if (tpmresult != 0) {
+		snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
+			 tpmresult);
+		audit_cause = tpm_audit_cause;
 		audit_info = 0;
 	}
 out:
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 5b366d7..69ff52c 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -102,7 +102,8 @@
 		key->expiry = 0;
 	}
 
-	kfree_rcu(zap, rcu);
+	if (zap)
+		kfree_rcu(zap, rcu);
 
 error:
 	return ret;
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index cfe2d72..e2b74eb 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -139,7 +139,9 @@
 	if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
 		struct sel_netport *tail;
 		tail = list_entry(
-			rcu_dereference(sel_netport_hash[idx].list.prev),
+			rcu_dereference_protected(
+				sel_netport_hash[idx].list.prev,
+				lockdep_is_held(&sel_netport_lock)),
 			struct sel_netport, list);
 		list_del_rcu(&tail->list);
 		call_rcu(&tail->rcu, sel_netport_free);
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index d1e05b0..a339187 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -95,7 +95,6 @@
 		return NULL;
 	is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
 	while (1) {
-		struct path ns_root = { .mnt = NULL, .dentry = NULL };
 		char *pos;
 		buf_len <<= 1;
 		kfree(buf);
@@ -128,8 +127,12 @@
 		/* If we don't have a vfsmount, we can't calculate. */
 		if (!path->mnt)
 			break;
-		/* go to whatever namespace root we are under */
-		pos = __d_path(path, &ns_root, buf, buf_len);
+		pos = d_absolute_path(path, buf, buf_len - 1);
+		/* If path is disconnected, use "[unknown]" instead. */
+		if (pos == ERR_PTR(-EINVAL)) {
+			name = tomoyo_encode("[unknown]");
+			break;
+		}
 		/* Prepend "/proc" prefix if using internal proc vfs mount. */
 		if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
 		    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 45b4a8d..67d341f 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1328,7 +1328,7 @@
 		for (i = 0; i < c->cvt_setups.used; i++) {
 			p = snd_array_elem(&c->cvt_setups, i);
 			if (!p->active && p->stream_tag == stream_tag &&
-			    get_wcaps_type(get_wcaps(codec, p->nid)) == type)
+			    get_wcaps_type(get_wcaps(c, p->nid)) == type)
 				p->dirty = 1;
 		}
 	}
@@ -2187,6 +2187,39 @@
 	return 0;
 }
 
+typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
+
+/* apply the function to all matching slave ctls in the mixer list */
+static int map_slaves(struct hda_codec *codec, const char * const *slaves,
+		      map_slave_func_t func, void *data)
+{
+	struct hda_nid_item *items;
+	const char * const *s;
+	int i, err;
+
+	items = codec->mixers.list;
+	for (i = 0; i < codec->mixers.used; i++) {
+		struct snd_kcontrol *sctl = items[i].kctl;
+		if (!sctl || !sctl->id.name ||
+		    sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
+			continue;
+		for (s = slaves; *s; s++) {
+			if (!strcmp(sctl->id.name, *s)) {
+				err = func(data, sctl);
+				if (err)
+					return err;
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+static int check_slave_present(void *data, struct snd_kcontrol *sctl)
+{
+	return 1;
+}
+
 /**
  * snd_hda_add_vmaster - create a virtual master control and add slaves
  * @codec: HD-audio codec
@@ -2207,12 +2240,10 @@
 			unsigned int *tlv, const char * const *slaves)
 {
 	struct snd_kcontrol *kctl;
-	const char * const *s;
 	int err;
 
-	for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++)
-		;
-	if (!*s) {
+	err = map_slaves(codec, slaves, check_slave_present, NULL);
+	if (err != 1) {
 		snd_printdd("No slave found for %s\n", name);
 		return 0;
 	}
@@ -2223,23 +2254,10 @@
 	if (err < 0)
 		return err;
 
-	for (s = slaves; *s; s++) {
-		struct snd_kcontrol *sctl;
-		int i = 0;
-		for (;;) {
-			sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
-			if (!sctl) {
-				if (!i)
-					snd_printdd("Cannot find slave %s, "
-						    "skipped\n", *s);
-				break;
-			}
-			err = snd_ctl_add_slave(kctl, sctl);
-			if (err < 0)
-				return err;
-			i++;
-		}
-	}
+	err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
+			 kctl);
+	if (err < 0)
+		return err;
 	return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 08ec073..e289a13 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -474,7 +474,12 @@
 }
 
 /* get the widget type from widget capability bits */
-#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT)
+static inline int get_wcaps_type(unsigned int wcaps)
+{
+	if (!wcaps)
+		return -1; /* invalid type */
+	return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+}
 
 static inline unsigned int get_wcaps_channels(u32 wcaps)
 {
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index bfe74c2..6fe944a 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -54,6 +54,8 @@
 		[AC_WID_BEEP] = "Beep Generator Widget",
 		[AC_WID_VENDOR] = "Vendor Defined Widget",
 	};
+	if (wid_value == -1)
+		return "UNKNOWN Widget";
 	wid_value &= 0xf;
 	if (names[wid_value])
 		return names[wid_value];
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index cf1fa36..3c2381c 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -136,6 +136,7 @@
 	unsigned int thinkpad:1;
 	unsigned int hp_laptop:1;
 	unsigned int asus:1;
+	unsigned int single_adc_amp:1;
 
 	unsigned int adc_switching:1;
 
@@ -4205,6 +4206,8 @@
 		int idx = get_input_connection(codec, adc_nid, nid);
 		if (idx < 0)
 			continue;
+		if (spec->single_adc_amp)
+			idx = 0;
 		return cx_auto_add_volume_idx(codec, label, pfx,
 					      cidx, adc_nid, HDA_INPUT, idx);
 	}
@@ -4245,14 +4248,21 @@
 	struct hda_input_mux *imux = &spec->private_imux;
 	const char *prev_label;
 	int input_conn[HDA_MAX_NUM_INPUTS];
-	int i, err, cidx;
+	int i, j, err, cidx;
 	int multi_connection;
 
+	if (!imux->num_items)
+		return 0;
+
 	multi_connection = 0;
 	for (i = 0; i < imux->num_items; i++) {
 		cidx = get_input_connection(codec, spec->imux_info[i].adc,
 					    spec->imux_info[i].pin);
-		input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
+		if (cidx < 0)
+			continue;
+		input_conn[i] = spec->imux_info[i].adc;
+		if (!spec->single_adc_amp)
+			input_conn[i] |= cidx << 8;
 		if (i > 0 && input_conn[i] != input_conn[0])
 			multi_connection = 1;
 	}
@@ -4281,6 +4291,15 @@
 			err = cx_auto_add_capture_volume(codec, nid,
 							 "Capture", "", cidx);
 		} else {
+			bool dup_found = false;
+			for (j = 0; j < i; j++) {
+				if (input_conn[j] == input_conn[i]) {
+					dup_found = true;
+					break;
+				}
+			}
+			if (dup_found)
+				continue;
 			err = cx_auto_add_capture_volume(codec, nid,
 							 label, " Capture", cidx);
 		}
@@ -4357,6 +4376,13 @@
 		return -ENOMEM;
 	codec->spec = spec;
 	codec->pin_amp_workaround = 1;
+
+	switch (codec->vendor_id) {
+	case 0x14f15045:
+		spec->single_adc_amp = 1;
+		break;
+	}
+
 	err = cx_auto_search_adcs(codec);
 	if (err < 0)
 		return err;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4c7cd6b..51412e1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -509,6 +509,8 @@
 	imux = &spec->input_mux[mux_idx];
 	if (!imux->num_items && mux_idx > 0)
 		imux = &spec->input_mux[0];
+	if (!imux->num_items)
+		return 0;
 
 	type = get_wcaps_type(get_wcaps(codec, nid));
 	if (type == AC_WID_AUD_MIX) {
@@ -2088,25 +2090,27 @@
 static void alc_auto_parse_digital(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	int i, err;
+	int i, err, nums;
 	hda_nid_t dig_nid;
 
 	/* support multiple SPDIFs; the secondary is set up as a slave */
+	nums = 0;
 	for (i = 0; i < spec->autocfg.dig_outs; i++) {
 		err = snd_hda_get_connections(codec,
 					      spec->autocfg.dig_out_pins[i],
 					      &dig_nid, 1);
-		if (err < 0)
+		if (err <= 0)
 			continue;
-		if (!i) {
+		if (!nums) {
 			spec->multiout.dig_out_nid = dig_nid;
 			spec->dig_out_type = spec->autocfg.dig_out_type[0];
 		} else {
 			spec->multiout.slave_dig_outs = spec->slave_dig_outs;
-			if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
+			if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
 				break;
-			spec->slave_dig_outs[i - 1] = dig_nid;
+			spec->slave_dig_outs[nums - 1] = dig_nid;
 		}
+		nums++;
 	}
 
 	if (spec->autocfg.dig_in_pin) {
@@ -16415,6 +16419,7 @@
 /* Pin config fixes */
 enum {
 	PINFIX_FSC_AMILO_PI1505,
+	PINFIX_ASUS_A6RP,
 };
 
 static const struct alc_fixup alc861_fixups[] = {
@@ -16426,9 +16431,19 @@
 			{ }
 		}
 	},
+	[PINFIX_ASUS_A6RP] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* node 0x0f VREF seems controlling the master output */
+			{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+			{ }
+		},
+	},
 };
 
 static const struct snd_pci_quirk alc861_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", PINFIX_ASUS_A6RP),
+	SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP),
 	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
 	{}
 };
@@ -20126,6 +20141,8 @@
 	  .patch = patch_alc882 },
 	{ .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
 	  .patch = patch_alc662 },
+	{ .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3",
+	  .patch = patch_alc662 },
 	{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
 	{ .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
 	{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 5c42f3e..43d88c7 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1602,7 +1602,7 @@
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd,
 				"Dell Studio 1557", STAC_DELL_M6_DMIC),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
-				"Dell Studio XPS 1645", STAC_DELL_M6_BOTH),
+				"Dell Studio XPS 1645", STAC_DELL_M6_DMIC),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
 				"Dell Studio 1558", STAC_DELL_M6_DMIC),
 	{} /* terminator */
@@ -4162,13 +4162,15 @@
 	return 1;
 }
 
-static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
+static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
 {
 	int i;
 	for (i = 0; i < cfg->hp_outs; i++)
 		if (cfg->hp_pins[i] == nid)
 			return 1; /* nid is a HP-Out */
-
+	for (i = 0; i < cfg->line_outs; i++)
+		if (cfg->line_out_pins[i] == nid)
+			return 1; /* nid is a line-Out */
 	return 0; /* nid is not a HP-Out */
 };
 
@@ -4354,7 +4356,7 @@
 			continue;
 		}
 
-		if (is_nid_hp_pin(cfg, nid))
+		if (is_nid_out_jack_pin(cfg, nid))
 			continue; /* already has an unsol event */
 
 		pinctl = snd_hda_codec_read(codec, nid, 0,
@@ -5425,9 +5427,7 @@
 static int patch_stac92hd83xxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
-	hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
 	int err;
-	int num_dacs;
 
 	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -5467,26 +5467,8 @@
 		stac92xx_set_config_regs(codec,
 				stac92hd83xxx_brd_tbl[spec->board_config]);
 
-	switch (codec->vendor_id) {
-	case 0x111d76d1:
-	case 0x111d76d9:
-	case 0x111d76df:
-	case 0x111d76e5:
-	case 0x111d7666:
-	case 0x111d7667:
-	case 0x111d7668:
-	case 0x111d7669:
-	case 0x111d76e3:
-	case 0x111d7604:
-	case 0x111d76d4:
-	case 0x111d7605:
-	case 0x111d76d5:
-	case 0x111d76e7:
-		if (spec->board_config == STAC_92HD83XXX_PWR_REF)
-			break;
+	if (spec->board_config != STAC_92HD83XXX_PWR_REF)
 		spec->num_pwrs = 0;
-		break;
-	}
 
 	codec->patch_ops = stac92xx_patch_ops;
 
@@ -5506,7 +5488,11 @@
 	}
 #endif	
 
-	err = stac92xx_parse_auto_config(codec, 0x1d, 0);
+	/* 92HD65/66 series has S/PDIF-IN */
+	if (codec->vendor_id >= 0x111d76e8 && codec->vendor_id <= 0x111d76f3)
+		err = stac92xx_parse_auto_config(codec, 0x1d, 0x22);
+	else
+		err = stac92xx_parse_auto_config(codec, 0x1d, 0);
 	if (!err) {
 		if (spec->board_config < 0) {
 			printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5522,22 +5508,6 @@
 		return err;
 	}
 
-	/* docking output support */
-	num_dacs = snd_hda_get_connections(codec, 0xF,
-				conn, STAC92HD83_DAC_COUNT + 1) - 1;
-	/* skip non-DAC connections */
-	while (num_dacs >= 0 &&
-			(get_wcaps_type(get_wcaps(codec, conn[num_dacs]))
-					!= AC_WID_AUD_OUT))
-		num_dacs--;
-	/* set port E and F to select the last DAC */
-	if (num_dacs >= 0) {
-		snd_hda_codec_write_cache(codec, 0xE, 0,
-			AC_VERB_SET_CONNECT_SEL, num_dacs);
-		snd_hda_codec_write_cache(codec, 0xF, 0,
-			AC_VERB_SET_CONNECT_SEL, num_dacs);
-	}
-
 	codec->proc_widget_hook = stac92hd_proc_hook;
 
 	return 0;
@@ -6405,6 +6375,18 @@
 	{ .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx},
 	{} /* terminator */
 };
 
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c
index e328cfb..e525da2 100644
--- a/sound/pci/ice1712/amp.c
+++ b/sound/pci/ice1712/amp.c
@@ -68,8 +68,11 @@
 
 static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice)
 {
-	/* we use pins 39 and 41 of the VT1616 for left and right read outputs */
-	snd_ac97_write_cache(ice->ac97, 0x5a, snd_ac97_read(ice->ac97, 0x5a) & ~0x8000);
+	if (ice->ac97)
+		/* we use pins 39 and 41 of the VT1616 for left and right
+		read outputs */
+		snd_ac97_write_cache(ice->ac97, 0x5a,
+			snd_ac97_read(ice->ac97, 0x5a) & ~0x8000);
 	return 0;
 }
 
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
index 617f98b..713f798 100644
--- a/sound/pci/lx6464es/lx_core.c
+++ b/sound/pci/lx6464es/lx_core.c
@@ -80,8 +80,12 @@
 
 void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len)
 {
-	void __iomem *address = lx_dsp_register(chip, port);
-	memcpy_fromio(data, address, len*sizeof(u32));
+	u32 __iomem *address = lx_dsp_register(chip, port);
+	int i;
+
+	/* we cannot use memcpy_fromio */
+	for (i = 0; i != len; ++i)
+		data[i] = ioread32(address + i);
 }
 
 
@@ -94,8 +98,12 @@
 void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
 			 u32 len)
 {
-	void __iomem *address = lx_dsp_register(chip, port);
-	memcpy_toio(address, data, len*sizeof(u32));
+	u32 __iomem *address = lx_dsp_register(chip, port);
+	int i;
+
+	/* we cannot use memcpy_to */
+	for (i = 0; i != len; ++i)
+		iowrite32(data[i], address + i);
 }
 
 
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index 42d1ab1..915546a 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -177,6 +177,7 @@
 	struct xonar_wm87x6 *data = chip->model_data;
 
 	wm8776_write(chip, WM8776_RESET, 0);
+	wm8776_write(chip, WM8776_PHASESWAP, WM8776_PH_MASK);
 	wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN |
 		     WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT);
 	wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0);
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 2b5c7a95..5fe840b 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -41,6 +41,7 @@
 static int index = SNDRV_DEFAULT_IDX1;	/* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;	/* ID for this card */
 static int enable = 1;
+static int codecs = 1;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator.");
@@ -48,6 +49,8 @@
 MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator.");
 module_param(enable, bool, 0444);
 MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator.");
+module_param(codecs, int, 0444);
+MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)");
 
 static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) },
@@ -140,6 +143,9 @@
 	dma_addr_t silence_dma_addr;
 };
 
+/* These values are also used by the module param 'codecs' to indicate
+ * which codecs should be present.
+ */
 #define SIS_PRIMARY_CODEC_PRESENT	0x0001
 #define SIS_SECONDARY_CODEC_PRESENT	0x0002
 #define SIS_TERTIARY_CODEC_PRESENT	0x0004
@@ -1078,6 +1084,7 @@
 {
 	unsigned long io = sis->ioport;
 	void __iomem *ioaddr = sis->ioaddr;
+	unsigned long timeout;
 	u16 status;
 	int count;
 	int i;
@@ -1104,22 +1111,46 @@
 	while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
 		udelay(1);
 
-	/* Now that we've finished the reset, find out what's attached.
-	 */
-	status = inl(io + SIS_AC97_STATUS);
-	if (status & SIS_AC97_STATUS_CODEC_READY)
-		sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
-	if (status & SIS_AC97_STATUS_CODEC2_READY)
-		sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
-	if (status & SIS_AC97_STATUS_CODEC3_READY)
-		sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
-
-	/* All done, let go of the semaphore, and check for errors
+	/* Command complete, we can let go of the semaphore now.
 	 */
 	outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
-	if (!sis->codecs_present || !count)
+	if (!count)
 		return -EIO;
 
+	/* Now that we've finished the reset, find out what's attached.
+	 * There are some codec/board combinations that take an extremely
+	 * long time to come up. 350+ ms has been observed in the field,
+	 * so we'll give them up to 500ms.
+	 */
+	sis->codecs_present = 0;
+	timeout = msecs_to_jiffies(500) + jiffies;
+	while (time_before_eq(jiffies, timeout)) {
+		status = inl(io + SIS_AC97_STATUS);
+		if (status & SIS_AC97_STATUS_CODEC_READY)
+			sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
+		if (status & SIS_AC97_STATUS_CODEC2_READY)
+			sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
+		if (status & SIS_AC97_STATUS_CODEC3_READY)
+			sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
+
+		if (sis->codecs_present == codecs)
+			break;
+
+		msleep(1);
+	}
+
+	/* All done, check for errors.
+	 */
+	if (!sis->codecs_present) {
+		printk(KERN_ERR "sis7019: could not find any codecs\n");
+		return -EIO;
+	}
+
+	if (sis->codecs_present != codecs) {
+		printk(KERN_WARNING "sis7019: missing codecs, found %0x, expected %0x\n",
+		       sis->codecs_present, codecs);
+	}
+
 	/* Let the hardware know that the audio driver is alive,
 	 * and enable PCM slots on the AC-link for L/R playback (3 & 4) and
 	 * record channels. We're going to want to use Variable Rate Audio
@@ -1390,6 +1421,17 @@
 	if (!enable)
 		goto error_out;
 
+	/* The user can specify which codecs should be present so that we
+	 * can wait for them to show up if they are slow to recover from
+	 * the AC97 cold reset. We default to a single codec, the primary.
+	 *
+	 * We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2.
+	 */
+	codecs &= SIS_PRIMARY_CODEC_PRESENT | SIS_SECONDARY_CODEC_PRESENT |
+		  SIS_TERTIARY_CODEC_PRESENT;
+	if (!codecs)
+		codecs = SIS_PRIMARY_CODEC_PRESENT;
+
 	rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
 	if (rc < 0)
 		goto error_out;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b923a25..88181a6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -250,6 +250,9 @@
 config SND_SOC_UDA1380
         tristate
 
+config SND_SOC_WCD9304
+	tristate
+
 config SND_SOC_WCD9310
         tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 78740ab..0bd7255 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -38,6 +38,7 @@
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
 snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
@@ -132,6 +133,7 @@
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WCD9304)	+= snd-soc-wcd9304.o
 obj-$(CONFIG_SND_SOC_WCD9310)	+= snd-soc-wcd9310.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index e1a214e..65abd09 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -40,11 +40,11 @@
 /*
  * ak4535 register cache
  */
-static const u16 ak4535_reg[AK4535_CACHEREGNUM] = {
-    0x0000, 0x0080, 0x0000, 0x0003,
-    0x0002, 0x0000, 0x0011, 0x0001,
-    0x0000, 0x0040, 0x0036, 0x0010,
-    0x0000, 0x0000, 0x0057, 0x0000,
+static const u8 ak4535_reg[AK4535_CACHEREGNUM] = {
+	0x00, 0x80, 0x00, 0x03,
+	0x02, 0x00, 0x11, 0x01,
+	0x00, 0x40, 0x36, 0x10,
+	0x00, 0x00, 0x57, 0x00,
 };
 
 /*
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 65f4604..79c1b3d 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -162,17 +162,17 @@
 /*
  * ak4642 register cache
  */
-static const u16 ak4642_reg[AK4642_CACHEREGNUM] = {
-	0x0000, 0x0000, 0x0001, 0x0000,
-	0x0002, 0x0000, 0x0000, 0x0000,
-	0x00e1, 0x00e1, 0x0018, 0x0000,
-	0x00e1, 0x0018, 0x0011, 0x0008,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000,
+static const u8 ak4642_reg[AK4642_CACHEREGNUM] = {
+	0x00, 0x00, 0x01, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0xe1, 0xe1, 0x18, 0x00,
+	0xe1, 0x18, 0x11, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00,
 };
 
 /*
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index c49317c..b65fd65 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -832,7 +832,7 @@
 	ldo->voltage = voltage;
 
 	ldo->dev = regulator_register(&ldo->desc, codec->dev,
-					  init_data, ldo);
+					  init_data, ldo, NULL);
 	if (IS_ERR(ldo->dev)) {
 		int ret = PTR_ERR(ldo->dev);
 
diff --git a/sound/soc/codecs/wcd9304-tables.c b/sound/soc/codecs/wcd9304-tables.c
new file mode 100644
index 0000000..823f926
--- /dev/null
+++ b/sound/soc/codecs/wcd9304-tables.c
@@ -0,0 +1,720 @@
+/* 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/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
+#include "wcd9304.h"
+
+const u8 sitar_reg_defaults[SITAR_CACHE_SIZE] = {
+	[WCD9XXX_A_CHIP_CTL] = WCD9XXX_A_CHIP_CTL__POR,
+	[WCD9XXX_A_CHIP_STATUS] = WCD9XXX_A_CHIP_STATUS__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_0] = WCD9XXX_A_CHIP_ID_BYTE_0__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_1] = WCD9XXX_A_CHIP_ID_BYTE_1__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_2] = WCD9XXX_A_CHIP_ID_BYTE_2__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_3] = WCD9XXX_A_CHIP_ID_BYTE_3__POR,
+	[WCD9XXX_A_CHIP_VERSION] = WCD9XXX_A_CHIP_VERSION__POR,
+	[WCD9XXX_A_SB_VERSION] = WCD9XXX_A_SB_VERSION__POR,
+	[WCD9XXX_A_SLAVE_ID_1] = WCD9XXX_A_SLAVE_ID_1__POR,
+	[WCD9XXX_A_SLAVE_ID_2] = WCD9XXX_A_SLAVE_ID_2__POR,
+	[WCD9XXX_A_SLAVE_ID_3] = WCD9XXX_A_SLAVE_ID_3__POR,
+	[SITAR_A_PIN_CTL_OE0] = SITAR_A_PIN_CTL_OE0__POR,
+	[SITAR_A_PIN_CTL_OE1] = SITAR_A_PIN_CTL_OE1__POR,
+	[SITAR_A_PIN_CTL_DATA0] = SITAR_A_PIN_CTL_DATA0__POR,
+	[SITAR_A_PIN_CTL_DATA1] = SITAR_A_PIN_CTL_DATA1__POR,
+	[SITAR_A_HDRIVE_GENERIC] = SITAR_A_HDRIVE_GENERIC__POR,
+	[SITAR_A_HDRIVE_OVERRIDE] = SITAR_A_HDRIVE_OVERRIDE__POR,
+	[SITAR_A_ANA_CSR_WAIT_STATE] = SITAR_A_ANA_CSR_WAIT_STATE__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL0] = SITAR_A_PROCESS_MONITOR_CTL0__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL1] = SITAR_A_PROCESS_MONITOR_CTL1__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL2] = SITAR_A_PROCESS_MONITOR_CTL2__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL3] = SITAR_A_PROCESS_MONITOR_CTL3__POR,
+	[SITAR_A_QFUSE_CTL] = SITAR_A_QFUSE_CTL__POR,
+	[SITAR_A_QFUSE_STATUS] = SITAR_A_QFUSE_STATUS__POR,
+	[SITAR_A_QFUSE_DATA_OUT0] = SITAR_A_QFUSE_DATA_OUT0__POR,
+	[SITAR_A_QFUSE_DATA_OUT1] = SITAR_A_QFUSE_DATA_OUT1__POR,
+	[SITAR_A_QFUSE_DATA_OUT2] = SITAR_A_QFUSE_DATA_OUT2__POR,
+	[SITAR_A_QFUSE_DATA_OUT3] = SITAR_A_QFUSE_DATA_OUT3__POR,
+	[SITAR_A_CDC_CTL] = SITAR_A_CDC_CTL__POR,
+	[SITAR_A_LEAKAGE_CTL] = SITAR_A_LEAKAGE_CTL__POR,
+	[SITAR_A_INTR_MODE] = SITAR_A_INTR_MODE__POR,
+	[SITAR_A_INTR_MASK0] = SITAR_A_INTR_MASK0__POR,
+	[SITAR_A_INTR_MASK1] = SITAR_A_INTR_MASK1__POR,
+	[SITAR_A_INTR_MASK2] = SITAR_A_INTR_MASK2__POR,
+	[SITAR_A_INTR_STATUS0] = SITAR_A_INTR_STATUS0__POR,
+	[SITAR_A_INTR_STATUS1] = SITAR_A_INTR_STATUS1__POR,
+	[SITAR_A_INTR_STATUS2] = SITAR_A_INTR_STATUS2__POR,
+	[SITAR_A_INTR_CLEAR0] = SITAR_A_INTR_CLEAR0__POR,
+	[SITAR_A_INTR_CLEAR1] = SITAR_A_INTR_CLEAR1__POR,
+	[SITAR_A_INTR_CLEAR2] = SITAR_A_INTR_CLEAR2__POR,
+	[SITAR_A_INTR_LEVEL0] = SITAR_A_INTR_LEVEL0__POR,
+	[SITAR_A_INTR_LEVEL1] = SITAR_A_INTR_LEVEL1__POR,
+	[SITAR_A_INTR_LEVEL2] = SITAR_A_INTR_LEVEL2__POR,
+	[SITAR_A_INTR_TEST0] = SITAR_A_INTR_TEST0__POR,
+	[SITAR_A_INTR_TEST1] = SITAR_A_INTR_TEST1__POR,
+	[SITAR_A_INTR_TEST2] = SITAR_A_INTR_TEST2__POR,
+	[SITAR_A_INTR_SET0] = SITAR_A_INTR_SET0__POR,
+	[SITAR_A_INTR_SET1] = SITAR_A_INTR_SET1__POR,
+	[SITAR_A_INTR_SET2] = SITAR_A_INTR_SET2__POR,
+	[SITAR_A_CDC_TX_I2S_SCK_MODE] = SITAR_A_CDC_TX_I2S_SCK_MODE__POR,
+	[SITAR_A_CDC_TX_I2S_WS_MODE] = SITAR_A_CDC_TX_I2S_WS_MODE__POR,
+	[SITAR_A_CDC_DMIC_DATA0_MODE] = SITAR_A_CDC_DMIC_DATA0_MODE__POR,
+	[SITAR_A_CDC_DMIC_CLK0_MODE] = SITAR_A_CDC_DMIC_CLK0_MODE__POR,
+	[SITAR_A_CDC_DMIC_DATA1_MODE] = SITAR_A_CDC_DMIC_DATA1_MODE__POR,
+	[SITAR_A_CDC_DMIC_CLK1_MODE] = SITAR_A_CDC_DMIC_CLK1_MODE__POR,
+	[SITAR_A_CDC_TX_I2S_SD0_MODE] = SITAR_A_CDC_TX_I2S_SD0_MODE__POR,
+	[SITAR_A_CDC_INTR_MODE] = SITAR_A_CDC_INTR_MODE__POR,
+	[SITAR_A_CDC_RX_I2S_SD0_MODE] = SITAR_A_CDC_RX_I2S_SD0_MODE__POR,
+	[SITAR_A_CDC_RX_I2S_SD1_MODE] = SITAR_A_CDC_RX_I2S_SD1_MODE__POR,
+	[SITAR_A_BIAS_REF_CTL] = SITAR_A_BIAS_REF_CTL__POR,
+	[SITAR_A_BIAS_CENTRAL_BG_CTL] = SITAR_A_BIAS_CENTRAL_BG_CTL__POR,
+	[SITAR_A_BIAS_PRECHRG_CTL] = SITAR_A_BIAS_PRECHRG_CTL__POR,
+	[SITAR_A_BIAS_CURR_CTL_1] = SITAR_A_BIAS_CURR_CTL_1__POR,
+	[SITAR_A_BIAS_CURR_CTL_2] = SITAR_A_BIAS_CURR_CTL_2__POR,
+	[SITAR_A_BIAS_OSC_BG_CTL] = SITAR_A_BIAS_OSC_BG_CTL__POR,
+	[SITAR_A_CLK_BUFF_EN1] = SITAR_A_CLK_BUFF_EN1__POR,
+	[SITAR_A_CLK_BUFF_EN2] = SITAR_A_CLK_BUFF_EN2__POR,
+	[SITAR_A_LDO_H_MODE_1] = SITAR_A_LDO_H_MODE_1__POR,
+	[SITAR_A_LDO_H_MODE_2] = SITAR_A_LDO_H_MODE_2__POR,
+	[SITAR_A_LDO_H_LOOP_CTL] = SITAR_A_LDO_H_LOOP_CTL__POR,
+	[SITAR_A_LDO_H_COMP_1] = SITAR_A_LDO_H_COMP_1__POR,
+	[SITAR_A_LDO_H_COMP_2] = SITAR_A_LDO_H_COMP_2__POR,
+	[SITAR_A_LDO_H_BIAS_1] = SITAR_A_LDO_H_BIAS_1__POR,
+	[SITAR_A_LDO_H_BIAS_2] = SITAR_A_LDO_H_BIAS_2__POR,
+	[SITAR_A_LDO_H_BIAS_3] = SITAR_A_LDO_H_BIAS_3__POR,
+	[SITAR_A_MICB_CFILT_1_CTL] = SITAR_A_MICB_CFILT_1_CTL__POR,
+	[SITAR_A_MICB_CFILT_1_VAL] = SITAR_A_MICB_CFILT_1_VAL__POR,
+	[SITAR_A_MICB_CFILT_1_PRECHRG] = SITAR_A_MICB_CFILT_1_PRECHRG__POR,
+	[SITAR_A_MICB_1_CTL] = SITAR_A_MICB_1_CTL__POR,
+	[SITAR_A_MICB_1_INT_RBIAS] = SITAR_A_MICB_1_INT_RBIAS__POR,
+	[SITAR_A_MICB_1_MBHC] = SITAR_A_MICB_1_MBHC__POR,
+	[SITAR_A_MICB_CFILT_2_CTL] = SITAR_A_MICB_CFILT_2_CTL__POR,
+	[SITAR_A_MICB_CFILT_2_VAL] = SITAR_A_MICB_CFILT_2_VAL__POR,
+	[SITAR_A_MICB_CFILT_2_PRECHRG] = SITAR_A_MICB_CFILT_2_PRECHRG__POR,
+	[SITAR_A_MICB_2_CTL] = SITAR_A_MICB_2_CTL__POR,
+	[SITAR_A_MICB_2_INT_RBIAS] = SITAR_A_MICB_2_INT_RBIAS__POR,
+	[SITAR_A_MICB_2_MBHC] = SITAR_A_MICB_2_MBHC__POR,
+	[SITAR_A_TX_COM_BIAS] = SITAR_A_TX_COM_BIAS__POR,
+	[SITAR_A_MBHC_SCALING_MUX_1] = SITAR_A_MBHC_SCALING_MUX_1__POR,
+	[SITAR_A_MBHC_SCALING_MUX_2] = SITAR_A_MBHC_SCALING_MUX_2__POR,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_1] = SITAR_A_TX_SUP_SWITCH_CTRL_1__POR,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_2] = SITAR_A_TX_SUP_SWITCH_CTRL_2__POR,
+	[SITAR_A_TX_1_2_EN] = SITAR_A_TX_1_2_EN__POR,
+	[SITAR_A_TX_1_2_TEST_EN] = SITAR_A_TX_1_2_TEST_EN__POR,
+	[SITAR_A_TX_1_2_ADC_CH1] = SITAR_A_TX_1_2_ADC_CH1__POR,
+	[SITAR_A_TX_1_2_ADC_CH2] = SITAR_A_TX_1_2_ADC_CH2__POR,
+	[SITAR_A_TX_1_2_ATEST_REFCTRL] = SITAR_A_TX_1_2_ATEST_REFCTRL__POR,
+	[SITAR_A_TX_1_2_TEST_CTL] = SITAR_A_TX_1_2_TEST_CTL__POR,
+	[SITAR_A_TX_1_2_TEST_BLOCK_EN] = SITAR_A_TX_1_2_TEST_BLOCK_EN__POR,
+	[SITAR_A_TX_1_2_TXFE_CLKDIV] = SITAR_A_TX_1_2_TXFE_CLKDIV__POR,
+	[SITAR_A_TX_1_2_SAR_ERR_CH1] = SITAR_A_TX_1_2_SAR_ERR_CH1__POR,
+	[SITAR_A_TX_1_2_SAR_ERR_CH2] = SITAR_A_TX_1_2_SAR_ERR_CH2__POR,
+	[SITAR_A_TX_3_EN] = SITAR_A_TX_3_EN__POR,
+	[SITAR_A_TX_3_TEST_EN] = SITAR_A_TX_3_TEST_EN__POR,
+	[SITAR_A_TX_3_ADC] = SITAR_A_TX_3_ADC__POR,
+	[SITAR_A_TX_3_MBHC_ATEST_REFCTRL] =
+		SITAR_A_TX_3_MBHC_ATEST_REFCTRL__POR,
+	[SITAR_A_TX_3_TEST_CTL] = SITAR_A_TX_3_TEST_CTL__POR,
+	[SITAR_A_TX_3_TEST_BLOCK_EN] = SITAR_A_TX_3_TEST_BLOCK_EN__POR,
+	[SITAR_A_TX_3_TXFE_CKDIV] = SITAR_A_TX_3_TXFE_CKDIV__POR,
+	[SITAR_A_TX_3_SAR_ERR] = SITAR_A_TX_3_SAR_ERR__POR,
+	[SITAR_A_TX_4_MBHC_EN] = SITAR_A_TX_4_MBHC_EN__POR,
+	[SITAR_A_TX_4_MBHC_ADC] = SITAR_A_TX_4_MBHC_ADC__POR,
+	[SITAR_A_TX_4_MBHC_TEST_CTL] = SITAR_A_TX_4_MBHC_TEST_CTL__POR,
+	[SITAR_A_TX_4_MBHC_SAR_ERR] = SITAR_A_TX_4_MBHC_SAR_ERR__POR,
+	[SITAR_A_TX_4_TXFE_CLKDIV] = SITAR_A_TX_4_TXFE_CLKDIV__POR,
+	[SITAR_A_AUX_COM_CTL] = SITAR_A_AUX_COM_CTL__POR,
+	[SITAR_A_AUX_COM_ATEST] = SITAR_A_AUX_COM_ATEST__POR,
+	[SITAR_A_AUX_L_EN] = SITAR_A_AUX_L_EN__POR,
+	[SITAR_A_AUX_L_GAIN] = SITAR_A_AUX_L_GAIN__POR,
+	[SITAR_A_AUX_L_PA_CONN] = SITAR_A_AUX_L_PA_CONN__POR,
+	[SITAR_A_AUX_L_PA_CONN_INV] = SITAR_A_AUX_L_PA_CONN_INV__POR,
+	[SITAR_A_AUX_R_EN] = SITAR_A_AUX_R_EN__POR,
+	[SITAR_A_AUX_R_GAIN] = SITAR_A_AUX_R_GAIN__POR,
+	[SITAR_A_AUX_R_PA_CONN] = SITAR_A_AUX_R_PA_CONN__POR,
+	[SITAR_A_AUX_R_PA_CONN_INV] = SITAR_A_AUX_R_PA_CONN_INV__POR,
+	[SITAR_A_CP_EN] = SITAR_A_CP_EN__POR,
+	[SITAR_A_CP_CLK] = SITAR_A_CP_CLK__POR,
+	[SITAR_A_CP_STATIC] = SITAR_A_CP_STATIC__POR,
+	[SITAR_A_CP_DCC1] = SITAR_A_CP_DCC1__POR,
+	[SITAR_A_CP_DCC3] = SITAR_A_CP_DCC3__POR,
+	[SITAR_A_CP_ATEST] = SITAR_A_CP_ATEST__POR,
+	[SITAR_A_CP_DTEST] = SITAR_A_CP_DTEST__POR,
+	[SITAR_A_RX_COM_TIMER_DIV] = SITAR_A_RX_COM_TIMER_DIV__POR,
+	[SITAR_A_RX_COM_OCP_CTL] = SITAR_A_RX_COM_OCP_CTL__POR,
+	[SITAR_A_RX_COM_OCP_COUNT] = SITAR_A_RX_COM_OCP_COUNT__POR,
+	[SITAR_A_RX_COM_DAC_CTL] = SITAR_A_RX_COM_DAC_CTL__POR,
+	[SITAR_A_RX_COM_BIAS] = SITAR_A_RX_COM_BIAS__POR,
+	[SITAR_A_RX_HPH_BIAS_PA] = SITAR_A_RX_HPH_BIAS_PA__POR,
+	[SITAR_A_RX_HPH_BIAS_LDO] = SITAR_A_RX_HPH_BIAS_LDO__POR,
+	[SITAR_A_RX_HPH_BIAS_CNP] = SITAR_A_RX_HPH_BIAS_CNP__POR,
+	[SITAR_A_RX_HPH_BIAS_WG] = SITAR_A_RX_HPH_BIAS_WG__POR,
+	[SITAR_A_RX_HPH_OCP_CTL] = SITAR_A_RX_HPH_OCP_CTL__POR,
+	[SITAR_A_RX_HPH_CNP_EN] = SITAR_A_RX_HPH_CNP_EN__POR,
+	[SITAR_A_RX_HPH_CNP_WG_CTL] = SITAR_A_RX_HPH_CNP_WG_CTL__POR,
+	[SITAR_A_RX_HPH_CNP_WG_TIME] = SITAR_A_RX_HPH_CNP_WG_TIME__POR,
+	[SITAR_A_RX_HPH_L_GAIN] = SITAR_A_RX_HPH_L_GAIN__POR,
+	[SITAR_A_RX_HPH_L_TEST] = SITAR_A_RX_HPH_L_TEST__POR,
+	[SITAR_A_RX_HPH_L_PA_CTL] = SITAR_A_RX_HPH_L_PA_CTL__POR,
+	[SITAR_A_RX_HPH_L_DAC_CTL] = SITAR_A_RX_HPH_L_DAC_CTL__POR,
+	[SITAR_A_RX_HPH_L_ATEST] = SITAR_A_RX_HPH_L_ATEST__POR,
+	[SITAR_A_RX_HPH_L_STATUS] = SITAR_A_RX_HPH_L_STATUS__POR,
+	[SITAR_A_RX_HPH_R_GAIN] = SITAR_A_RX_HPH_R_GAIN__POR,
+	[SITAR_A_RX_HPH_R_TEST] = SITAR_A_RX_HPH_R_TEST__POR,
+	[SITAR_A_RX_HPH_R_PA_CTL] = SITAR_A_RX_HPH_R_PA_CTL__POR,
+	[SITAR_A_RX_HPH_R_DAC_CTL] = SITAR_A_RX_HPH_R_DAC_CTL__POR,
+	[SITAR_A_RX_HPH_R_ATEST] = SITAR_A_RX_HPH_R_ATEST__POR,
+	[SITAR_A_RX_HPH_R_STATUS] = SITAR_A_RX_HPH_R_STATUS__POR,
+	[SITAR_A_RX_EAR_BIAS_PA] = SITAR_A_RX_EAR_BIAS_PA__POR,
+	[SITAR_A_RX_EAR_BIAS_CMBUFF] = SITAR_A_RX_EAR_BIAS_CMBUFF__POR,
+	[SITAR_A_RX_EAR_EN] = SITAR_A_RX_EAR_EN__POR,
+	[SITAR_A_RX_EAR_GAIN] = SITAR_A_RX_EAR_GAIN__POR,
+	[SITAR_A_RX_EAR_CMBUFF] = SITAR_A_RX_EAR_CMBUFF__POR,
+	[SITAR_A_RX_EAR_ICTL] = SITAR_A_RX_EAR_ICTL__POR,
+	[SITAR_A_RX_EAR_CCOMP] = SITAR_A_RX_EAR_CCOMP__POR,
+	[SITAR_A_RX_EAR_VCM] = SITAR_A_RX_EAR_VCM__POR,
+	[SITAR_A_RX_EAR_CNP] = SITAR_A_RX_EAR_CNP__POR,
+	[SITAR_A_RX_EAR_ATEST] = SITAR_A_RX_EAR_ATEST__POR,
+	[SITAR_A_RX_EAR_STATUS] = SITAR_A_RX_EAR_STATUS__POR,
+	[SITAR_A_RX_LINE_BIAS_PA] = SITAR_A_RX_LINE_BIAS_PA__POR,
+	[SITAR_A_RX_LINE_BIAS_LDO] = SITAR_A_RX_LINE_BIAS_LDO__POR,
+	[SITAR_A_RX_LINE_BIAS_CNP1] = SITAR_A_RX_LINE_BIAS_CNP1__POR,
+	[SITAR_A_RX_LINE_COM] = SITAR_A_RX_LINE_COM__POR,
+	[SITAR_A_RX_LINE_CNP_EN] = SITAR_A_RX_LINE_CNP_EN__POR,
+	[SITAR_A_RX_LINE_CNP_WG_CTL] = SITAR_A_RX_LINE_CNP_WG_CTL__POR,
+	[SITAR_A_RX_LINE_CNP_WG_TIME] = SITAR_A_RX_LINE_CNP_WG_TIME__POR,
+	[SITAR_A_RX_LINE_1_GAIN] = SITAR_A_RX_LINE_1_GAIN__POR,
+	[SITAR_A_RX_LINE_1_TEST] = SITAR_A_RX_LINE_1_TEST__POR,
+	[SITAR_A_RX_LINE_1_DAC_CTL] = SITAR_A_RX_LINE_1_DAC_CTL__POR,
+	[SITAR_A_RX_LINE_1_STATUS] = SITAR_A_RX_LINE_1_STATUS__POR,
+	[SITAR_A_RX_LINE_2_GAIN] = SITAR_A_RX_LINE_2_GAIN__POR,
+	[SITAR_A_RX_LINE_2_TEST] = SITAR_A_RX_LINE_2_TEST__POR,
+	[SITAR_A_RX_LINE_2_DAC_CTL] = SITAR_A_RX_LINE_2_DAC_CTL__POR,
+	[SITAR_A_RX_LINE_2_STATUS] = SITAR_A_RX_LINE_2_STATUS__POR,
+	[SITAR_A_RX_LINE_BIAS_CNP2] = SITAR_A_RX_LINE_BIAS_CNP2__POR,
+	[SITAR_A_RX_LINE_OCP_CTL] = SITAR_A_RX_LINE_OCP_CTL__POR,
+	[SITAR_A_RX_LINE_1_PA_CTL] = SITAR_A_RX_LINE_1_PA_CTL__POR,
+	[SITAR_A_RX_LINE_2_PA_CTL] = SITAR_A_RX_LINE_2_PA_CTL__POR,
+	[SITAR_A_RX_LINE_CNP_DBG] = SITAR_A_RX_LINE_CNP_DBG__POR,
+	[SITAR_A_MBHC_HPH] = SITAR_A_MBHC_HPH__POR,
+	[SITAR_A_RC_OSC_FREQ] = SITAR_A_RC_OSC_FREQ__POR,
+	[SITAR_A_RC_OSC_TEST] = SITAR_A_RC_OSC_TEST__POR,
+	[SITAR_A_RC_OSC_STATUS] = SITAR_A_RC_OSC_STATUS__POR,
+	[SITAR_A_RC_OSC_TUNER] = SITAR_A_RC_OSC_TUNER__POR,
+	[SITAR_A_CDC_ANC1_CTL] = SITAR_A_CDC_ANC1_CTL__POR,
+	[SITAR_A_CDC_ANC1_SHIFT] = SITAR_A_CDC_ANC1_SHIFT__POR,
+	[SITAR_A_CDC_ANC1_IIR_B1_CTL] = SITAR_A_CDC_ANC1_IIR_B1_CTL__POR,
+	[SITAR_A_CDC_ANC1_IIR_B2_CTL] = SITAR_A_CDC_ANC1_IIR_B2_CTL__POR,
+	[SITAR_A_CDC_ANC1_IIR_B3_CTL] = SITAR_A_CDC_ANC1_IIR_B3_CTL__POR,
+	[SITAR_A_CDC_ANC1_IIR_B4_CTL] = SITAR_A_CDC_ANC1_IIR_B4_CTL__POR,
+	[SITAR_A_CDC_ANC1_LPF_B1_CTL] = SITAR_A_CDC_ANC1_LPF_B1_CTL__POR,
+	[SITAR_A_CDC_ANC1_LPF_B2_CTL] = SITAR_A_CDC_ANC1_LPF_B2_CTL__POR,
+	[SITAR_A_CDC_ANC1_LPF_B3_CTL] = SITAR_A_CDC_ANC1_LPF_B3_CTL__POR,
+	[SITAR_A_CDC_ANC1_SPARE] = SITAR_A_CDC_ANC1_SPARE__POR,
+	[SITAR_A_CDC_ANC1_SMLPF_CTL] = SITAR_A_CDC_ANC1_SMLPF_CTL__POR,
+	[SITAR_A_CDC_ANC1_DCFLT_CTL] = SITAR_A_CDC_ANC1_DCFLT_CTL__POR,
+	[SITAR_A_CDC_TX1_VOL_CTL_TIMER] = SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR,
+	[SITAR_A_CDC_TX1_VOL_CTL_GAIN] = SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR,
+	[SITAR_A_CDC_TX1_VOL_CTL_CFG] = SITAR_A_CDC_TX1_VOL_CTL_CFG__POR,
+	[SITAR_A_CDC_TX1_MUX_CTL] = SITAR_A_CDC_TX1_MUX_CTL__POR,
+	[SITAR_A_CDC_TX1_CLK_FS_CTL] = SITAR_A_CDC_TX1_CLK_FS_CTL__POR,
+	[SITAR_A_CDC_TX1_DMIC_CTL] = SITAR_A_CDC_TX1_DMIC_CTL__POR,
+	[SITAR_A_CDC_SRC1_PDA_CFG] = SITAR_A_CDC_SRC1_PDA_CFG__POR,
+	[SITAR_A_CDC_SRC1_FS_CTL] = SITAR_A_CDC_SRC1_FS_CTL__POR,
+	[SITAR_A_CDC_RX1_B1_CTL] = SITAR_A_CDC_RX1_B1_CTL__POR,
+	[SITAR_A_CDC_RX1_B2_CTL] = SITAR_A_CDC_RX1_B2_CTL__POR,
+	[SITAR_A_CDC_RX1_B3_CTL] = SITAR_A_CDC_RX1_B3_CTL__POR,
+	[SITAR_A_CDC_RX1_B4_CTL] = SITAR_A_CDC_RX1_B4_CTL__POR,
+	[SITAR_A_CDC_RX1_B5_CTL] = SITAR_A_CDC_RX1_B5_CTL__POR,
+	[SITAR_A_CDC_RX1_B6_CTL] = SITAR_A_CDC_RX1_B6_CTL__POR,
+	[SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
+	[SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
+	[SITAR_A_CDC_CLK_ANC_RESET_CTL] = SITAR_A_CDC_CLK_ANC_RESET_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_RESET_CTL] = SITAR_A_CDC_CLK_RX_RESET_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_RESET_B1_CTL] =
+		SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_RESET_B2_CTL] =
+		SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR,
+	[SITAR_A_CDC_CLK_DMIC_CTL] = SITAR_A_CDC_CLK_DMIC_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_I2S_CTL] = SITAR_A_CDC_CLK_RX_I2S_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_I2S_CTL] = SITAR_A_CDC_CLK_TX_I2S_CTL__POR,
+	[SITAR_A_CDC_CLK_OTHR_RESET_CTL] = SITAR_A_CDC_CLK_OTHR_RESET_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
+		SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
+	[SITAR_A_CDC_CLK_OTHR_CTL] = SITAR_A_CDC_CLK_OTHR_CTL__POR,
+	[SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL] =
+		SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL__POR,
+	[SITAR_A_CDC_CLK_ANC_CLK_EN_CTL] = SITAR_A_CDC_CLK_ANC_CLK_EN_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_B1_CTL] = SITAR_A_CDC_CLK_RX_B1_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_B2_CTL] = SITAR_A_CDC_CLK_RX_B2_CTL__POR,
+	[SITAR_A_CDC_CLK_MCLK_CTL] = SITAR_A_CDC_CLK_MCLK_CTL__POR,
+	[SITAR_A_CDC_CLK_PDM_CTL] = SITAR_A_CDC_CLK_PDM_CTL__POR,
+	[SITAR_A_CDC_CLK_SD_CTL] = SITAR_A_CDC_CLK_SD_CTL__POR,
+	[SITAR_A_CDC_CLK_LP_CTL] = SITAR_A_CDC_CLK_LP_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR,
+	[SITAR_A_CDC_CLSG_GAIN_THRESH_CTL] =
+		SITAR_A_CDC_CLSG_GAIN_THRESH_CTL__POR,
+	[SITAR_A_CDC_CLSG_TIMER_B1_CFG] = SITAR_A_CDC_CLSG_TIMER_B1_CFG__POR,
+	[SITAR_A_CDC_CLSG_TIMER_B2_CFG] = SITAR_A_CDC_CLSG_TIMER_B2_CFG__POR,
+	[SITAR_A_CDC_CLSG_CTL] = SITAR_A_CDC_CLSG_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B1_CTL] = SITAR_A_CDC_IIR1_GAIN_B1_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B2_CTL] = SITAR_A_CDC_IIR1_GAIN_B2_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B3_CTL] = SITAR_A_CDC_IIR1_GAIN_B3_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B4_CTL] = SITAR_A_CDC_IIR1_GAIN_B4_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B5_CTL] = SITAR_A_CDC_IIR1_GAIN_B5_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B6_CTL] = SITAR_A_CDC_IIR1_GAIN_B6_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B7_CTL] = SITAR_A_CDC_IIR1_GAIN_B7_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B8_CTL] = SITAR_A_CDC_IIR1_GAIN_B8_CTL__POR,
+	[SITAR_A_CDC_IIR1_CTL] = SITAR_A_CDC_IIR1_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_TIMER_CTL] =
+		SITAR_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B1_CTL] = SITAR_A_CDC_IIR1_COEF_B1_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B2_CTL] = SITAR_A_CDC_IIR1_COEF_B2_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B3_CTL] = SITAR_A_CDC_IIR1_COEF_B3_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B4_CTL] = SITAR_A_CDC_IIR1_COEF_B4_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B5_CTL] = SITAR_A_CDC_IIR1_COEF_B5_CTL__POR,
+	[SITAR_A_CDC_TOP_GAIN_UPDATE] = SITAR_A_CDC_TOP_GAIN_UPDATE__POR,
+	[SITAR_A_CDC_TOP_RDAC_DOUT_CTL] = SITAR_A_CDC_TOP_RDAC_DOUT_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B1_CTL] = SITAR_A_CDC_DEBUG_B1_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B2_CTL] = SITAR_A_CDC_DEBUG_B2_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B3_CTL] = SITAR_A_CDC_DEBUG_B3_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B4_CTL] = SITAR_A_CDC_DEBUG_B4_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B5_CTL] = SITAR_A_CDC_DEBUG_B5_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B6_CTL] = SITAR_A_CDC_DEBUG_B6_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B7_CTL] = SITAR_A_CDC_DEBUG_B7_CTL__POR,
+	[SITAR_A_CDC_COMP1_B1_CTL] = SITAR_A_CDC_COMP1_B1_CTL__POR,
+	[SITAR_A_CDC_COMP1_B2_CTL] = SITAR_A_CDC_COMP1_B2_CTL__POR,
+	[SITAR_A_CDC_COMP1_B3_CTL] = SITAR_A_CDC_COMP1_B3_CTL__POR,
+	[SITAR_A_CDC_COMP1_B4_CTL] = SITAR_A_CDC_COMP1_B4_CTL__POR,
+	[SITAR_A_CDC_COMP1_B5_CTL] = SITAR_A_CDC_COMP1_B5_CTL__POR,
+	[SITAR_A_CDC_COMP1_B6_CTL] = SITAR_A_CDC_COMP1_B6_CTL__POR,
+	[SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+		SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+	[SITAR_A_CDC_COMP1_FS_CFG] = SITAR_A_CDC_COMP1_FS_CFG__POR,
+	[SITAR_A_CDC_CONN_RX1_B1_CTL] = SITAR_A_CDC_CONN_RX1_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX1_B2_CTL] = SITAR_A_CDC_CONN_RX1_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_RX1_B3_CTL] = SITAR_A_CDC_CONN_RX1_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_RX2_B1_CTL] = SITAR_A_CDC_CONN_RX2_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX2_B2_CTL] = SITAR_A_CDC_CONN_RX2_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_RX2_B3_CTL] = SITAR_A_CDC_CONN_RX2_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_RX3_B1_CTL] = SITAR_A_CDC_CONN_RX3_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX3_B2_CTL] = SITAR_A_CDC_CONN_RX3_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_RX3_B3_CTL] = SITAR_A_CDC_CONN_RX3_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_ANC_B1_CTL] = SITAR_A_CDC_CONN_ANC_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_ANC_B2_CTL] = SITAR_A_CDC_CONN_ANC_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_B1_CTL] = SITAR_A_CDC_CONN_TX_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_B2_CTL] = SITAR_A_CDC_CONN_TX_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B1_CTL] = SITAR_A_CDC_CONN_EQ1_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B2_CTL] = SITAR_A_CDC_CONN_EQ1_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B3_CTL] = SITAR_A_CDC_CONN_EQ1_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B4_CTL] = SITAR_A_CDC_CONN_EQ1_B4_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B1_CTL] = SITAR_A_CDC_CONN_EQ2_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B2_CTL] = SITAR_A_CDC_CONN_EQ2_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B3_CTL] = SITAR_A_CDC_CONN_EQ2_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B4_CTL] = SITAR_A_CDC_CONN_EQ2_B4_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC1_B1_CTL] = SITAR_A_CDC_CONN_SRC1_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC1_B2_CTL] = SITAR_A_CDC_CONN_SRC1_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC2_B1_CTL] = SITAR_A_CDC_CONN_SRC2_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC2_B2_CTL] = SITAR_A_CDC_CONN_SRC2_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B1_CTL] = SITAR_A_CDC_CONN_TX_SB_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B2_CTL] = SITAR_A_CDC_CONN_TX_SB_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B3_CTL] = SITAR_A_CDC_CONN_TX_SB_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B4_CTL] = SITAR_A_CDC_CONN_TX_SB_B4_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B5_CTL] = SITAR_A_CDC_CONN_TX_SB_B5_CTL__POR,
+	[SITAR_A_CDC_CONN_RX_SB_B1_CTL] = SITAR_A_CDC_CONN_RX_SB_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX_SB_B2_CTL] = SITAR_A_CDC_CONN_RX_SB_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_CLSG_CTL] = SITAR_A_CDC_CONN_CLSG_CTL__POR,
+	[SITAR_A_CDC_CONN_SPARE] = SITAR_A_CDC_CONN_SPARE__POR,
+	[SITAR_A_CDC_MBHC_EN_CTL] = SITAR_A_CDC_MBHC_EN_CTL__POR,
+	[SITAR_A_CDC_MBHC_FIR_B1_CFG] = SITAR_A_CDC_MBHC_FIR_B1_CFG__POR,
+	[SITAR_A_CDC_MBHC_FIR_B2_CFG] = SITAR_A_CDC_MBHC_FIR_B2_CFG__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B1_CTL] = SITAR_A_CDC_MBHC_TIMER_B1_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B2_CTL] = SITAR_A_CDC_MBHC_TIMER_B2_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B3_CTL] = SITAR_A_CDC_MBHC_TIMER_B3_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B4_CTL] = SITAR_A_CDC_MBHC_TIMER_B4_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B5_CTL] = SITAR_A_CDC_MBHC_TIMER_B5_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B6_CTL] = SITAR_A_CDC_MBHC_TIMER_B6_CTL__POR,
+	[SITAR_A_CDC_MBHC_B1_STATUS] = SITAR_A_CDC_MBHC_B1_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B2_STATUS] = SITAR_A_CDC_MBHC_B2_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B3_STATUS] = SITAR_A_CDC_MBHC_B3_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B4_STATUS] = SITAR_A_CDC_MBHC_B4_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B5_STATUS] = SITAR_A_CDC_MBHC_B5_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B1_CTL] = SITAR_A_CDC_MBHC_B1_CTL__POR,
+	[SITAR_A_CDC_MBHC_B2_CTL] = SITAR_A_CDC_MBHC_B2_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B1_CTL] = SITAR_A_CDC_MBHC_VOLT_B1_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B2_CTL] = SITAR_A_CDC_MBHC_VOLT_B2_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B3_CTL] = SITAR_A_CDC_MBHC_VOLT_B3_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B4_CTL] = SITAR_A_CDC_MBHC_VOLT_B4_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B5_CTL] = SITAR_A_CDC_MBHC_VOLT_B5_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B6_CTL] = SITAR_A_CDC_MBHC_VOLT_B6_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B7_CTL] = SITAR_A_CDC_MBHC_VOLT_B7_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B8_CTL] = SITAR_A_CDC_MBHC_VOLT_B8_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B9_CTL] = SITAR_A_CDC_MBHC_VOLT_B9_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B10_CTL] = SITAR_A_CDC_MBHC_VOLT_B10_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B11_CTL] = SITAR_A_CDC_MBHC_VOLT_B11_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B12_CTL] = SITAR_A_CDC_MBHC_VOLT_B12_CTL__POR,
+	[SITAR_A_CDC_MBHC_CLK_CTL] = SITAR_A_CDC_MBHC_CLK_CTL__POR,
+	[SITAR_A_CDC_MBHC_INT_CTL] = SITAR_A_CDC_MBHC_INT_CTL__POR,
+	[SITAR_A_CDC_MBHC_DEBUG_CTL] = SITAR_A_CDC_MBHC_DEBUG_CTL__POR,
+	[SITAR_A_CDC_MBHC_SPARE] = SITAR_A_CDC_MBHC_SPARE__POR,
+};
+
+const u8 sitar_reg_readable[SITAR_CACHE_SIZE] = {
+	[WCD9XXX_A_CHIP_CTL] = 1,
+	[WCD9XXX_A_CHIP_STATUS] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_0] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_1] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_2] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_3] = 1,
+	[WCD9XXX_A_CHIP_VERSION] = 1,
+	[WCD9XXX_A_SB_VERSION] = 1,
+	[WCD9XXX_A_SLAVE_ID_1] = 1,
+	[WCD9XXX_A_SLAVE_ID_2] = 1,
+	[WCD9XXX_A_SLAVE_ID_3] = 1,
+	[SITAR_A_PIN_CTL_OE0] = 1,
+	[SITAR_A_PIN_CTL_OE1] = 1,
+	[SITAR_A_PIN_CTL_DATA0] = 1,
+	[SITAR_A_PIN_CTL_DATA1] = 1,
+	[SITAR_A_HDRIVE_GENERIC] = 1,
+	[SITAR_A_HDRIVE_OVERRIDE] = 1,
+	[SITAR_A_ANA_CSR_WAIT_STATE] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL0] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL1] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL2] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL3] = 1,
+	[SITAR_A_QFUSE_CTL] = 1,
+	[SITAR_A_QFUSE_STATUS] = 1,
+	[SITAR_A_QFUSE_DATA_OUT0] = 1,
+	[SITAR_A_QFUSE_DATA_OUT1] = 1,
+	[SITAR_A_QFUSE_DATA_OUT2] = 1,
+	[SITAR_A_QFUSE_DATA_OUT3] = 1,
+	[SITAR_A_CDC_CTL] = 1,
+	[SITAR_A_LEAKAGE_CTL] = 1,
+	[SITAR_A_INTR_MODE] = 1,
+	[SITAR_A_INTR_MASK0] = 1,
+	[SITAR_A_INTR_MASK1] = 1,
+	[SITAR_A_INTR_MASK2] = 1,
+	[SITAR_A_INTR_STATUS0] = 1,
+	[SITAR_A_INTR_STATUS1] = 1,
+	[SITAR_A_INTR_STATUS2] = 1,
+	[SITAR_A_INTR_LEVEL0] = 1,
+	[SITAR_A_INTR_LEVEL1] = 1,
+	[SITAR_A_INTR_LEVEL2] = 1,
+	[SITAR_A_INTR_TEST0] = 1,
+	[SITAR_A_INTR_TEST1] = 1,
+	[SITAR_A_INTR_TEST2] = 1,
+	[SITAR_A_INTR_SET0] = 1,
+	[SITAR_A_INTR_SET1] = 1,
+	[SITAR_A_INTR_SET2] = 1,
+	[SITAR_A_CDC_TX_I2S_SCK_MODE] = 1,
+	[SITAR_A_CDC_TX_I2S_WS_MODE] = 1,
+	[SITAR_A_CDC_DMIC_DATA0_MODE] = 1,
+	[SITAR_A_CDC_DMIC_CLK0_MODE] = 1,
+	[SITAR_A_CDC_DMIC_DATA1_MODE] = 1,
+	[SITAR_A_CDC_DMIC_CLK1_MODE] = 1,
+	[SITAR_A_CDC_TX_I2S_SD0_MODE] = 1,
+	[SITAR_A_CDC_INTR_MODE] = 1,
+	[SITAR_A_CDC_RX_I2S_SD0_MODE] = 1,
+	[SITAR_A_CDC_RX_I2S_SD1_MODE] = 1,
+	[SITAR_A_BIAS_REF_CTL] = 1,
+	[SITAR_A_BIAS_CENTRAL_BG_CTL] = 1,
+	[SITAR_A_BIAS_PRECHRG_CTL] = 1,
+	[SITAR_A_BIAS_CURR_CTL_1] = 1,
+	[SITAR_A_BIAS_CURR_CTL_2] = 1,
+	[SITAR_A_BIAS_OSC_BG_CTL] = 1,
+	[SITAR_A_CLK_BUFF_EN1] = 1,
+	[SITAR_A_CLK_BUFF_EN2] = 1,
+	[SITAR_A_LDO_H_MODE_1] = 1,
+	[SITAR_A_LDO_H_MODE_2] = 1,
+	[SITAR_A_LDO_H_LOOP_CTL] = 1,
+	[SITAR_A_LDO_H_COMP_1] = 1,
+	[SITAR_A_LDO_H_COMP_2] = 1,
+	[SITAR_A_LDO_H_BIAS_1] = 1,
+	[SITAR_A_LDO_H_BIAS_2] = 1,
+	[SITAR_A_LDO_H_BIAS_3] = 1,
+	[SITAR_A_MICB_CFILT_1_CTL] = 1,
+	[SITAR_A_MICB_CFILT_1_VAL] = 1,
+	[SITAR_A_MICB_CFILT_1_PRECHRG] = 1,
+	[SITAR_A_MICB_1_CTL] = 1,
+	[SITAR_A_MICB_1_INT_RBIAS] = 1,
+	[SITAR_A_MICB_1_MBHC] = 1,
+	[SITAR_A_MICB_CFILT_2_CTL] = 1,
+	[SITAR_A_MICB_CFILT_2_VAL] = 1,
+	[SITAR_A_MICB_CFILT_2_PRECHRG] = 1,
+	[SITAR_A_MICB_2_CTL] = 1,
+	[SITAR_A_MICB_2_INT_RBIAS] = 1,
+	[SITAR_A_MICB_2_MBHC] = 1,
+	[SITAR_A_TX_COM_BIAS] = 1,
+	[SITAR_A_MBHC_SCALING_MUX_1] = 1,
+	[SITAR_A_MBHC_SCALING_MUX_2] = 1,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_1] = 1,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_2] = 1,
+	[SITAR_A_TX_1_2_EN] = 1,
+	[SITAR_A_TX_1_2_TEST_EN] = 1,
+	[SITAR_A_TX_1_2_ADC_CH1] = 1,
+	[SITAR_A_TX_1_2_ADC_CH2] = 1,
+	[SITAR_A_TX_1_2_ATEST_REFCTRL] = 1,
+	[SITAR_A_TX_1_2_TEST_CTL] = 1,
+	[SITAR_A_TX_1_2_TEST_BLOCK_EN] = 1,
+	[SITAR_A_TX_1_2_TXFE_CLKDIV] = 1,
+	[SITAR_A_TX_1_2_SAR_ERR_CH1] = 1,
+	[SITAR_A_TX_1_2_SAR_ERR_CH2] = 1,
+	[SITAR_A_TX_3_EN] = 1,
+	[SITAR_A_TX_3_TEST_EN] = 1,
+	[SITAR_A_TX_3_ADC] = 1,
+	[SITAR_A_TX_3_MBHC_ATEST_REFCTRL] = 1,
+	[SITAR_A_TX_3_TEST_CTL] = 1,
+	[SITAR_A_TX_3_TEST_BLOCK_EN] = 1,
+	[SITAR_A_TX_3_TXFE_CKDIV] = 1,
+	[SITAR_A_TX_3_SAR_ERR] = 1,
+	[SITAR_A_TX_4_MBHC_EN] = 1,
+	[SITAR_A_TX_4_MBHC_ADC] = 1,
+	[SITAR_A_TX_4_MBHC_TEST_CTL] = 1,
+	[SITAR_A_TX_4_MBHC_SAR_ERR] = 1,
+	[SITAR_A_TX_4_TXFE_CLKDIV] = 1,
+	[SITAR_A_AUX_COM_CTL] = 1,
+	[SITAR_A_AUX_COM_ATEST] = 1,
+	[SITAR_A_AUX_L_EN] = 1,
+	[SITAR_A_AUX_L_GAIN] = 1,
+	[SITAR_A_AUX_L_PA_CONN] = 1,
+	[SITAR_A_AUX_L_PA_CONN_INV] = 1,
+	[SITAR_A_AUX_R_EN] = 1,
+	[SITAR_A_AUX_R_GAIN] = 1,
+	[SITAR_A_AUX_R_PA_CONN] = 1,
+	[SITAR_A_AUX_R_PA_CONN_INV] = 1,
+	[SITAR_A_CP_EN] = 1,
+	[SITAR_A_CP_CLK] = 1,
+	[SITAR_A_CP_STATIC] = 1,
+	[SITAR_A_CP_DCC1] = 1,
+	[SITAR_A_CP_DCC3] = 1,
+	[SITAR_A_CP_ATEST] = 1,
+	[SITAR_A_CP_DTEST] = 1,
+	[SITAR_A_RX_COM_TIMER_DIV] = 1,
+	[SITAR_A_RX_COM_OCP_CTL] = 1,
+	[SITAR_A_RX_COM_OCP_COUNT] = 1,
+	[SITAR_A_RX_COM_DAC_CTL] = 1,
+	[SITAR_A_RX_COM_BIAS] = 1,
+	[SITAR_A_RX_HPH_BIAS_PA] = 1,
+	[SITAR_A_RX_HPH_BIAS_LDO] = 1,
+	[SITAR_A_RX_HPH_BIAS_CNP] = 1,
+	[SITAR_A_RX_HPH_BIAS_WG] = 1,
+	[SITAR_A_RX_HPH_OCP_CTL] = 1,
+	[SITAR_A_RX_HPH_CNP_EN] = 1,
+	[SITAR_A_RX_HPH_CNP_WG_CTL] = 1,
+	[SITAR_A_RX_HPH_CNP_WG_TIME] = 1,
+	[SITAR_A_RX_HPH_L_GAIN] = 1,
+	[SITAR_A_RX_HPH_L_TEST] = 1,
+	[SITAR_A_RX_HPH_L_PA_CTL] = 1,
+	[SITAR_A_RX_HPH_L_DAC_CTL] = 1,
+	[SITAR_A_RX_HPH_L_ATEST] = 1,
+	[SITAR_A_RX_HPH_L_STATUS] = 1,
+	[SITAR_A_RX_HPH_R_GAIN] = 1,
+	[SITAR_A_RX_HPH_R_TEST] = 1,
+	[SITAR_A_RX_HPH_R_PA_CTL] = 1,
+	[SITAR_A_RX_HPH_R_DAC_CTL] = 1,
+	[SITAR_A_RX_HPH_R_ATEST] = 1,
+	[SITAR_A_RX_HPH_R_STATUS] = 1,
+	[SITAR_A_RX_EAR_BIAS_PA] = 1,
+	[SITAR_A_RX_EAR_BIAS_CMBUFF] = 1,
+	[SITAR_A_RX_EAR_EN] = 1,
+	[SITAR_A_RX_EAR_GAIN] = 1,
+	[SITAR_A_RX_EAR_CMBUFF] = 1,
+	[SITAR_A_RX_EAR_ICTL] = 1,
+	[SITAR_A_RX_EAR_CCOMP] = 1,
+	[SITAR_A_RX_EAR_VCM] = 1,
+	[SITAR_A_RX_EAR_CNP] = 1,
+	[SITAR_A_RX_EAR_ATEST] = 1,
+	[SITAR_A_RX_EAR_STATUS] = 1,
+	[SITAR_A_RX_LINE_BIAS_PA] = 1,
+	[SITAR_A_RX_LINE_BIAS_LDO] = 1,
+	[SITAR_A_RX_LINE_BIAS_CNP1] = 1,
+	[SITAR_A_RX_LINE_COM] = 1,
+	[SITAR_A_RX_LINE_CNP_EN] = 1,
+	[SITAR_A_RX_LINE_CNP_WG_CTL] = 1,
+	[SITAR_A_RX_LINE_CNP_WG_TIME] = 1,
+	[SITAR_A_RX_LINE_1_GAIN] = 1,
+	[SITAR_A_RX_LINE_1_TEST] = 1,
+	[SITAR_A_RX_LINE_1_DAC_CTL] = 1,
+	[SITAR_A_RX_LINE_1_STATUS] = 1,
+	[SITAR_A_RX_LINE_2_GAIN] = 1,
+	[SITAR_A_RX_LINE_2_TEST] = 1,
+	[SITAR_A_RX_LINE_2_DAC_CTL] = 1,
+	[SITAR_A_RX_LINE_2_STATUS] = 1,
+	[SITAR_A_RX_LINE_BIAS_CNP2] = 1,
+	[SITAR_A_RX_LINE_OCP_CTL] = 1,
+	[SITAR_A_RX_LINE_1_PA_CTL] = 1,
+	[SITAR_A_RX_LINE_2_PA_CTL] = 1,
+	[SITAR_A_RX_LINE_CNP_DBG] = 1,
+	[SITAR_A_MBHC_HPH] = 1,
+	[SITAR_A_RC_OSC_FREQ] = 1,
+	[SITAR_A_RC_OSC_TEST] = 1,
+	[SITAR_A_RC_OSC_STATUS] = 1,
+	[SITAR_A_RC_OSC_TUNER] = 1,
+	[SITAR_A_CDC_ANC1_CTL] = 1,
+	[SITAR_A_CDC_ANC1_SHIFT] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B1_CTL] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B2_CTL] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B3_CTL] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B4_CTL] = 1,
+	[SITAR_A_CDC_ANC1_LPF_B1_CTL] = 1,
+	[SITAR_A_CDC_ANC1_LPF_B2_CTL] = 1,
+	[SITAR_A_CDC_ANC1_LPF_B3_CTL] = 1,
+	[SITAR_A_CDC_ANC1_SPARE] = 1,
+	[SITAR_A_CDC_ANC1_SMLPF_CTL] = 1,
+	[SITAR_A_CDC_ANC1_DCFLT_CTL] = 1,
+	[SITAR_A_CDC_TX1_VOL_CTL_TIMER] = 1,
+	[SITAR_A_CDC_TX1_VOL_CTL_GAIN] = 1,
+	[SITAR_A_CDC_TX1_VOL_CTL_CFG] = 1,
+	[SITAR_A_CDC_TX1_MUX_CTL] = 1,
+	[SITAR_A_CDC_TX1_CLK_FS_CTL] = 1,
+	[SITAR_A_CDC_TX1_DMIC_CTL] = 1,
+	[SITAR_A_CDC_SRC1_PDA_CFG] = 1,
+	[SITAR_A_CDC_SRC1_FS_CTL] = 1,
+	[SITAR_A_CDC_RX1_B1_CTL] = 1,
+	[SITAR_A_CDC_RX1_B2_CTL] = 1,
+	[SITAR_A_CDC_RX1_B3_CTL] = 1,
+	[SITAR_A_CDC_RX1_B4_CTL] = 1,
+	[SITAR_A_CDC_RX1_B5_CTL] = 1,
+	[SITAR_A_CDC_RX1_B6_CTL] = 1,
+	[SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
+	[SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
+	[SITAR_A_CDC_CLK_ANC_RESET_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_RESET_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_RESET_B2_CTL] = 1,
+	[SITAR_A_CDC_CLK_DMIC_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_I2S_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_I2S_CTL] = 1,
+	[SITAR_A_CDC_CLK_OTHR_RESET_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
+	[SITAR_A_CDC_CLK_OTHR_CTL] = 1,
+	[SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL] = 1,
+	[SITAR_A_CDC_CLK_ANC_CLK_EN_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_B1_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_B2_CTL] = 1,
+	[SITAR_A_CDC_CLK_MCLK_CTL] = 1,
+	[SITAR_A_CDC_CLK_PDM_CTL] = 1,
+	[SITAR_A_CDC_CLK_SD_CTL] = 1,
+	[SITAR_A_CDC_CLK_LP_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL] = 1,
+	[SITAR_A_CDC_CLSG_GAIN_THRESH_CTL] = 1,
+	[SITAR_A_CDC_CLSG_TIMER_B1_CFG] = 1,
+	[SITAR_A_CDC_CLSG_TIMER_B2_CFG] = 1,
+	[SITAR_A_CDC_CLSG_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B1_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B2_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B3_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B4_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B5_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B6_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B7_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B8_CTL] = 1,
+	[SITAR_A_CDC_IIR1_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B1_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B2_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B3_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B4_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B5_CTL] = 1,
+	[SITAR_A_CDC_TOP_GAIN_UPDATE] = 1,
+	[SITAR_A_CDC_TOP_RDAC_DOUT_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B1_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B2_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B3_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B4_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B5_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B6_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B7_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B1_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B2_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B3_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B4_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B5_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B6_CTL] = 1,
+	[SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
+	[SITAR_A_CDC_COMP1_FS_CFG] = 1,
+	[SITAR_A_CDC_CONN_RX1_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX1_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX1_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX2_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX2_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX2_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX3_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX3_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX3_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_ANC_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_ANC_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B4_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B4_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC1_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC1_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC2_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC2_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B4_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B5_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX_SB_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX_SB_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_CLSG_CTL] = 1,
+	[SITAR_A_CDC_CONN_SPARE] = 1,
+	[SITAR_A_CDC_MBHC_EN_CTL] = 1,
+	[SITAR_A_CDC_MBHC_FIR_B1_CFG] = 1,
+	[SITAR_A_CDC_MBHC_FIR_B2_CFG] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B1_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B2_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B3_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B4_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B5_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B6_CTL] = 1,
+	[SITAR_A_CDC_MBHC_B1_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B2_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B3_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B4_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B5_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B1_CTL] = 1,
+	[SITAR_A_CDC_MBHC_B2_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B1_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B2_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B3_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B4_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B5_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B6_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B7_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B8_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B9_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B10_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B11_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B12_CTL] = 1,
+	[SITAR_A_CDC_MBHC_CLK_CTL] = 1,
+	[SITAR_A_CDC_MBHC_INT_CTL] = 1,
+	[SITAR_A_CDC_MBHC_DEBUG_CTL] = 1,
+	[SITAR_A_CDC_MBHC_SPARE] = 1,
+};
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
new file mode 100644
index 0000000..c9c8e25
--- /dev/null
+++ b/sound/soc/codecs/wcd9304.c
@@ -0,0 +1,3541 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include "wcd9304.h"
+
+#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
+			SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
+
+#define NUM_DECIMATORS 4
+#define NUM_INTERPOLATORS 3
+#define BITS_PER_REG 8
+#define AIF1_PB 1
+#define AIF1_CAP 2
+#define NUM_CODEC_DAIS 2
+
+struct sitar_codec_dai_data {
+	u32 rate;
+	u32 *ch_num;
+	u32 ch_act;
+	u32 ch_tot;
+};
+#define SITAR_CFILT_FAST_MODE 0x00
+#define SITAR_CFILT_SLOW_MODE 0x40
+
+
+#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
+
+#define SITAR_I2S_MASTER_MODE_MASK 0x08
+
+#define SITAR_OCP_ATTEMPT 1
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver sitar_dai[];
+static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event);
+static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event);
+
+enum sitar_bandgap_type {
+	SITAR_BANDGAP_OFF = 0,
+	SITAR_BANDGAP_AUDIO_MODE,
+	SITAR_BANDGAP_MBHC_MODE,
+};
+
+struct mbhc_micbias_regs {
+	u16 cfilt_val;
+	u16 cfilt_ctl;
+	u16 mbhc_reg;
+	u16 int_rbias;
+	u16 ctl_reg;
+	u8 cfilt_sel;
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR1 = 0,
+	IIR2,
+	IIR_MAX,
+};
+/* Codec supports 5 bands */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_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. */
+enum sitar_priv_ack_flags {
+	SITAR_HPHL_PA_OFF_ACK = 0,
+	SITAR_HPHR_PA_OFF_ACK,
+	SITAR_HPHL_DAC_OFF_ACK,
+	SITAR_HPHR_DAC_OFF_ACK
+};
+
+struct sitar_priv {
+	struct snd_soc_codec *codec;
+	u32 adc_count;
+	u32 cfilt1_cnt;
+	u32 cfilt2_cnt;
+	u32 cfilt3_cnt;
+	u32 rx_bias_count;
+	enum sitar_bandgap_type bandgap_type;
+	bool mclk_enabled;
+	bool clock_active;
+	bool config_mode_active;
+	bool mbhc_polling_active;
+	bool fake_insert_context;
+	int buttons_pressed;
+
+	struct sitar_mbhc_calibration *calibration;
+
+	struct snd_soc_jack *headset_jack;
+	struct snd_soc_jack *button_jack;
+
+	struct wcd9xxx_pdata *pdata;
+	u32 anc_slot;
+
+	bool no_mic_headset_override;
+	/* Delayed work to report long button press */
+	struct delayed_work btn0_dwork;
+
+	struct mbhc_micbias_regs mbhc_bias_regs;
+	u8 cfilt_k_value;
+	bool mbhc_micbias_switched;
+
+	/* track PA/DAC state */
+	unsigned long hph_pa_dac_state;
+
+	/*track sitar interface type*/
+	u8 intf_type;
+
+	u32 hph_status; /* track headhpone status */
+	/* define separate work for left and right headphone OCP to avoid
+	 * additional checking on which OCP event to report so no locking
+	 * to ensure synchronization is required
+	 */
+	struct work_struct hphlocp_work; /* reporting left hph ocp off */
+	struct work_struct hphrocp_work; /* reporting right hph ocp off */
+
+	/* pm_cnt holds number of sleep lock holders + 1
+	 * so if pm_cnt is 1 system is sleep-able. */
+	atomic_t pm_cnt;
+	wait_queue_head_t pm_wq;
+
+	u8 hphlocp_cnt; /* headphone left ocp retry */
+	u8 hphrocp_cnt; /* headphone right ocp retry */
+	/* num of slim ports required */
+	struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
+};
+
+#ifdef CONFIG_DEBUG_FS
+struct sitar_priv *debug_sitar_priv;
+#endif
+
+
+static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
+
+	ear_pa_gain = ear_pa_gain >> 5;
+
+	if (ear_pa_gain == 0x00) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (ear_pa_gain == 0x04) {
+		ucontrol->value.integer.value[0] = 1;
+	} else  {
+		pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+				__func__, ear_pa_gain);
+		return -EINVAL;
+	}
+
+	pr_err("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+
+	return 0;
+}
+
+static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s: ucontrol->value.integer.value[0]  = %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		ear_pa_gain = 0x00;
+		break;
+	case 1:
+		ear_pa_gain = 0x80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, SITAR_A_RX_EAR_GAIN, ear_pa_gain);
+	return 0;
+}
+
+static int sitar_get_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+		(1 << band_idx);
+
+	pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int sitar_put_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	/* Mask first 5 bits, 6-8 are reserved */
+	snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
+		(1 << band_idx), (value << band_idx));
+
+	pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx, value);
+	return 0;
+}
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				int coeff_idx)
+{
+	/* Address does not automatically update if reading */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		0x1F, band_idx * BAND_MAX + coeff_idx);
+
+	/* Mask bits top 2 bits since they are reserved */
+	return ((snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
+		(snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
+		(snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
+		(snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
+		0x3FFFFFFF;
+}
+
+static int sitar_get_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+	ucontrol->value.integer.value[1] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+	ucontrol->value.integer.value[2] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+	ucontrol->value.integer.value[3] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+	ucontrol->value.integer.value[4] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+	pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[1],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[2],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[3],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[4]);
+	return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				int coeff_idx, uint32_t value)
+{
+	/* Mask top 3 bits, 6-8 are reserved */
+	/* Update address manually each time */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		0x1F, band_idx * BAND_MAX + coeff_idx);
+
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+		0x3F, (value >> 24) & 0x3F);
+
+	/* Isolate 8bits at a time */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
+		0xFF, (value >> 16) & 0xFF);
+
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
+		0xFF, (value >> 8) & 0xFF);
+
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
+		0xFF, value & 0xFF);
+}
+
+static int sitar_put_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+				ucontrol->value.integer.value[0]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+				ucontrol->value.integer.value[1]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+				ucontrol->value.integer.value[2]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+				ucontrol->value.integer.value[3]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+				ucontrol->value.integer.value[4]);
+
+	pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+	return 0;
+}
+
+static const char *sitar_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
+static const struct soc_enum sitar_ear_pa_gain_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, sitar_ear_pa_gain_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char *cf_text[] = {
+	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_dec1_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_rxmix1_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+
+static const struct snd_kcontrol_new sitar_snd_controls[] = {
+
+	SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
+		sitar_pa_gain_get, sitar_pa_gain_put),
+
+	SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
+		line_gain),
+	SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
+		line_gain),
+
+	SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
+		line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
+		line_gain),
+
+	SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
+		-84, 40, digital_gain),
+
+	SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+
+	SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
+	SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
+
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+
+	SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
+
+	SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
+
+	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+
+	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+};
+
+static const char *rx_mix1_text[] = {
+	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
+		"RX5"
+};
+
+static const char *rx_dac1_text[] = {
+	"ZERO", "RX1", "RX2"
+};
+
+static const char *rx_dac2_text[] = {
+	"ZERO", "RX1",
+};
+
+static const char *rx_dac3_text[] = {
+	"ZERO", "RX1", "RX1_INV", "RX2"
+};
+
+static const char *rx_dac4_text[] = {
+	"ZERO", "ON"
+};
+
+static const char *sb_tx1_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC1"
+};
+
+static const char *sb_tx2_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC2"
+};
+
+static const char *sb_tx3_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC3"
+};
+
+static const char *sb_tx5_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC5"
+};
+
+static const char *dec1_mux_text[] = {
+	"ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANCFB1",
+};
+
+static const char *dec2_mux_text[] = {
+	"ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANCFB2",
+};
+
+static const char *dec3_mux_text[] = {
+	"ZERO", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3", "MBADC",
+};
+
+static const char *dec4_mux_text[] = {
+	"ZERO", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3",
+};
+
+static const char *iir1_inp1_text[] = {
+	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
+	"ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
+};
+
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx_dac1_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
+
+static const struct soc_enum rx_dac2_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
+
+static const struct soc_enum rx_dac3_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
+
+static const struct soc_enum rx_dac4_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
+
+static const struct soc_enum sb_tx3_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
+
+static const struct soc_enum sb_tx2_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
+
+static const struct soc_enum sb_tx1_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
+
+static const struct soc_enum dec1_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 2, 8, dec2_mux_text);
+
+static const struct soc_enum dec3_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 4, 8, dec3_mux_text);
+
+static const struct soc_enum dec4_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 6, 8, dec4_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_dac1_mux =
+	SOC_DAPM_ENUM("RX1 DAC Mux", rx_dac1_enum);
+
+static const struct snd_kcontrol_new rx_dac2_mux =
+	SOC_DAPM_ENUM("RX2 DAC Mux", rx_dac2_enum);
+
+static const struct snd_kcontrol_new rx_dac3_mux =
+	SOC_DAPM_ENUM("RX3 DAC Mux", rx_dac3_enum);
+
+static const struct snd_kcontrol_new rx_dac4_mux =
+	SOC_DAPM_ENUM("RX4 DAC Mux", rx_dac4_enum);
+
+static const struct snd_kcontrol_new sb_tx5_mux =
+	SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx3_mux =
+	SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx2_mux =
+	SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx1_mux =
+	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+
+static const struct snd_kcontrol_new dec1_mux =
+	SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+	SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new dec3_mux =
+	SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+
+static const struct snd_kcontrol_new dec4_mux =
+	SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new dac1_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new hphl_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SITAR_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
+};
+
+static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
+	int enable)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	pr_err("%s %d\n", __func__, enable);
+
+	if (enable) {
+		sitar->adc_count++;
+		snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
+
+	} else {
+		sitar->adc_count--;
+		if (!sitar->adc_count) {
+			if (!sitar->mbhc_polling_active)
+				snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS,
+					0xE0, 0x0);
+		}
+	}
+}
+
+static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 adc_reg;
+
+	pr_err("%s %d\n", __func__, event);
+
+	if (w->reg == SITAR_A_TX_1_2_EN)
+		adc_reg = SITAR_A_TX_1_2_TEST_CTL;
+	else {
+		pr_err("%s: Error, invalid adc register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		sitar_codec_enable_adc_block(codec, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
+			1 << w->shift);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, adc_reg, 0x08, 0x08);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		sitar_codec_enable_adc_block(codec, 0);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 lineout_gain_reg;
+
+	pr_err("%s %d %s\n", __func__, event, w->name);
+
+	switch (w->shift) {
+	case 0:
+		lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
+		break;
+	case 1:
+		lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
+		break;
+	default:
+		pr_err("%s: Error, incorrect lineout register value\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		pr_err("%s: sleeping 16 ms after %s PA turn on\n",
+				__func__, w->name);
+		usleep_range(16000, 16000);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
+	u8 dmic_clk_sel, dmic_clk_en;
+	unsigned int dmic;
+	int ret;
+
+	ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
+	if (ret < 0) {
+		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 1:
+	case 2:
+		dmic_clk_sel = 0x02;
+		dmic_clk_en = 0x01;
+		break;
+	case 3:
+	case 4:
+		dmic_clk_sel = 0x08;
+		dmic_clk_en = 0x04;
+		break;
+
+		break;
+
+	default:
+		pr_err("%s: Invalid DMIC Selection\n", __func__);
+		return -EINVAL;
+	}
+
+	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
+	tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
+
+	pr_err("%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
+
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+				dmic_clk_sel, dmic_clk_sel);
+
+		snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
+
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+				dmic_clk_en, dmic_clk_en);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+				dmic_clk_en, 0);
+		break;
+	}
+	return 0;
+}
+
+
+static void sitar_codec_disable_button_presses(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
+}
+
+static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+	if (!sitar->no_mic_headset_override) {
+		wcd9xxx_enable_irq(codec->control_data,
+				SITAR_IRQ_MBHC_POTENTIAL);
+		wcd9xxx_enable_irq(codec->control_data,
+				SITAR_IRQ_MBHC_RELEASE);
+	} else {
+		sitar_codec_disable_button_presses(codec);
+	}
+}
+
+static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+	if (!sitar->no_mic_headset_override) {
+		wcd9xxx_disable_irq(codec->control_data,
+			SITAR_IRQ_MBHC_POTENTIAL);
+		wcd9xxx_disable_irq(codec->control_data,
+			SITAR_IRQ_MBHC_RELEASE);
+	}
+}
+
+static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
+		int mode)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u8 reg_mode_val, cur_mode_val;
+	bool mbhc_was_polling = false;
+
+	if (mode)
+		reg_mode_val = SITAR_CFILT_FAST_MODE;
+	else
+		reg_mode_val = SITAR_CFILT_SLOW_MODE;
+
+	cur_mode_val = snd_soc_read(codec,
+			sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
+
+	if (cur_mode_val != reg_mode_val) {
+		if (sitar->mbhc_polling_active) {
+			sitar_codec_pause_hs_polling(codec);
+			mbhc_was_polling = true;
+		}
+		snd_soc_update_bits(codec,
+			sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
+		if (mbhc_was_polling)
+			sitar_codec_start_hs_polling(codec);
+		pr_err("%s: CFILT mode change (%x to %x)\n", __func__,
+			cur_mode_val, reg_mode_val);
+	} else {
+		pr_err("%s: CFILT Value is already %x\n",
+			__func__, cur_mode_val);
+	}
+}
+
+static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
+					  u8 cfilt_sel, int inc)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u32 *cfilt_cnt_ptr = NULL;
+	u16 micb_cfilt_reg;
+
+	switch (cfilt_sel) {
+	case SITAR_CFILT1_SEL:
+		cfilt_cnt_ptr = &sitar->cfilt1_cnt;
+		micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
+		break;
+	case SITAR_CFILT2_SEL:
+		cfilt_cnt_ptr = &sitar->cfilt2_cnt;
+		micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
+		break;
+	default:
+		return; /* should not happen */
+	}
+
+	if (inc) {
+		if (!(*cfilt_cnt_ptr)++) {
+			/* Switch CFILT to slow mode if MBHC CFILT being used */
+			if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
+				sitar_codec_switch_cfilt_mode(codec, 0);
+
+			snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
+		}
+	} else {
+		/* check if count not zero, decrement
+		* then check if zero, go ahead disable cfilter
+		*/
+		if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
+			snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
+
+			/* Switch CFILT to fast mode if MBHC CFILT being used */
+			if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
+				sitar_codec_switch_cfilt_mode(codec, 1);
+		}
+	}
+}
+
+static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
+{
+	int rc = -EINVAL;
+	unsigned min_mv, max_mv;
+
+	switch (ldoh_v) {
+	case SITAR_LDOH_1P95_V:
+		min_mv = 160;
+		max_mv = 1800;
+		break;
+	case SITAR_LDOH_2P35_V:
+		min_mv = 200;
+		max_mv = 2200;
+		break;
+	case SITAR_LDOH_2P75_V:
+		min_mv = 240;
+		max_mv = 2600;
+		break;
+	case SITAR_LDOH_2P85_V:
+		min_mv = 250;
+		max_mv = 2700;
+		break;
+	default:
+		goto done;
+	}
+
+	if (cfilt_mv < min_mv || cfilt_mv > max_mv)
+		goto done;
+
+	for (rc = 4; rc <= 44; rc++) {
+		min_mv = max_mv * (rc) / 44;
+		if (min_mv >= cfilt_mv) {
+			rc -= 4;
+			break;
+		}
+	}
+done:
+	return rc;
+}
+
+static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
+{
+	u8 hph_reg_val = 0;
+	hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
+
+	return (hph_reg_val & 0x30) ? true : false;
+}
+
+static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
+{
+	u8 hph_reg_val = 0;
+	if (left)
+		hph_reg_val = snd_soc_read(codec,
+					  SITAR_A_RX_HPH_L_DAC_CTL);
+	else
+		hph_reg_val = snd_soc_read(codec,
+					  SITAR_A_RX_HPH_R_DAC_CTL);
+
+	return (hph_reg_val & 0xC0) ? true : false;
+}
+
+static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
+	int vddio_switch)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	int cfilt_k_val;
+	bool mbhc_was_polling =  false;
+
+	switch (vddio_switch) {
+	case 1:
+		if (sitar->mbhc_polling_active) {
+
+			sitar_codec_pause_hs_polling(codec);
+			/* Enable Mic Bias switch to VDDIO */
+			sitar->cfilt_k_value = snd_soc_read(codec,
+					sitar->mbhc_bias_regs.cfilt_val);
+			cfilt_k_val = sitar_find_k_value(
+					sitar->pdata->micbias.ldoh_v, 1800);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.cfilt_val,
+				0xFC, (cfilt_k_val << 2));
+
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x80, 0x80);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x10, 0x00);
+			sitar_codec_start_hs_polling(codec);
+
+			sitar->mbhc_micbias_switched = true;
+			pr_err("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
+				__func__);
+		}
+		break;
+
+	case 0:
+		if (sitar->mbhc_micbias_switched) {
+			if (sitar->mbhc_polling_active) {
+				sitar_codec_pause_hs_polling(codec);
+				mbhc_was_polling = true;
+			}
+			/* Disable Mic Bias switch to VDDIO */
+			if (sitar->cfilt_k_value != 0)
+				snd_soc_update_bits(codec,
+					sitar->mbhc_bias_regs.cfilt_val, 0XFC,
+					sitar->cfilt_k_value);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x80, 0x00);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x10, 0x00);
+
+			if (mbhc_was_polling)
+				sitar_codec_start_hs_polling(codec);
+
+			sitar->mbhc_micbias_switched = false;
+			pr_err("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
+				__func__);
+		}
+		break;
+	}
+}
+
+static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u16 micb_int_reg;
+	int micb_line;
+	u8 cfilt_sel_val = 0;
+	char *internal1_text = "Internal1";
+	char *internal2_text = "Internal2";
+
+	pr_err("%s %d\n", __func__, event);
+	switch (w->reg) {
+	case SITAR_A_MICB_1_CTL:
+		micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
+		cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
+		micb_line = SITAR_MICBIAS1;
+		break;
+	case SITAR_A_MICB_2_CTL:
+		micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
+		cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
+		micb_line = SITAR_MICBIAS2;
+		break;
+	default:
+		pr_err("%s: Error, invalid micbias register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Decide whether to switch the micbias for MBHC */
+		if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
+				&& sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+
+		snd_soc_update_bits(codec, w->reg, 0x1E, 0x0A);
+		sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
+
+		if (strnstr(w->name, internal1_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
+		else if (strnstr(w->name, internal2_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (sitar->mbhc_polling_active &&
+			(sitar->calibration->bias == micb_line)) {
+			sitar_codec_pause_hs_polling(codec);
+			sitar_codec_start_hs_polling(codec);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+
+		if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
+				&& sitar_is_hph_pa_on(codec))
+			sitar_codec_switch_micbias(codec, 1);
+
+		if (strnstr(w->name, internal1_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
+		else if (strnstr(w->name, internal2_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
+		sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 dec_reset_reg;
+
+	pr_err("%s %d\n", __func__, event);
+
+	if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
+		dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
+	else {
+		pr_err("%s: Error, incorrect dec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+			1 << w->shift);
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %d %s\n", __func__, event, w->name);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
+			1 << w->shift, 1 << w->shift);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
+			1 << w->shift, 0x0);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(1000, 1000);
+		pr_debug("LDO_H\n");
+		break;
+	}
+	return 0;
+}
+
+static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32  enable)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		sitar->rx_bias_count++;
+		if (sitar->rx_bias_count == 1)
+			snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
+				0x80, 0x80);
+	} else {
+		sitar->rx_bias_count--;
+		if (!sitar->rx_bias_count)
+			snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
+				0x80, 0x00);
+	}
+}
+
+static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		sitar_enable_rx_bias(codec, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		sitar_enable_rx_bias(codec, 0);
+		break;
+	}
+	return 0;
+}
+static int sitar_hphr_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
+				     struct snd_soc_jack *jack, int status,
+				     int mask)
+{
+	/* XXX: wake_lock_timeout()? */
+	snd_soc_jack_report(jack, status, mask);
+}
+
+static void hphocp_off_report(struct sitar_priv *sitar,
+	u32 jack_status, int irq)
+{
+	struct snd_soc_codec *codec;
+
+	if (sitar) {
+		pr_info("%s: clear ocp status %x\n", __func__, jack_status);
+		codec = sitar->codec;
+		sitar->hph_status &= ~jack_status;
+		if (sitar->headset_jack)
+			sitar_snd_soc_jack_report(sitar, sitar->headset_jack,
+						 sitar->hph_status,
+						 SITAR_JACK_MASK);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+		0x00);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+		0x10);
+		/* reset retry counter as PA is turned off signifying
+		* start of new OCP detection session
+		*/
+		if (SITAR_IRQ_HPH_PA_OCPL_FAULT)
+			sitar->hphlocp_cnt = 0;
+		else
+			sitar->hphrocp_cnt = 0;
+		wcd9xxx_enable_irq(codec->control_data, irq);
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+}
+
+static void hphlocp_off_report(struct work_struct *work)
+{
+	struct sitar_priv *sitar = container_of(work, struct sitar_priv,
+		hphlocp_work);
+	hphocp_off_report(sitar, SND_JACK_OC_HPHL, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+}
+
+static void hphrocp_off_report(struct work_struct *work)
+{
+	struct sitar_priv *sitar = container_of(work, struct sitar_priv,
+		hphrocp_work);
+	hphocp_off_report(sitar, SND_JACK_OC_HPHR, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+}
+
+static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u8 mbhc_micb_ctl_val;
+	pr_err("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mbhc_micb_ctl_val = snd_soc_read(codec,
+				sitar->mbhc_bias_regs.ctl_reg);
+
+		if (!(mbhc_micb_ctl_val & 0x80)
+				&& !sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 1);
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* schedule work is required because at the time HPH PA DAPM
+		* event callback is called by DAPM framework, CODEC dapm mutex
+		* would have been locked while snd_soc_jack_report also
+		* attempts to acquire same lock.
+		*/
+		if (w->shift == 5) {
+			clear_bit(SITAR_HPHL_PA_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			if (sitar->hph_status & SND_JACK_OC_HPHL)
+				schedule_work(&sitar->hphlocp_work);
+		} else if (w->shift == 4) {
+			clear_bit(SITAR_HPHR_PA_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			if (sitar->hph_status & SND_JACK_OC_HPHR)
+				schedule_work(&sitar->hphrocp_work);
+		}
+
+		if (sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+
+		pr_err("%s: sleep 10 ms after %s PA disable.\n", __func__,
+				w->name);
+		usleep_range(10000, 10000);
+
+		break;
+	}
+	return 0;
+}
+
+static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
+		struct mbhc_micbias_regs *micbias_regs)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+	unsigned int cfilt;
+
+	switch (calibration->bias) {
+	case SITAR_MICBIAS1:
+		cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
+		micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
+		micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
+		micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
+		break;
+	case SITAR_MICBIAS2:
+		cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
+		micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
+		micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
+		micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
+		break;
+	default:
+		/* Should never reach here */
+		pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
+		return;
+	}
+
+	micbias_regs->cfilt_sel = cfilt;
+
+	switch (cfilt) {
+	case SITAR_CFILT1_SEL:
+		micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
+		micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
+		break;
+	case SITAR_CFILT2_SEL:
+		micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
+		micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
+		break;
+	}
+}
+
+static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
+			0x01);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
+		usleep_range(200, 200);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
+			0x10);
+		usleep_range(20, 20);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
+			0x00);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
+	4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
+	0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
+	/*RX stuff */
+	SND_SOC_DAPM_OUTPUT("EAR"),
+
+	SND_SOC_DAPM_PGA("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
+		ARRAY_SIZE(dac1_switch)),
+	SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
+	SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM RX5", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Headphone */
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+		sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("HPHL DAC", SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
+		hphl_switch, ARRAY_SIZE(hphl_switch)),
+
+	SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+		sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
+		sitar_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Speaker */
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
+			0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
+			0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+		0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+		0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+		0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac1_mux),
+	SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac2_mux),
+	SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac3_mux),
+	SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac4_mux),
+
+	SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp2_mux),
+
+	SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
+		sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
+		sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+	/* TX */
+	SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+		0),
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
+		sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
+		sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC1 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+		&dec1_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
+	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
+	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
+
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimtx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimtx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimtx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+		&dec2_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+		&dec3_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+		&dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* Sidetone */
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR PA"},
+	{"EAR PA", "NULL", "DAC1"},
+	{"DAC1", "Switch", "DAC1 MUX"},
+	{"DAC1", NULL, "CP"},
+	{"DAC1", NULL, "EAR DRIVER"},
+
+	{"LINEOUT1", NULL, "CP"},
+	{"LINEOUT2", NULL, "CP"},
+
+	{"LINEOUT2", NULL, "LINEOUT2 PA"},
+	{"LINEOUT2 PA", "NULL", "DAC3 MUX"},
+
+	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+	{"LINEOUT1 PA", "NULL", "DAC2 MUX"},
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL"},
+	{"HEADPHONE", NULL, "HPHR"},
+
+	{"HPHL", NULL, "HPHL DAC"},
+	{"HPHL DAC", NULL, "DAC4 MUX"},
+	{"HPHR", NULL, "HPHR DAC"},
+	{"HPHL DAC", NULL, "RX3 MIX1"},
+
+	{"DAC1 MUX", "RX1", "RX1 CHAIN"},
+	{"DAC2 MUX", "RX1", "RX1 CHAIN"},
+	{"DAC3 MUX", "RX1", "RX1 CHAIN"},
+	{"DAC3 MUX", "RX1_INV", "RX1 CHAIN"},
+	{"DAC3 MUX", "RX2", "RX2 MIX1"},
+	{"DAC4 MUX", "ON", "RX2 MIX1"},
+
+	{"RX1 CHAIN", NULL, "RX1 MIX1"},
+
+	{"CP", NULL, "RX_BIAS"},
+
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+
+	/* SLIMBUS Connections */
+
+	/* Slimbus port 5 is non functional in Sitar 1.0 */
+	{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
+
+
+	/* TX */
+	{"SLIM TX1", NULL, "SLIM TX1 MUX"},
+	{"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
+
+	{"SLIM TX2", NULL, "SLIM TX2 MUX"},
+	{"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
+
+	{"SLIM TX1", NULL, "SLIM TX1 MUX"},
+	{"SLIM TX2", NULL, "SLIM TX2 MUX"},
+	{"SLIM TX3", NULL, "SLIM TX3 MUX"},
+
+	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
+
+	/* Decimator Inputs */
+	{"DEC1 MUX", "DMIC1", "DMIC1"},
+	{"DEC1 MUX", "DMIC4", "DMIC4"},
+	{"DEC1 MUX", "ADC1", "ADC1"},
+	{"DEC1 MUX", "ADC2", "ADC2"},
+
+	{"DEC2 MUX", "DMIC2", "DMIC2"},
+	{"DEC2 MUX", "DMIC3", "DMIC3"},
+	{"DEC2 MUX", "ADC1", "ADC1"},
+	{"DEC2 MUX", "ADC2", "ADC2"},
+
+	{"DEC3 MUX", "DMIC3", "DMIC3"},
+	{"DEC3 MUX", "ADC1", "ADC1"},
+	{"DEC3 MUX", "ADC2", "ADC2"},
+	{"DEC3 MUX", "DMIC2", "DMIC2"},
+	{"DEC3 MUX", "DMIC3", "DMIC4"},
+
+	{"DEC4 MUX", "DMIC4", "DMIC4"},
+	{"DEC4 MUX", "ADC1", "ADC1"},
+	{"DEC4 MUX", "ADC2", "ADC2"},
+	{"DEC4 MUX", "DMIC3", "DMIC3"},
+	{"DEC4 MUX", "DMIC2", "DMIC2"},
+	{"DEC4 MUX", "DMIC1", "DMIC1"},
+
+	/* ADC Connections */
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2", NULL, "AMIC2"},
+
+	/* IIR */
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
+	{"MIC BIAS1 External", NULL, "LDO_H"},
+	{"MIC BIAS2 Internal1", NULL, "LDO_H"},
+	{"MIC BIAS2 External", NULL, "LDO_H"},
+};
+
+static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	return sitar_reg_readable[reg];
+}
+
+static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	/* Registers lower than 0x100 are top level registers which can be
+	* written by the Sitar core driver.
+	*/
+
+	if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
+		return 1;
+
+	/* IIR Coeff registers are not cacheable */
+	if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
+		(reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
+		return 1;
+
+	return 0;
+}
+
+#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	int ret;
+
+	BUG_ON(reg > SITAR_MAX_REGISTER);
+
+	if (!sitar_volatile(codec, reg)) {
+		ret = snd_soc_cache_write(codec, reg, value);
+		if (ret != 0)
+			dev_err(codec->dev, "Cache write to %x failed: %d\n",
+				reg, ret);
+	}
+
+	return wcd9xxx_reg_write(codec->control_data, reg, value);
+}
+static unsigned int sitar_read(struct snd_soc_codec *codec,
+				unsigned int reg)
+{
+	unsigned int val;
+	int ret;
+
+	BUG_ON(reg > SITAR_MAX_REGISTER);
+
+	if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
+		reg < codec->driver->reg_cache_size) {
+		ret = snd_soc_cache_read(codec, reg, &val);
+		if (ret >= 0) {
+			return val;
+		} else
+			dev_err(codec->dev, "Cache read from %x failed: %d\n",
+				reg, ret);
+	}
+
+	val = wcd9xxx_reg_read(codec->control_data, reg);
+	return val;
+}
+
+static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
+{
+
+	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x61);
+	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+	usleep_range(1000, 1000);
+	snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x80);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
+		0x04);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
+		0x01);
+	usleep_range(1000, 1000);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x00);
+}
+
+static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
+	enum sitar_bandgap_type choice)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	/* TODO lock resources accessed by audio streams and threaded
+	* interrupt handlers
+	*/
+
+	pr_err("%s, choice is %d, current is %d\n", __func__, choice,
+		sitar->bandgap_type);
+
+	if (sitar->bandgap_type == choice)
+		return;
+
+	if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
+		(choice == SITAR_BANDGAP_AUDIO_MODE)) {
+		sitar_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == SITAR_BANDGAP_MBHC_MODE) {
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
+			0x2);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
+			0x4);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
+			0x1);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x00);
+	} else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
+		(choice == SITAR_BANDGAP_AUDIO_MODE)) {
+		snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
+		usleep_range(100, 100);
+		sitar_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == SITAR_BANDGAP_OFF) {
+		snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
+	} else {
+		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
+	}
+	sitar->bandgap_type = choice;
+}
+
+
+static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
+	int config_mode)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	pr_err("%s\n", __func__);
+
+	if (config_mode) {
+		snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
+		snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
+		snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
+		usleep_range(1000, 1000);
+	} else
+		snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
+
+
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
+	snd_soc_update_bits(codec, SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+	snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
+	usleep_range(50, 50);
+	sitar->clock_active = true;
+	return 0;
+}
+static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	pr_err("%s\n", __func__);
+	snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
+	ndelay(160);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
+	sitar->clock_active = false;
+}
+
+static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+{
+	/* TODO store register values in calibration */
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
+
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
+
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
+
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 3);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL, 9);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL, 30);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 120);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_B2_CTL, 11);
+}
+
+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);
+
+	return 0;
+}
+
+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);
+}
+
+int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	pr_err("%s() mclk_enable = %u\n", __func__, mclk_enable);
+
+	if (mclk_enable) {
+		sitar->mclk_enabled = true;
+
+		if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
+			sitar_codec_pause_hs_polling(codec);
+			sitar_codec_enable_bandgap(codec,
+					SITAR_BANDGAP_AUDIO_MODE);
+			sitar_codec_enable_clock_block(codec, 0);
+			sitar_codec_calibrate_hs_polling(codec);
+			sitar_codec_start_hs_polling(codec);
+		} else {
+			sitar_codec_enable_bandgap(codec,
+					SITAR_BANDGAP_AUDIO_MODE);
+			sitar_codec_enable_clock_block(codec, 0);
+		}
+	} else {
+
+		if (!sitar->mclk_enabled) {
+			pr_err("Error, MCLK already diabled\n");
+			return -EINVAL;
+		}
+		sitar->mclk_enabled = false;
+
+		if (sitar->mbhc_polling_active) {
+			if (!sitar->mclk_enabled) {
+				sitar_codec_pause_hs_polling(codec);
+				sitar_codec_enable_bandgap(codec,
+					SITAR_BANDGAP_MBHC_MODE);
+				sitar_enable_rx_bias(codec, 1);
+				sitar_codec_enable_clock_block(codec, 1);
+				sitar_codec_calibrate_hs_polling(codec);
+				sitar_codec_start_hs_polling(codec);
+			}
+			snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
+					0x05, 0x01);
+		} else {
+			sitar_codec_disable_clock_block(codec);
+			sitar_codec_enable_bandgap(codec,
+				SITAR_BANDGAP_OFF);
+		}
+	}
+	return 0;
+}
+
+static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	pr_err("%s\n", __func__);
+	return 0;
+}
+
+static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	u8 val = 0;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+
+	pr_err("%s\n", __func__);
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* CPU is master */
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL,
+					SITAR_I2S_MASTER_MODE_MASK, 0);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL,
+					SITAR_I2S_MASTER_MODE_MASK, 0);
+		}
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+	/* CPU is slave */
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			val = SITAR_I2S_MASTER_MODE_MASK;
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+static int sitar_set_channel_map(struct snd_soc_dai *dai,
+			unsigned int tx_num, unsigned int *tx_slot,
+			unsigned int rx_num, unsigned int *rx_slot)
+
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+	u32 i = 0;
+	if (!tx_slot && !rx_slot) {
+		pr_err("%s: Invalid\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
+
+	if (dai->id == AIF1_PB) {
+		for (i = 0; i < rx_num; i++) {
+			sitar->dai[dai->id - 1].ch_num[i]  = rx_slot[i];
+			sitar->dai[dai->id - 1].ch_act = 0;
+			sitar->dai[dai->id - 1].ch_tot = rx_num;
+		}
+	} else if (dai->id == AIF1_CAP) {
+		for (i = 0; i < tx_num; i++) {
+			sitar->dai[dai->id - 1].ch_num[i]  = tx_slot[i];
+			sitar->dai[dai->id - 1].ch_act = 0;
+			sitar->dai[dai->id - 1].ch_tot = tx_num;
+		}
+	}
+	return 0;
+}
+
+static int sitar_get_channel_map(struct snd_soc_dai *dai,
+			unsigned int *tx_num, unsigned int *tx_slot,
+			unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+	struct wcd9xxx *sitar = dev_get_drvdata(dai->codec->control_data);
+
+	u32 cnt = 0;
+	u32 tx_ch[SLIM_MAX_TX_PORTS];
+	u32 rx_ch[SLIM_MAX_RX_PORTS];
+
+	if (!rx_slot && !tx_slot) {
+		pr_err("%s: Invalid\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
+	/* for virtual port, codec driver needs to do
+	* housekeeping, for now should be ok
+	*/
+	wcd9xxx_get_channel(sitar, rx_ch, tx_ch);
+	if (dai->id == AIF1_PB) {
+		*rx_num = sitar_dai[dai->id - 1].playback.channels_max;
+		while (cnt < *rx_num) {
+			rx_slot[cnt] = rx_ch[cnt];
+			cnt++;
+		}
+	} else if (dai->id == AIF1_CAP) {
+		*tx_num = sitar_dai[dai->id - 1].capture.channels_max;
+		while (cnt < *tx_num) {
+			tx_slot[cnt] = tx_ch[6 + cnt];
+			cnt++;
+		}
+	}
+	return 0;
+}
+
+static int sitar_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+	u8 path, shift;
+	u16 tx_fs_reg, rx_fs_reg;
+	u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+
+	pr_err("%s: DAI-ID %x\n", __func__, dai->id);
+
+	switch (params_rate(params)) {
+	case 8000:
+		tx_fs_rate = 0x00;
+		rx_fs_rate = 0x00;
+		break;
+	case 16000:
+		tx_fs_rate = 0x01;
+		rx_fs_rate = 0x20;
+		break;
+	case 32000:
+		tx_fs_rate = 0x02;
+		rx_fs_rate = 0x40;
+		break;
+	case 48000:
+		tx_fs_rate = 0x03;
+		rx_fs_rate = 0x60;
+		break;
+	default:
+		pr_err("%s: Invalid sampling rate %d\n", __func__,
+				params_rate(params));
+		return -EINVAL;
+	}
+
+
+	/**
+	* If current dai is a tx dai, set sample rate to
+	* all the txfe paths that are currently not active
+	*/
+	if (dai->id == AIF1_CAP) {
+
+		tx_state = snd_soc_read(codec,
+				SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
+
+		for (path = 1, shift = 0;
+				path <= NUM_DECIMATORS; path++, shift++) {
+
+			if (!(tx_state & (1 << shift))) {
+				tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
+						+ (BITS_PER_REG*(path-1));
+				snd_soc_update_bits(codec, tx_fs_reg,
+							0x03, tx_fs_rate);
+			}
+		}
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				pr_err("invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
+						0x03, tx_fs_rate);
+		}
+	} else {
+		sitar->dai[dai->id - 1].rate   = params_rate(params);
+	}
+
+	/**
+	* TODO: Need to handle case where same RX chain takes 2 or more inputs
+	* with varying sample rates
+	*/
+
+	/**
+	* If current dai is a rx dai, set sample rate to
+	* all the rx paths that are currently not active
+	*/
+	if (dai->id == AIF1_PB) {
+
+		rx_state = snd_soc_read(codec,
+			SITAR_A_CDC_CLK_RX_B1_CTL);
+
+		for (path = 1, shift = 0;
+				path <= NUM_INTERPOLATORS; path++, shift++) {
+
+			if (!(rx_state & (1 << shift))) {
+				rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
+						+ (BITS_PER_REG*(path-1));
+				snd_soc_update_bits(codec, rx_fs_reg,
+						0xE0, rx_fs_rate);
+			}
+		}
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				pr_err("invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
+						0x03, (rx_fs_rate >> 0x05));
+		}
+	} else {
+		sitar->dai[dai->id - 1].rate   = params_rate(params);
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops sitar_dai_ops = {
+	.startup = sitar_startup,
+	.shutdown = sitar_shutdown,
+	.hw_params = sitar_hw_params,
+	.set_sysclk = sitar_set_dai_sysclk,
+	.set_fmt = sitar_set_dai_fmt,
+	.set_channel_map = sitar_set_channel_map,
+	.get_channel_map = sitar_get_channel_map,
+};
+
+static struct snd_soc_dai_driver sitar_dai[] = {
+	{
+		.name = "sitar_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9304_RATES,
+			.formats = SITAR_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &sitar_dai_ops,
+	},
+	{
+		.name = "sitar_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9304_RATES,
+			.formats = SITAR_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &sitar_dai_ops,
+	},
+};
+
+static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct wcd9xxx *sitar;
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+	u32  j = 0;
+	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	sitar = codec->control_data;
+	/* Execute the callback only if interface type is slimbus */
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return 0;
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_CAP)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].playback.stream_name, 13)) {
+				++sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
+			wcd9xxx_cfg_slim_sch_rx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot,
+					sitar_p->dai[j].rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_CAP)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].playback.stream_name, 13)) {
+				--sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (!sitar_p->dai[j].ch_act) {
+			wcd9xxx_close_slim_sch_rx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot);
+			/* Wait for remove channel to complete
+			 * before derouting Rx path
+			 */
+			usleep_range(15000, 15000);
+			sitar_p->dai[j].rate = 0;
+			memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
+					sitar_p->dai[j].ch_tot));
+			sitar_p->dai[j].ch_tot = 0;
+		}
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct wcd9xxx *sitar;
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+	/* index to the DAI ID, for now hardcoding */
+	u32  j = 0;
+
+	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	sitar = codec->control_data;
+
+	/* Execute the callback only if interface type is slimbus */
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return 0;
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_PB)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].capture.stream_name, 13)) {
+				++sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
+			wcd9xxx_cfg_slim_sch_tx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot,
+					sitar_p->dai[j].rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_PB)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].capture.stream_name, 13)) {
+				--sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (!sitar_p->dai[j].ch_act) {
+			wcd9xxx_close_slim_sch_tx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot);
+			sitar_p->dai[j].rate = 0;
+			memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
+					sitar_p->dai[j].ch_tot));
+			sitar_p->dai[j].ch_tot = 0;
+		}
+	}
+	return 0;
+}
+
+
+static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
+{
+	u8 bias_msb, bias_lsb;
+	short bias_value;
+
+	bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
+	bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
+	bias_value = (bias_msb << 8) | bias_lsb;
+	return bias_value;
+}
+
+static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
+{
+	u8 bias_msb, bias_lsb;
+	short bias_value;
+
+	bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
+	bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
+	bias_value = (bias_msb << 8) | bias_lsb;
+	return bias_value;
+}
+
+static short sitar_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
+	int dce)
+{
+	short bias_value;
+
+	if (dce) {
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
+		usleep_range(60000, 60000);
+		bias_value = sitar_codec_read_dce_result(codec);
+	} else {
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+		usleep_range(5000, 5000);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
+		usleep_range(50, 50);
+		bias_value = sitar_codec_read_sta_result(codec);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
+	}
+
+	pr_err("read microphone bias value %x\n", bias_value);
+	return bias_value;
+}
+
+static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+	short bias_value;
+	u8 cfilt_mode;
+
+	if (!calibration) {
+		pr_err("Error, no sitar calibration\n");
+		return -ENODEV;
+	}
+
+	sitar->mbhc_polling_active = true;
+
+	if (!sitar->mclk_enabled) {
+		sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
+		sitar_enable_rx_bias(codec, 1);
+		sitar_codec_enable_clock_block(codec, 1);
+	}
+
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
+
+	snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
+
+	/* Make sure CFILT is in fast mode, save current mode */
+	cfilt_mode = snd_soc_read(codec,
+		sitar->mbhc_bias_regs.cfilt_ctl);
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
+		0x70, 0x00);
+
+	snd_soc_update_bits(codec,
+		sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+
+	sitar_codec_calibrate_hs_polling(codec);
+
+	bias_value = sitar_codec_measure_micbias_voltage(codec, 0);
+	snd_soc_update_bits(codec,
+		sitar->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
+	snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
+
+	return bias_value;
+}
+
+static int sitar_codec_enable_hs_detect(struct snd_soc_codec *codec,
+		int insertion)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+	int central_bias_enabled = 0;
+	u8 wg_time;
+
+	if (!calibration) {
+		pr_err("Error, no sitar calibration\n");
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0);
+
+	if (insertion) {
+		/* Make sure mic bias and Mic line schmitt trigger
+		* are turned OFF
+		*/
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
+			0x81, 0x01);
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+			0x90, 0x00);
+		wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
+		wg_time += 1;
+
+		/* Enable HPH Schmitt Trigger */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x11, 0x11);
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x0C,
+			calibration->hph_current << 2);
+
+		/* Turn off HPH PAs and DAC's during insertion detection to
+		* avoid false insertion interrupts
+		*/
+		if (sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
+			0xC0, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
+			0xC0, 0x00);
+		usleep_range(wg_time * 1000, wg_time * 1000);
+
+		/* setup for insetion detection */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x02, 0x02);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
+	} else {
+		/* Make sure the HPH schmitt trigger is OFF */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
+
+		/* enable the mic line schmitt trigger */
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x60,
+			calibration->mic_current << 5);
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+			0x80, 0x80);
+		usleep_range(calibration->mic_pid, calibration->mic_pid);
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+			0x10, 0x10);
+
+		/* Setup for low power removal detection */
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
+	}
+
+	if (snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_CTL) & 0x4) {
+		if (!(sitar->clock_active)) {
+			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
+				0x06, 0);
+			usleep_range(calibration->shutdown_plug_removal,
+				calibration->shutdown_plug_removal);
+		} else
+			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
+				0x06, 0);
+	}
+
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.int_rbias, 0x80, 0);
+
+	/* If central bandgap disabled */
+	if (!(snd_soc_read(codec, SITAR_A_PIN_CTL_OE1) & 1)) {
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x3, 0x3);
+		usleep_range(calibration->bg_fast_settle,
+			calibration->bg_fast_settle);
+		central_bias_enabled = 1;
+	}
+
+	/* If LDO_H disabled */
+	if (snd_soc_read(codec, SITAR_A_PIN_CTL_OE0) & 0x80) {
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x10, 0);
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0x80);
+		usleep_range(calibration->tldoh, calibration->tldoh);
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0);
+
+		if (central_bias_enabled)
+			snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x1, 0);
+	}
+
+	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+	return 0;
+}
+
+static void btn0_lpress_fn(struct work_struct *work)
+{
+	struct delayed_work *delayed_work;
+	struct sitar_priv *sitar;
+
+	pr_err("%s:\n", __func__);
+
+	delayed_work = to_delayed_work(work);
+	sitar = container_of(delayed_work, struct sitar_priv, btn0_dwork);
+
+	if (sitar) {
+		if (sitar->button_jack) {
+			pr_err("%s: Reporting long button press event\n",
+					__func__);
+			sitar_snd_soc_jack_report(sitar, sitar->button_jack,
+						 SND_JACK_BTN_0,
+						 SND_JACK_BTN_0);
+		}
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+
+}
+
+int sitar_hs_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
+	struct sitar_mbhc_calibration *calibration)
+{
+	struct sitar_priv *sitar;
+	int rc;
+
+	if (!codec || !calibration) {
+		pr_err("Error: no codec or calibration\n");
+		return -EINVAL;
+	}
+	sitar = snd_soc_codec_get_drvdata(codec);
+	sitar->headset_jack = headset_jack;
+	sitar->button_jack = button_jack;
+	sitar->calibration = calibration;
+	sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
+
+	/* Put CFILT in fast mode by default */
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
+		0x40, SITAR_CFILT_FAST_MODE);
+
+	INIT_DELAYED_WORK(&sitar->btn0_dwork, btn0_lpress_fn);
+	INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
+	INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
+	rc =  sitar_codec_enable_hs_detect(codec, 1);
+
+	if (!IS_ERR_VALUE(rc)) {
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+			0x10);
+		wcd9xxx_enable_irq(codec->control_data,
+			SITAR_IRQ_HPH_PA_OCPL_FAULT);
+		wcd9xxx_enable_irq(codec->control_data,
+			SITAR_IRQ_HPH_PA_OCPR_FAULT);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(sitar_hs_detect);
+
+static irqreturn_t sitar_dce_handler(int irq, void *data)
+{
+	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);
+
+	bias_value = sitar_codec_read_dce_result(codec);
+	pr_err("%s: button press interrupt, bias value(DCE Read)=%d\n",
+			__func__, bias_value);
+
+	bias_value = sitar_codec_read_sta_result(codec);
+	pr_err("%s: button press interrupt, bias value(STA Read)=%d\n",
+			__func__, bias_value);
+	/*
+	* TODO: If button pressed is not button 0,
+	* report the button press event immediately.
+	*/
+	priv->buttons_pressed |= SND_JACK_BTN_0;
+
+	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");
+		wcd9xxx_unlock_sleep(core);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_release_handler(int irq, void *data)
+{
+	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);
+
+	mic_voltage = sitar_codec_read_dce_result(codec);
+	pr_err("%s: Microphone Voltage on release(DCE Read) = %d\n",
+		__func__, mic_voltage);
+
+	if (priv->buttons_pressed & SND_JACK_BTN_0) {
+		ret = cancel_delayed_work(&priv->btn0_dwork);
+
+		if (ret == 0) {
+
+			pr_err("%s: Reporting long button release event\n",
+					__func__);
+			if (priv->button_jack) {
+				sitar_snd_soc_jack_report(priv,
+							 priv->button_jack, 0,
+							 SND_JACK_BTN_0);
+			}
+
+		} else {
+			/* if scheduled btn0_dwork is canceled from here,
+			* we have to unlock from here instead btn0_work */
+			wcd9xxx_unlock_sleep(core);
+			mic_voltage =
+				sitar_codec_measure_micbias_voltage(codec, 0);
+			pr_err("%s: Mic Voltage on release(new STA) = %d\n",
+						__func__, mic_voltage);
+
+			if (mic_voltage < -2000 || mic_voltage > -670) {
+				pr_err("%s: Fake buttton press interrupt\n",
+						__func__);
+			} else {
+
+				if (priv->button_jack) {
+					pr_err("%s:reporting short button press and release\n",
+							__func__);
+
+					sitar_snd_soc_jack_report(priv,
+							     priv->button_jack,
+						SND_JACK_BTN_0, SND_JACK_BTN_0);
+					sitar_snd_soc_jack_report(priv,
+							    priv->button_jack,
+							    0, SND_JACK_BTN_0);
+				}
+			}
+		}
+
+		priv->buttons_pressed &= ~SND_JACK_BTN_0;
+	}
+
+	sitar_codec_start_hs_polling(codec);
+	return IRQ_HANDLED;
+}
+
+static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
+
+	snd_soc_update_bits(codec,
+		sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+	usleep_range(calibration->shutdown_plug_removal,
+		calibration->shutdown_plug_removal);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
+
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
+}
+
+static void sitar_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	sitar_codec_shutdown_hs_removal_detect(codec);
+
+	if (!sitar->mclk_enabled) {
+		snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0x00);
+		sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_AUDIO_MODE);
+		sitar_codec_enable_clock_block(codec, 0);
+	}
+
+	sitar->mbhc_polling_active = false;
+}
+
+static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
+{
+	struct sitar_priv *sitar = data;
+	struct snd_soc_codec *codec;
+
+	pr_info("%s: received HPHL OCP irq\n", __func__);
+
+	if (sitar) {
+		codec = sitar->codec;
+		if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
+			pr_info("%s: retry\n", __func__);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x00);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x10);
+		} else {
+			wcd9xxx_disable_irq(codec->control_data,
+					 SITAR_IRQ_HPH_PA_OCPL_FAULT);
+			sitar->hphlocp_cnt = 0;
+			sitar->hph_status |= SND_JACK_OC_HPHL;
+			if (sitar->headset_jack)
+				sitar_snd_soc_jack_report(sitar,
+							 sitar->headset_jack,
+							 sitar->hph_status,
+							 SITAR_JACK_MASK);
+		}
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
+{
+	struct sitar_priv *sitar = data;
+	struct snd_soc_codec *codec;
+
+	pr_info("%s: received HPHR OCP irq\n", __func__);
+
+	if (sitar) {
+		codec = sitar->codec;
+		if (sitar->hphrocp_cnt++ < SITAR_OCP_ATTEMPT) {
+			pr_info("%s: retry\n", __func__);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x00);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x10);
+		} else {
+			wcd9xxx_disable_irq(codec->control_data,
+					 SITAR_IRQ_HPH_PA_OCPR_FAULT);
+			sitar->hphrocp_cnt = 0;
+			sitar->hph_status |= SND_JACK_OC_HPHR;
+			if (sitar->headset_jack)
+				sitar_snd_soc_jack_report(sitar,
+							 sitar->headset_jack,
+							 sitar->hph_status,
+							 SITAR_JACK_MASK);
+		}
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void sitar_sync_hph_state(struct sitar_priv *sitar)
+{
+	if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHR clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
+				   1 << 4);
+	}
+	if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHL clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
+				   1 << 5);
+	}
+
+	if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHR clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
+				   0xC0, 0xC0);
+	}
+	if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHL clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
+				   0xC0, 0xC0);
+	}
+}
+
+static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	int ldo_h_on, micb_cfilt_on;
+	short mic_voltage;
+	short threshold_no_mic = 0xF7F6;
+	short threshold_fake_insert = 0xFD30;
+	u8 is_removal;
+
+	pr_err("%s\n", __func__);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+
+	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);
+
+	/* Turn off both HPH and MIC line schmitt triggers */
+	snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+			0x90, 0x00);
+	snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
+
+	if (priv->fake_insert_context) {
+		pr_err("%s: fake context interrupt, reset insertion\n",
+			__func__);
+		priv->fake_insert_context = false;
+		sitar_codec_shutdown_hs_polling(codec);
+		sitar_codec_enable_hs_detect(codec, 1);
+		return IRQ_HANDLED;
+	}
+
+
+	ldo_h_on = snd_soc_read(codec, SITAR_A_LDO_H_MODE_1) & 0x80;
+	micb_cfilt_on = snd_soc_read(codec,
+					priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
+
+	if (!ldo_h_on)
+		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+	if (!micb_cfilt_on)
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
+							0x80, 0x80);
+
+	usleep_range(priv->calibration->setup_plug_removal_delay,
+		priv->calibration->setup_plug_removal_delay);
+
+	if (!ldo_h_on)
+		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x0);
+	if (!micb_cfilt_on)
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
+							0x80, 0x0);
+
+	if (is_removal) {
+		/*
+		* If headphone is removed while playback is in progress,
+		* it is possible that micbias will be switched to VDDIO.
+		*/
+		if (priv->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+		priv->hph_status &= ~SND_JACK_HEADPHONE;
+
+		/* If headphone PA is on, check if userspace receives
+		* removal event to sync-up PA's state */
+		if (sitar_is_hph_pa_on(codec)) {
+			set_bit(SITAR_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
+			set_bit(SITAR_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
+		}
+
+		if (sitar_is_hph_dac_on(codec, 1))
+			set_bit(SITAR_HPHL_DAC_OFF_ACK,
+				&priv->hph_pa_dac_state);
+		if (sitar_is_hph_dac_on(codec, 0))
+			set_bit(SITAR_HPHR_DAC_OFF_ACK,
+				&priv->hph_pa_dac_state);
+
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting removal\n", __func__);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack,
+						 priv->hph_status,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_shutdown_hs_removal_detect(codec);
+		sitar_codec_enable_hs_detect(codec, 1);
+		return IRQ_HANDLED;
+	}
+
+	mic_voltage = sitar_codec_setup_hs_polling(codec);
+
+	if (mic_voltage > threshold_fake_insert) {
+		pr_err("%s: Fake insertion interrupt, mic_voltage = %x\n",
+			__func__, mic_voltage);
+
+		/* Disable HPH trigger and enable MIC line trigger */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
+
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
+			priv->calibration->mic_current << 5);
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+			0x80, 0x80);
+		usleep_range(priv->calibration->mic_pid,
+			priv->calibration->mic_pid);
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+			0x10, 0x10);
+
+		/* Setup for insertion detection */
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
+		priv->fake_insert_context = true;
+		wcd9xxx_enable_irq(codec->control_data,
+				SITAR_IRQ_MBHC_INSERTION);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+
+	} else if (mic_voltage < threshold_no_mic) {
+		pr_err("%s: Headphone Detected, mic_voltage = %x\n",
+			__func__, mic_voltage);
+		priv->hph_status |= SND_JACK_HEADPHONE;
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting insertion %d\n", __func__,
+				SND_JACK_HEADPHONE);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack,
+						 priv->hph_status,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_shutdown_hs_polling(codec);
+		sitar_codec_enable_hs_detect(codec, 0);
+		sitar_sync_hph_state(priv);
+	} else {
+		pr_err("%s: Headset detected, mic_voltage = %x\n",
+			__func__, mic_voltage);
+		priv->hph_status |= SND_JACK_HEADSET;
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting insertion %d\n", __func__,
+				SND_JACK_HEADSET);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack,
+						 priv->hph_status,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_start_hs_polling(codec);
+		sitar_sync_hph_state(priv);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	short bias_value;
+
+	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);
+
+	usleep_range(priv->calibration->shutdown_plug_removal,
+		priv->calibration->shutdown_plug_removal);
+
+	bias_value = sitar_codec_measure_micbias_voltage(codec, 1);
+	pr_err("removal interrupt, bias value is %d\n", bias_value);
+
+	if (bias_value < -90) {
+		pr_err("False alarm, headset not actually removed\n");
+		sitar_codec_start_hs_polling(codec);
+	} else {
+		/*
+		* If this removal is not false, first check the micbias
+		* switch status and switch it to LDOH if it is already
+		* switched to VDDIO.
+		*/
+		if (priv->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+		priv->hph_status &= ~SND_JACK_HEADSET;
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting removal\n", __func__);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack, 0,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_shutdown_hs_polling(codec);
+
+		sitar_codec_enable_hs_detect(codec, 1);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static unsigned long slimbus_value;
+
+static irqreturn_t sitar_slimbus_irq(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	int i, j;
+	u8 val;
+
+
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
+		slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
+			SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
+		for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
+			val = wcd9xxx_interface_reg_read(codec->control_data,
+				SITAR_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
+			if (val & 0x1)
+				pr_err_ratelimited("overflow error on port %x,"
+					" value %x\n", i*8 + j, val);
+			if (val & 0x2)
+				pr_err_ratelimited("underflow error on port %x,"
+					" value %x\n", i*8 + j, val);
+		}
+		wcd9xxx_interface_reg_write(codec->control_data,
+			SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static int sitar_handle_pdata(struct sitar_priv *sitar)
+{
+	struct snd_soc_codec *codec = sitar->codec;
+	struct wcd9xxx_pdata *pdata = sitar->pdata;
+	int k1, k2, rc = 0;
+	u8 leg_mode = pdata->amic_settings.legacy_mode;
+	u8 txfe_bypass = pdata->amic_settings.txfe_enable;
+	u8 txfe_buff = pdata->amic_settings.txfe_buff;
+	u8 flag = pdata->amic_settings.use_pdata;
+	u8 i = 0, j = 0;
+	u8 val_txfe = 0, value = 0;
+
+	if (!pdata) {
+		rc = -ENODEV;
+		goto done;
+	}
+
+	/* Make sure settings are correct */
+	if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
+	   (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
+	   (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* figure out k value */
+	k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
+		pdata->micbias.cfilt1_mv);
+	k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
+		pdata->micbias.cfilt2_mv);
+
+	if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Set voltage level and always use LDO */
+
+	snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
+		(k1 << 2));
+	snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
+		(k2 << 2));
+
+	snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
+		(pdata->micbias.bias1_cfilt_sel << 5));
+	snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
+		(pdata->micbias.bias2_cfilt_sel << 5));
+
+	for (i = 0; i < 6; j++, i += 2) {
+		if (flag & (0x01 << i)) {
+			value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
+			val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
+			val_txfe = val_txfe |
+				((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
+			snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
+				0x10, value);
+			snd_soc_update_bits(codec,
+				SITAR_A_TX_1_2_TEST_EN + j * 10,
+				0x30, val_txfe);
+		}
+		if (flag & (0x01 << (i + 1))) {
+			value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
+			val_txfe = (txfe_bypass &
+					(0x01 << (i + 1))) ? 0x02 : 0x00;
+			val_txfe |= (txfe_buff &
+					(0x01 << (i + 1))) ? 0x01 : 0x00;
+			snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
+				0x01, value);
+			snd_soc_update_bits(codec,
+				SITAR_A_TX_1_2_TEST_EN + j * 10,
+				0x03, val_txfe);
+		}
+	}
+
+	if (pdata->ocp.use_pdata) {
+		/* not defined in CODEC specification */
+		if (pdata->ocp.hph_ocp_limit == 1 ||
+			pdata->ocp.hph_ocp_limit == 5) {
+			rc = -EINVAL;
+			goto done;
+		}
+		snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
+			0x0F, pdata->ocp.num_attempts);
+		snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
+			((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
+			0xE0, (pdata->ocp.hph_ocp_limit << 5));
+	}
+done:
+	return rc;
+}
+
+static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
+
+	/* Sitar 1.1 MICBIAS changes */
+	SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
+	SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
+
+	/* Sitar 1.1 HPH changes */
+	SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
+	SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
+
+	/* Sitar 1.1 EAR PA changes */
+	SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
+	SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
+	SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
+
+	/* Sitar 1.1 RX Changes */
+	SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
+
+	/* Sitar 1.1 RX1 and RX2 Changes */
+	SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
+
+	SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
+
+};
+
+static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
+{
+	u32 i;
+	for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
+		snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
+				sitar_1_1_reg_defaults[i].val);
+
+}
+static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
+	/* Initialize current threshold to 350MA
+	* number of wait and run cycles to 4096
+	*/
+	{SITAR_A_RX_HPH_OCP_CTL, 0xF8, 0x60},
+	{SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+
+	{SITAR_A_QFUSE_CTL, 0xFF, 0x03},
+
+	/* Initialize gain registers to use register gain */
+	{SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
+	{SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
+	{SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
+	{SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
+
+	/* Initialize mic biases to differential mode */
+	{SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
+	{SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
+
+	{SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
+
+	/* Use 16 bit sample size for TX1 to TX6 */
+	{SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x28},
+	{SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
+	{SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
+	{SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
+	{SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
+
+	/* Use 16 bit sample size for RX */
+	{SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
+	{SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
+
+	/*enable HPF filter for TX paths */
+	{SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
+};
+
+static void sitar_codec_init_reg(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
+		snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
+			sitar_codec_reg_init_val[i].mask,
+			sitar_codec_reg_init_val[i].val);
+}
+
+static int sitar_codec_probe(struct snd_soc_codec *codec)
+{
+	struct sitar *control;
+	struct sitar_priv *sitar;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret = 0;
+	int i;
+	u8 sitar_version;
+	int ch_cnt;
+
+	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	control = codec->control_data;
+
+	sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
+	if (!sitar) {
+		dev_err(codec->dev, "Failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	/* Make sure mbhc micbias register addresses are zeroed out */
+	memset(&sitar->mbhc_bias_regs, 0,
+		sizeof(struct mbhc_micbias_regs));
+	sitar->cfilt_k_value = 0;
+	sitar->mbhc_micbias_switched = false;
+
+	snd_soc_codec_set_drvdata(codec, sitar);
+
+	sitar->mclk_enabled = false;
+	sitar->bandgap_type = SITAR_BANDGAP_OFF;
+	sitar->clock_active = false;
+	sitar->config_mode_active = false;
+	sitar->mbhc_polling_active = false;
+	sitar->fake_insert_context = false;
+	sitar->no_mic_headset_override = false;
+	sitar->codec = codec;
+	sitar->pdata = dev_get_platdata(codec->dev->parent);
+	atomic_set(&sitar->pm_cnt, 1);
+	init_waitqueue_head(&sitar->pm_wq);
+
+	sitar_update_reg_defaults(codec);
+	sitar_codec_init_reg(codec);
+
+	ret = sitar_handle_pdata(sitar);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s: bad pdata\n", __func__);
+		goto err_pdata;
+	}
+
+	snd_soc_add_controls(codec, sitar_snd_controls,
+		ARRAY_SIZE(sitar_snd_controls));
+	snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
+		ARRAY_SIZE(sitar_dapm_widgets));
+	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+	sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
+	pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
+
+	sitar_version &=  0x1F;
+	pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
+
+	snd_soc_dapm_sync(dapm);
+
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION,
+		sitar_hs_insert_irq, "Headset insert detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_INSERTION);
+		goto err_insert_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL,
+		sitar_hs_remove_irq, "Headset remove detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_REMOVAL);
+		goto err_remove_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
+		sitar_dce_handler, "DC Estimation detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_POTENTIAL);
+		goto err_potential_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
+		sitar_release_handler, "Button Release detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_RELEASE);
+		goto err_release_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
+		sitar_slimbus_irq, "SLIMBUS Slave", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_SLIMBUS);
+		goto err_slimbus_irq;
+	}
+
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+		wcd9xxx_interface_reg_write(codec->control_data,
+			SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+
+
+	ret = wcd9xxx_request_irq(codec->control_data,
+		SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar_hphl_ocp_irq,
+		"HPH_L OCP detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_HPH_PA_OCPL_FAULT);
+		goto err_hphl_ocp_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+
+	ret = wcd9xxx_request_irq(codec->control_data,
+		SITAR_IRQ_HPH_PA_OCPR_FAULT, sitar_hphr_ocp_irq,
+		"HPH_R OCP detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_HPH_PA_OCPR_FAULT);
+		goto err_hphr_ocp_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+
+	for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
+		switch (sitar_dai[i].id) {
+		case AIF1_PB:
+			ch_cnt = sitar_dai[i].playback.channels_max;
+			break;
+		case AIF1_CAP:
+			ch_cnt = sitar_dai[i].capture.channels_max;
+			break;
+		default:
+			continue;
+		}
+		sitar->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
+					ch_cnt), GFP_KERNEL);
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	debug_sitar_priv = sitar;
+#endif
+
+	return ret;
+
+err_hphr_ocp_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar);
+err_hphl_ocp_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_SLIMBUS, sitar);
+err_slimbus_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_RELEASE, sitar);
+err_release_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_POTENTIAL, sitar);
+err_potential_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_REMOVAL, sitar);
+err_remove_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_INSERTION, sitar);
+err_insert_irq:
+err_pdata:
+	kfree(sitar);
+	return ret;
+}
+static int sitar_codec_remove(struct snd_soc_codec *codec)
+{
+	int i;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_SLIMBUS, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
+	sitar_codec_disable_clock_block(codec);
+	sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
+	for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
+		kfree(sitar->dai[i].ch_num);
+	kfree(sitar);
+	return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_sitar = {
+	.probe	= sitar_codec_probe,
+	.remove	= sitar_codec_remove,
+	.read = sitar_read,
+	.write = sitar_write,
+
+	.readable_register = sitar_readable,
+	.volatile_register = sitar_volatile,
+
+	.reg_cache_size = SITAR_CACHE_SIZE,
+	.reg_cache_default = sitar_reg_defaults,
+	.reg_word_size = 1,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_poke;
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t codec_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[32];
+	char *buf;
+	int rc;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	buf = (char *)lbuf;
+	debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
+		? false : true;
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+};
+#endif
+
+#ifdef CONFIG_PM
+static int sitar_suspend(struct device *dev)
+{
+	dev_dbg(dev, "%s: system suspend\n", __func__);
+	return 0;
+}
+
+static int sitar_resume(struct device *dev)
+{
+	dev_dbg(dev, "%s: system resume\n", __func__);
+	return 0;
+}
+
+static const struct dev_pm_ops sitar_pm_ops = {
+	.suspend	= sitar_suspend,
+	.resume		= sitar_resume,
+};
+#endif
+
+static int __devinit sitar_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	pr_err("%s\n", __func__);
+#ifdef CONFIG_DEBUG_FS
+	debugfs_poke = debugfs_create_file("TRRS",
+		S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
+
+#endif
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+			sitar_dai, ARRAY_SIZE(sitar_dai));
+	return ret;
+}
+static int __devexit sitar_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(debugfs_poke);
+#endif
+	return 0;
+}
+static struct platform_driver sitar_codec_driver = {
+	.probe = sitar_probe,
+	.remove = sitar_remove,
+	.driver = {
+		.name = "sitar_codec",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &sitar_pm_ops,
+#endif
+	},
+};
+
+static int __init sitar_codec_init(void)
+{
+	return platform_driver_register(&sitar_codec_driver);
+}
+
+static void __exit sitar_codec_exit(void)
+{
+	platform_driver_unregister(&sitar_codec_driver);
+}
+
+module_init(sitar_codec_init);
+module_exit(sitar_codec_exit);
+
+MODULE_DESCRIPTION("Sitar codec driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9304.h b/sound/soc/codecs/wcd9304.h
new file mode 100644
index 0000000..07a1ca0
--- /dev/null
+++ b/sound/soc/codecs/wcd9304.h
@@ -0,0 +1,72 @@
+/* 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 <sound/soc.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+
+#define SITAR_VERSION_1_0	0x00
+
+#define SITAR_NUM_REGISTERS 0x3E0
+#define SITAR_MAX_REGISTER (SITAR_NUM_REGISTERS-1)
+#define SITAR_CACHE_SIZE SITAR_NUM_REGISTERS
+
+#define SITAR_REG_VAL(reg, val)		{reg, 0, val}
+
+/* Local to the core only */
+#define SITAR_SLIM_MAX_RX_PORTS 5
+#define SITAR_SLIM_MAX_TX_PORTS 5
+
+extern const u8 sitar_reg_readable[SITAR_CACHE_SIZE];
+extern const u8 sitar_reg_defaults[SITAR_CACHE_SIZE];
+
+enum sitar_micbias_num {
+	SITAR_MICBIAS1,
+	SITAR_MICBIAS2,
+};
+
+enum sitar_pid_current {
+	SITAR_PID_MIC_2P5_UA,
+	SITAR_PID_MIC_5_UA,
+	SITAR_PID_MIC_10_UA,
+	SITAR_PID_MIC_20_UA,
+};
+
+struct sitar_mbhc_calibration {
+	enum sitar_micbias_num bias;
+	int tldoh;
+	int bg_fast_settle;
+	enum sitar_pid_current mic_current;
+	int mic_pid;
+	enum sitar_pid_current hph_current;
+	int setup_plug_removal_delay;
+	int shutdown_plug_removal;
+};
+
+struct sitar_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+extern int sitar_hs_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
+	struct sitar_mbhc_calibration *calibration);
+
+#ifndef anc_header_dec
+struct anc_header {
+	u32 reserved[3];
+	u32 num_anc_slots;
+};
+#define anc_header_dec
+#endif
+
+extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
index c681771..2cba59d 100644
--- a/sound/soc/codecs/wcd9310-tables.c
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mfd/wcd9310/registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
 #include "wcd9310.h"
 
 const u8 tabla_reg_readable[TABLA_CACHE_SIZE] = {
@@ -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 46f6461..d49e215 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -18,9 +18,10 @@
 #include <linux/printk.h>
 #include <linux/ratelimit.h>
 #include <linux/debugfs.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -28,6 +29,9 @@
 #include <sound/tlv.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
 #include "wcd9310.h"
 
 #define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
@@ -41,6 +45,15 @@
 #define MBHC_FW_READ_ATTEMPTS 15
 #define MBHC_FW_READ_TIMEOUT 2000000
 
+enum {
+	MBHC_USE_HPHL_TRIGGER = 1,
+	MBHC_USE_MB_TRIGGER = 2
+};
+
+#define MBHC_NUM_DCE_PLUG_DETECT 3
+#define NUM_ATTEMPTS_INSERT_DETECT 25
+#define NUM_ATTEMPTS_TO_REPORT 5
+
 #define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
 
 #define TABLA_I2S_MASTER_MODE_MASK 0x08
@@ -51,6 +64,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;
@@ -65,10 +79,31 @@
 #define TABLA_FAKE_INS_THRESHOLD_MS 2500
 #define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
 
+#define TABLA_MBHC_BUTTON_MIN 0x8000
+
+#define TABLA_MBHC_FAKE_INSERT_LOW 10
+#define TABLA_MBHC_FAKE_INSERT_HIGH 80
+#define TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO 150
+
+#define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
+
+#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
+
+#define TABLA_MBHC_FAKE_INSERT_VOLT_DELTA_MV 200
+
+#define TABLA_HS_DETECT_PLUG_TIME_MS (5 * 1000)
+#define TABLA_HS_DETECT_PLUG_INERVAL_MS 100
+
+#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
+
+#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
+#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
 static struct snd_soc_dai_driver tabla_dai[];
+static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
 
 enum tabla_bandgap_type {
 	TABLA_BANDGAP_OFF = 0,
@@ -101,6 +136,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. */
@@ -111,6 +160,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;
@@ -139,10 +195,32 @@
 	u16 micb_4_mbhc;
 };
 
+enum tabla_mbhc_plug_type {
+	PLUG_TYPE_NONE = 0,
+	PLUG_TYPE_HEADSET,
+	PLUG_TYPE_HEADPHONE,
+	PLUG_TYPE_HIGH_HPH,
+};
+
+enum tabla_mbhc_state {
+	MBHC_STATE_NONE = -1,
+	MBHC_STATE_POTENTIAL,
+	MBHC_STATE_POTENTIAL_RECOVERY,
+	MBHC_STATE_RELEASE,
+};
+
+struct hpf_work {
+	struct tabla_priv *tabla;
+	u32 decimator;
+	u8 tx_hpf_cut_of_freq;
+	struct delayed_work dwork;
+};
+
+static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
 struct tabla_priv {
 	struct snd_soc_codec *codec;
 	struct tabla_reg_address reg_addr;
-	u32 mclk_freq;
 	u32 adc_count;
 	u32 cfilt1_cnt;
 	u32 cfilt2_cnt;
@@ -155,28 +233,16 @@
 	bool mbhc_polling_active;
 	unsigned long mbhc_fake_ins_start;
 	int buttons_pressed;
-
-	enum tabla_micbias_num micbias;
-	/* void* calibration contains:
-	 *  struct tabla_mbhc_general_cfg generic;
-	 *  struct tabla_mbhc_plug_detect_cfg plug_det;
-	 *  struct tabla_mbhc_plug_type_cfg plug_type;
-	 *  struct tabla_mbhc_btn_detect_cfg btn_det;
-	 *  struct tabla_mbhc_imped_detect_cfg imped_det;
-	 * Note: various size depends on btn_det->num_btn
-	 */
-	void *calibration;
+	enum tabla_mbhc_state mbhc_state;
+	struct tabla_mbhc_config mbhc_cfg;
 	struct mbhc_internal_cal_data mbhc_data;
 
-	struct snd_soc_jack *headset_jack;
-	struct snd_soc_jack *button_jack;
-
-	struct tabla_pdata *pdata;
+	struct wcd9xxx_pdata *pdata;
 	u32 anc_slot;
 
 	bool no_mic_headset_override;
 	/* Delayed work to report long button press */
-	struct delayed_work btn0_dwork;
+	struct delayed_work mbhc_btn_dwork;
 
 	struct mbhc_micbias_regs mbhc_bias_regs;
 	u8 cfilt_k_value;
@@ -199,21 +265,88 @@
 	u8 hphlocp_cnt; /* headphone left ocp retry */
 	u8 hphrocp_cnt; /* headphone right ocp retry */
 
-	/* Callback function to enable MCLK */
-	int (*mclk_cb) (struct snd_soc_codec*, int);
-
 	/* Work to perform MBHC Firmware Read */
 	struct delayed_work mbhc_firmware_dwork;
 	const struct firmware *mbhc_fw;
 
 	/* 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];
+
+	/* Maintain the status of AUX PGA */
+	int aux_pga_cnt;
+	u8 aux_l_gain;
+	u8 aux_r_gain;
+
+	struct delayed_work mbhc_insert_dwork;
+	unsigned long mbhc_last_resume; /* in jiffies */
+
+	u8 current_plug;
+	struct work_struct hs_correct_plug_work;
+	bool hs_detect_work_stop;
+	bool hs_polling_irq_prepared;
+	bool lpi_enabled; /* low power insertion detection */
+	bool in_gpio_handler;
+	/* Currently, only used for mbhc purpose, to protect
+	 * concurrent execution of mbhc threaded irq handlers and
+	 * kill race between DAPM and MBHC.But can serve as a
+	 * general lock to protect codec resource
+	 */
+	struct mutex codec_resource_lock;
+
+	/* Used to override the rule "invalid headset
+	 * when microphone voltage is too high"
+	 */
+	bool mbhc_inval_hs_range_override;
 };
 
 #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)
 {
@@ -477,6 +610,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),
@@ -609,6 +928,11 @@
 	SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
 
+	SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
+		aux_pga_gain),
+	SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
+		aux_pga_gain),
+
 	SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
 	SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
 	SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
@@ -694,6 +1018,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[] = {
@@ -1020,6 +1348,94 @@
 	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
 };
 
+static const struct snd_kcontrol_new hphl_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					7, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					7, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new hphr_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					6, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					6, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout1_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					5, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					5, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout2_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					4, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					4, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout3_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					3, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					3, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout4_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					2, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					2, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout5_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					1, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					1, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new ear_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					0, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					0, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
+};
+
 static const struct snd_kcontrol_new lineout3_ground_switch =
 	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
 
@@ -1027,7 +1443,7 @@
 	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
 
 static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
-	int enable)
+					 int enable)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
@@ -1035,17 +1451,12 @@
 
 	if (enable) {
 		tabla->adc_count++;
-		snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
 		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
 	} else {
 		tabla->adc_count--;
-		if (!tabla->adc_count) {
+		if (!tabla->adc_count)
 			snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
-				0x2, 0x0);
-			if (!tabla->mbhc_polling_active)
-				snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
-					0xE0, 0x0);
-		}
+					    0x2, 0x0);
 	}
 }
 
@@ -1099,6 +1510,259 @@
 	return 0;
 }
 
+static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x80);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
+		0x04);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
+		0x01);
+	usleep_range(1000, 1000);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x00);
+}
+
+static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
+	enum tabla_bandgap_type choice)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	/* TODO lock resources accessed by audio streams and threaded
+	 * interrupt handlers
+	 */
+
+	pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
+		tabla->bandgap_type);
+
+	if (tabla->bandgap_type == choice)
+		return;
+
+	if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
+		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
+		tabla_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
+			0x2);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
+			0x4);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
+			0x01);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x00);
+	} else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
+		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+		usleep_range(100, 100);
+		tabla_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == TABLA_BANDGAP_OFF) {
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+	} else {
+		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
+	}
+	tabla->bandgap_type = choice;
+}
+
+static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	pr_debug("%s\n", __func__);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
+	ndelay(160);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
+	tabla->clock_active = false;
+}
+
+static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
+{
+	if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
+		return 0;
+	else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
+		return 1;
+	else {
+		BUG_ON(1);
+		return -EINVAL;
+	}
+}
+
+static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32  enable)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		tabla->rx_bias_count++;
+		if (tabla->rx_bias_count == 1)
+			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
+				0x80, 0x80);
+	} else {
+		tabla->rx_bias_count--;
+		if (!tabla->rx_bias_count)
+			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
+				0x80, 0x00);
+	}
+}
+
+static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
+	int enable)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	if (enable) {
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
+		snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
+		usleep_range(5, 5);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
+			0x80);
+		usleep_range(10, 10);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
+		usleep_range(20, 20);
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
+	} else {
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
+			0);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+	}
+	tabla->config_mode_active = enable ? true : false;
+
+	return 0;
+}
+
+static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
+	int config_mode)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+
+	if (config_mode) {
+		tabla_codec_enable_config_mode(codec, 1);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
+		usleep_range(1000, 1000);
+	} else
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+
+	if (!config_mode && tabla->mbhc_polling_active) {
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+		tabla_codec_enable_config_mode(codec, 0);
+
+	}
+
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
+	snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+	usleep_range(50, 50);
+	tabla->clock_active = true;
+	return 0;
+}
+
+static int tabla_codec_enable_aux_pga(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);
+
+	pr_debug("%s: %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tabla_codec_enable_bandgap(codec,
+					TABLA_BANDGAP_AUDIO_MODE);
+		tabla_enable_rx_bias(codec, 1);
+
+		snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
+						0x08, 0x08);
+		/* Enable Zero Cross detect for AUX PGA channel
+		 * and set the initial AUX PGA gain to NEG_0P0_DB
+		 * to avoid glitches.
+		 */
+		if (w->reg == TABLA_A_AUX_L_EN) {
+			snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
+						0x20, 0x20);
+			tabla->aux_l_gain = snd_soc_read(codec,
+							TABLA_A_AUX_L_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
+		} else {
+			snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
+						0x20, 0x20);
+			tabla->aux_r_gain = snd_soc_read(codec,
+							TABLA_A_AUX_R_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
+		}
+		if (tabla->aux_pga_cnt++ == 1
+			&& !tabla->mclk_enabled) {
+			tabla_codec_enable_clock_block(codec, 1);
+			pr_debug("AUX PGA enabled RC osc\n");
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->reg == TABLA_A_AUX_L_EN)
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
+				tabla->aux_l_gain);
+		else
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
+				tabla->aux_r_gain);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Mute AUX PGA channel in use before disabling AUX PGA */
+		if (w->reg == TABLA_A_AUX_L_EN) {
+			tabla->aux_l_gain = snd_soc_read(codec,
+							TABLA_A_AUX_L_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
+		} else {
+			tabla->aux_r_gain = snd_soc_read(codec,
+							TABLA_A_AUX_R_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		tabla_enable_rx_bias(codec, 0);
+
+		snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
+						0x08, 0x00);
+		if (w->reg == TABLA_A_AUX_L_EN) {
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
+					tabla->aux_l_gain);
+			snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
+							0x20, 0x00);
+		} else {
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
+					tabla->aux_r_gain);
+			snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
+						0x20, 0x00);
+		}
+
+		if (tabla->aux_pga_cnt-- == 0) {
+			if (tabla->mbhc_polling_active)
+				tabla_codec_enable_bandgap(codec,
+					TABLA_BANDGAP_MBHC_MODE);
+			else
+				tabla_codec_enable_bandgap(codec,
+					TABLA_BANDGAP_OFF);
+
+			if (!tabla->mclk_enabled &&
+				!tabla->mbhc_polling_active) {
+				tabla_codec_enable_clock_block(codec, 0);
+			}
+		}
+		break;
+	}
+	return 0;
+}
+
 static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
@@ -1307,45 +1971,64 @@
 	return 0;
 }
 
-
-static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
-{
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
-}
-
+/* called under codec_resource_lock acquisition */
 static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
+	int mbhc_state = tabla->mbhc_state;
 
-	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
-	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
-	if (!tabla->no_mic_headset_override) {
-		tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
-		tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
-	} else {
-		tabla_codec_disable_button_presses(codec);
+	pr_debug("%s: enter\n", __func__);
+	if (!tabla->mbhc_polling_active) {
+		pr_debug("Polling is not active, do not start polling\n");
+		return;
 	}
+	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
+
+	if (!tabla->no_mic_headset_override) {
+		if (mbhc_state == MBHC_STATE_POTENTIAL) {
+			pr_debug("%s recovering MBHC state macine\n", __func__);
+			tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
+			/* set to max button press threshold */
+			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
+				      0x7F);
+			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
+				      0xFF);
+			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
+				      (TABLA_IS_1_X(tabla_core->version) ?
+				       0x07 : 0x7F));
+			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
+				      0xFF);
+			/* set to max */
+			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
+				      0x7F);
+			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
+				      0xFF);
+		}
+	}
+
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
+	pr_debug("%s: leave\n", __func__);
 }
 
+/* called under codec_resource_lock acquisition */
 static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
-	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
-	if (!tabla->no_mic_headset_override) {
-		tabla_disable_irq(codec->control_data,
-			TABLA_IRQ_MBHC_POTENTIAL);
-		tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+	pr_debug("%s: enter\n", __func__);
+	if (!tabla->mbhc_polling_active) {
+		pr_debug("polling not active, nothing to pause\n");
+		return;
 	}
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+	pr_debug("%s: leave\n", __func__);
 }
 
-static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
-		int mode)
+static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	u8 reg_mode_val, cur_mode_val;
@@ -1360,6 +2043,7 @@
 					tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
 
 	if (cur_mode_val != reg_mode_val) {
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 		if (tabla->mbhc_polling_active) {
 			tabla_codec_pause_hs_polling(codec);
 			mbhc_was_polling = true;
@@ -1368,6 +2052,7 @@
 			tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
 		if (mbhc_was_polling)
 			tabla_codec_start_hs_polling(codec);
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 		pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
 			cur_mode_val, reg_mode_val);
 	} else {
@@ -1483,17 +2168,18 @@
 	return (hph_reg_val & 0xC0) ? true : false;
 }
 
+/* called under codec_resource_lock acquisition */
 static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
-	int vddio_switch)
+				       int vddio_switch)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	int cfilt_k_val;
-	bool mbhc_was_polling =  false;
+	bool mbhc_was_polling = false;
 
 	switch (vddio_switch) {
 	case 1:
-		if (tabla->mbhc_polling_active) {
-
+		if (tabla->mbhc_micbias_switched == 0 &&
+		    tabla->mbhc_polling_active) {
 			tabla_codec_pause_hs_polling(codec);
 			/* VDDIO switch enabled */
 			tabla->cfilt_k_value = snd_soc_read(codec,
@@ -1584,9 +2270,11 @@
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Decide whether to switch the micbias for MBHC */
-		if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
-				&& tabla->mbhc_micbias_switched)
+		if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
+			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 			tabla_codec_switch_micbias(codec, 0);
+			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		}
 
 		snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
 		tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
@@ -1600,18 +2288,25 @@
 
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+
+		usleep_range(20000, 20000);
+
 		if (tabla->mbhc_polling_active &&
-		    tabla->micbias == micb_line) {
+		    tabla->mbhc_cfg.micbias == micb_line) {
+			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 			tabla_codec_pause_hs_polling(codec);
 			tabla_codec_start_hs_polling(codec);
+			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 		}
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-
-		if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
-				&& tabla_is_hph_pa_on(codec))
+		if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
+		    tabla_is_hph_pa_on(codec)) {
+			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 			tabla_codec_switch_micbias(codec, 1);
+			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		}
 
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
@@ -1627,14 +2322,73 @@
 	return 0;
 }
 
+
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct tabla_priv *tabla;
+	struct snd_soc_codec *codec;
+	u16 tx_mux_ctl_reg;
+	u8 hpf_cut_of_freq;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	tabla = hpf_work->tabla;
+	codec = hpf_work->tabla->codec;
+	hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+	tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
+			(hpf_work->decimator - 1) * 8;
+
+	pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
+		hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+#define  TX_MUX_CTL_CUT_OFF_FREQ_MASK	0x30
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
+
 static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 dec_reset_reg;
+	unsigned int decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	int ret = 0;
+	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+	u8 dec_hpf_cut_of_freq;
 
 	pr_debug("%s %d\n", __func__, event);
 
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
+	if (ret < 0) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+			w->name, dec_name, decimator);
+
 	if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
 		dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
 	else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
@@ -1644,14 +2398,68 @@
 		return -EINVAL;
 	}
 
+	tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
+	tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+
+		// Enableable TX digital mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+
 		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
 			1 << w->shift);
 		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+
+		dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+
+		dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
+
+		tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+			dec_hpf_cut_of_freq;
+
+		if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
+
+			/* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
+			snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+					    CF_MIN_3DB_150HZ << 4);
+		}
+
+		/* enable HPF */
+		snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+
+		/* Disable TX digital mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+
+		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+				CF_MIN_3DB_150HZ) {
+
+			schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+					msecs_to_jiffies(300));
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+
 		break;
 	}
-	return 0;
+out:
+	kfree(widget_name);
+	return ret;
 }
 
 static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
@@ -1684,24 +2492,6 @@
 	return 0;
 }
 
-
-static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32  enable)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	if (enable) {
-		tabla->rx_bias_count++;
-		if (tabla->rx_bias_count == 1)
-			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
-				0x80, 0x80);
-	} else {
-		tabla->rx_bias_count--;
-		if (!tabla->rx_bias_count)
-			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
-				0x80, 0x00);
-	}
-}
-
 static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -1742,20 +2532,25 @@
 				      int mask)
 {
 	/* XXX: wake_lock_timeout()? */
-	snd_soc_jack_report(jack, status, mask);
+	snd_soc_jack_report_no_dapm(jack, status, mask);
 }
 
 static void hphocp_off_report(struct tabla_priv *tabla,
 	u32 jack_status, int irq)
 {
 	struct snd_soc_codec *codec;
+	if (!tabla) {
+		pr_err("%s: Bad tabla private data\n", __func__);
+		return;
+	}
 
-	if (tabla) {
-		pr_info("%s: clear ocp status %x\n", __func__, jack_status);
-		codec = tabla->codec;
+	pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
+	codec = tabla->codec;
+	if (tabla->hph_status & jack_status) {
 		tabla->hph_status &= ~jack_status;
-		if (tabla->headset_jack)
-			tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
+		if (tabla->mbhc_cfg.headset_jack)
+			tabla_snd_soc_jack_report(tabla,
+						  tabla->mbhc_cfg.headset_jack,
 						  tabla->hph_status,
 						  TABLA_JACK_MASK);
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
@@ -1767,9 +2562,7 @@
 			tabla->hphlocp_cnt = 0;
 		else
 			tabla->hphrocp_cnt = 0;
-		tabla_enable_irq(codec->control_data, irq);
-	} else {
-		pr_err("%s: Bad tabla private data\n", __func__);
+		wcd9xxx_enable_irq(codec->control_data, irq);
 	}
 }
 
@@ -1800,10 +2593,11 @@
 		mbhc_micb_ctl_val = snd_soc_read(codec,
 				tabla->mbhc_bias_regs.ctl_reg);
 
-		if (!(mbhc_micb_ctl_val & 0x80)
-				&& !tabla->mbhc_micbias_switched)
+		if (!(mbhc_micb_ctl_val & 0x80)) {
+			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 			tabla_codec_switch_micbias(codec, 1);
-
+			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		}
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
@@ -1828,13 +2622,13 @@
 				schedule_work(&tabla->hphrocp_work);
 		}
 
-		if (tabla->mbhc_micbias_switched)
-			tabla_codec_switch_micbias(codec, 0);
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		tabla_codec_switch_micbias(codec, 0);
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 
 		pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
 				w->name);
 		usleep_range(10000, 10000);
-
 		break;
 	}
 	return 0;
@@ -1846,7 +2640,7 @@
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	unsigned int cfilt;
 
-	switch (tabla->micbias) {
+	switch (tabla->mbhc_cfg.micbias) {
 	case TABLA_MICBIAS1:
 		cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
 		micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
@@ -1925,16 +2719,16 @@
 
 static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
-			       0, tabla_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
+				0, tabla_codec_enable_micbias,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
-			       0, tabla_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
+				0, tabla_codec_enable_micbias,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route audio_i2s_map[] = {
@@ -2006,10 +2800,10 @@
 	{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
 	{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
 
-
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
-	{"EAR PA", NULL, "DAC1"},
+	{"EAR PA", NULL, "EAR_PA_MIXER"},
+	{"EAR_PA_MIXER", NULL, "DAC1"},
 	{"DAC1", NULL, "CP"},
 
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
@@ -2020,8 +2814,11 @@
 	{"HEADPHONE", NULL, "HPHL"},
 	{"HEADPHONE", NULL, "HPHR"},
 
-	{"HPHL", NULL, "HPHL DAC"},
-	{"HPHR", NULL, "HPHR DAC"},
+	{"HPHL", NULL, "HPHL_PA_MIXER"},
+	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+
+	{"HPHR", NULL, "HPHR_PA_MIXER"},
+	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
 
 	{"HPHL DAC", NULL, "CP"},
 	{"HPHR DAC", NULL, "CP"},
@@ -2049,11 +2846,16 @@
 	{"LINEOUT4", NULL, "LINEOUT4 PA"},
 	{"LINEOUT5", NULL, "LINEOUT5 PA"},
 
-	{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
-	{"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
-	{"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
-	{"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
-	{"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
+	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
+	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
+	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
+	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
+	{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
+	{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
+	{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
+	{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
+	{"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
+	{"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
 
 	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 	{"LINEOUT5 DAC", NULL, "RX7 MIX1"},
@@ -2070,6 +2872,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"},
@@ -2221,6 +3029,42 @@
 	{"ADC5", NULL, "AMIC5"},
 	{"ADC6", NULL, "AMIC6"},
 
+	/* AUX PGA Connections */
+	{"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"AUX_PGA_Left", NULL, "AMIC5"},
+	{"AUX_PGA_Right", NULL, "AMIC6"},
+
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
 	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
@@ -2284,7 +3128,7 @@
 static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
 {
 	int i;
-	struct tabla *tabla_core = dev_get_drvdata(ssc->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
 
 	if (TABLA_IS_1_X(tabla_core->version)) {
 		for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
@@ -2323,7 +3167,6 @@
 	unsigned int value)
 {
 	int ret;
-
 	BUG_ON(reg > TABLA_MAX_REGISTER);
 
 	if (!tabla_volatile(codec, reg)) {
@@ -2333,7 +3176,7 @@
 				reg, ret);
 	}
 
-	return tabla_reg_write(codec->control_data, reg, value);
+	return wcd9xxx_reg_write(codec->control_data, reg, value);
 }
 static unsigned int tabla_read(struct snd_soc_codec *codec,
 				unsigned int reg)
@@ -2353,155 +3196,16 @@
 				reg, ret);
 	}
 
-	val = tabla_reg_read(codec->control_data, reg);
+	val = wcd9xxx_reg_read(codec->control_data, reg);
 	return val;
 }
 
-static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
-{
-	snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x80);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
-		0x04);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
-		0x01);
-	usleep_range(1000, 1000);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x00);
-}
-
-static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
-	enum tabla_bandgap_type choice)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	/* TODO lock resources accessed by audio streams and threaded
-	 * interrupt handlers
-	 */
-
-	pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
-		tabla->bandgap_type);
-
-	if (tabla->bandgap_type == choice)
-		return;
-
-	if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
-		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
-		tabla_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
-			0x2);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-			0x80);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
-			0x4);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
-			0x01);
-		usleep_range(1000, 1000);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-			0x00);
-	} else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
-		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
-		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
-		usleep_range(100, 100);
-		tabla_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == TABLA_BANDGAP_OFF) {
-		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
-	} else {
-		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
-	}
-	tabla->bandgap_type = choice;
-}
-
-static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
-	int enable)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	if (enable) {
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
-		snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
-		usleep_range(5, 5);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
-			0x80);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
-			0x80);
-		usleep_range(10, 10);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
-		usleep_range(20, 20);
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
-	} else {
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
-			0);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
-	}
-	tabla->config_mode_active = enable ? true : false;
-
-	return 0;
-}
-
-static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
-	int config_mode)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
-
-	if (config_mode) {
-		tabla_codec_enable_config_mode(codec, 1);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
-		usleep_range(1000, 1000);
-	} else
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
-
-	if (!config_mode && tabla->mbhc_polling_active) {
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		tabla_codec_enable_config_mode(codec, 0);
-
-	}
-
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
-	snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
-	usleep_range(50, 50);
-	tabla->clock_active = true;
-	return 0;
-}
-static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	pr_debug("%s\n", __func__);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
-	ndelay(160);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
-	tabla->clock_active = false;
-}
-
-static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
-{
-	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
-		return 0;
-	else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
-		return 1;
-	else {
-		BUG_ON(1);
-		return -EINVAL;
-	}
-}
-
 static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
 {
 	u8 *n_ready, *n_cic;
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
 
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
 		      tabla->mbhc_data.v_ins_hu & 0xFF);
@@ -2543,8 +3247,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;
 }
@@ -2552,16 +3261,25 @@
 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)
+int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
 
+	if (dapm)
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 	if (mclk_enable) {
 		tabla->mclk_enabled = true;
 
@@ -2580,6 +3298,8 @@
 	} else {
 
 		if (!tabla->mclk_enabled) {
+			if (dapm)
+				TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 			pr_err("Error, MCLK already diabled\n");
 			return -EINVAL;
 		}
@@ -2603,6 +3323,8 @@
 				TABLA_BANDGAP_OFF);
 		}
 	}
+	if (dapm)
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 	return 0;
 }
 
@@ -2622,7 +3344,7 @@
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* CPU is master */
-		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			if (dai->id == AIF1_CAP)
 				snd_soc_update_bits(dai->codec,
 					TABLA_A_CDC_CLK_TX_I2S_CTL,
@@ -2635,7 +3357,7 @@
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 	/* CPU is slave */
-		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			val = TABLA_I2S_MASTER_MODE_MASK;
 			if (dai->id == AIF1_CAP)
 				snd_soc_update_bits(dai->codec,
@@ -2685,7 +3407,7 @@
 				unsigned int *rx_num, unsigned int *rx_slot)
 
 {
-	struct tabla *tabla = dev_get_drvdata(dai->codec->control_data);
+	struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
 
 	u32 cnt = 0;
 	u32 tx_ch[SLIM_MAX_TX_PORTS];
@@ -2699,7 +3421,7 @@
 	/* for virtual port, codec driver needs to do
 	 * housekeeping, for now should be ok
 	 */
-	tabla_get_channel(tabla, rx_ch, tx_ch);
+	wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
 	if (dai->id == AIF1_PB) {
 		*rx_num = tabla_dai[dai->id - 1].playback.channels_max;
 		while (cnt < *rx_num) {
@@ -2731,6 +3453,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));
@@ -2739,18 +3462,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__,
@@ -2784,7 +3511,7 @@
 							0x03, tx_fs_rate);
 			}
 		}
-		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			switch (params_format(params)) {
 			case SNDRV_PCM_FORMAT_S16_LE:
 				snd_soc_update_bits(codec,
@@ -2828,9 +3555,12 @@
 						+ (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 == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			switch (params_format(params)) {
 			case SNDRV_PCM_FORMAT_S16_LE:
 				snd_soc_update_bits(codec,
@@ -2945,7 +3675,7 @@
 static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct tabla *tabla;
+	struct wcd9xxx *tabla;
 	struct snd_soc_codec *codec = w->codec;
 	struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
 	u32  j = 0;
@@ -2953,7 +3683,7 @@
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	tabla = codec->control_data;
 	/* Execute the callback only if interface type is slimbus */
-	if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+	if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		return 0;
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -2967,10 +3697,10 @@
 			}
 		}
 		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
-			ret = tabla_cfg_slim_sch_rx(tabla,
-						tabla_p->dai[j].ch_num,
-						tabla_p->dai[j].ch_tot,
-						tabla_p->dai[j].rate);
+			ret = wcd9xxx_cfg_slim_sch_rx(tabla,
+					tabla_p->dai[j].ch_num,
+					tabla_p->dai[j].ch_tot,
+					tabla_p->dai[j].rate);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
@@ -2983,12 +3713,13 @@
 			}
 		}
 		if (!tabla_p->dai[j].ch_act) {
-			ret = tabla_close_slim_sch_rx(tabla,
+			ret = wcd9xxx_close_slim_sch_rx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot);
+			usleep_range(5000, 5000);
 			tabla_p->dai[j].rate = 0;
 			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
-						tabla_p->dai[j].ch_tot));
+					tabla_p->dai[j].ch_tot));
 			tabla_p->dai[j].ch_tot = 0;
 		}
 	}
@@ -2998,7 +3729,7 @@
 static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct tabla *tabla;
+	struct wcd9xxx *tabla;
 	struct snd_soc_codec *codec = w->codec;
 	struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
 	/* index to the DAI ID, for now hardcoding */
@@ -3009,7 +3740,7 @@
 	tabla = codec->control_data;
 
 	/* Execute the callback only if interface type is slimbus */
-	if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+	if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		return 0;
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -3024,7 +3755,7 @@
 			}
 		}
 		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
-			ret = tabla_cfg_slim_sch_tx(tabla,
+			ret = wcd9xxx_cfg_slim_sch_tx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot,
 						tabla_p->dai[j].rate);
@@ -3041,12 +3772,12 @@
 			}
 		}
 		if (!tabla_p->dai[j].ch_act) {
-			ret = tabla_close_slim_sch_tx(tabla,
+			ret = wcd9xxx_close_slim_sch_tx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot);
 			tabla_p->dai[j].rate = 0;
 			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
-						tabla_p->dai[j].ch_tot));
+					tabla_p->dai[j].ch_tot));
 			tabla_p->dai[j].ch_tot = 0;
 		}
 	}
@@ -3212,6 +3943,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 |
@@ -3245,34 +3983,54 @@
 		tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
-		&dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec1_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
-		&dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec2_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
-		&dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec3_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
-		&dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec4_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
-		&dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec5_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
-		&dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec6_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
-		&dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec7_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
-		&dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec8_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
-		&dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec9_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
-		&dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+		&dec10_mux, tabla_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
 	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
@@ -3368,6 +4126,42 @@
 	/* Sidetone */
 	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
 	SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+
+	/* AUX PGA */
+	SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
+		tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
+		tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* Lineout, ear and HPH PA Mixers */
+	SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
 };
 
 static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
@@ -3392,13 +4186,24 @@
 	return bias_value;
 }
 
-static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
+static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
 {
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
+}
+
+static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+				   bool override_bypass, bool noreldetection)
+{
 	short bias_value;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	if (noreldetection)
+		tabla_turn_onoff_rel_detection(codec, false);
 
 	/* Turn on the override */
-	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
+	if (!override_bypass)
+		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
 	if (dce) {
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
@@ -3423,24 +4228,34 @@
 		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
 	}
 	/* Turn off the override after measuring mic voltage */
-	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+	if (!override_bypass)
+		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+
+	if (noreldetection)
+		tabla_turn_onoff_rel_detection(codec, true);
+	wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
 
 	return bias_value;
 }
 
+static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+				 bool norel)
+{
+	return __tabla_codec_sta_dce(codec, dce, false, norel);
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
 static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	short bias_value;
 	u8 cfilt_mode;
 
-	if (!tabla->calibration) {
+	if (!tabla->mbhc_cfg.calibration) {
 		pr_err("Error, no tabla calibration\n");
 		return -ENODEV;
 	}
 
-	tabla->mbhc_polling_active = true;
-
 	if (!tabla->mclk_enabled) {
 		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
 		tabla_enable_rx_bias(codec, 1);
@@ -3449,8 +4264,6 @@
 
 	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
 
-	snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
-
 	/* Make sure CFILT is in fast mode, save current mode */
 	cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
@@ -3473,7 +4286,8 @@
 
 	tabla_codec_calibrate_hs_polling(codec);
 
-	bias_value = tabla_codec_sta_dce(codec, 0);
+	/* don't flip override */
+	bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
 			    cfilt_mode);
 	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
@@ -3481,60 +4295,225 @@
 	return bias_value;
 }
 
+static int tabla_cancel_btn_work(struct tabla_priv *tabla)
+{
+	int r = 0;
+	struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
+
+	if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
+		/* if scheduled mbhc_btn_dwork is canceled from here,
+		* we have to unlock from here instead btn_work */
+		wcd9xxx_unlock_sleep(core);
+		r = 1;
+	}
+	return r;
+}
+
+/* called under codec_resource_lock acquisition */
+void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	u8 wg_time;
+
+	wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
+	wg_time += 1;
+
+	/* If headphone PA is on, check if userspace receives
+	 * removal event to sync-up PA's state */
+	if (tabla_is_hph_pa_on(codec)) {
+		pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
+		set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
+		set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
+	} else {
+		pr_debug("%s PA is off\n", __func__);
+	}
+
+	if (tabla_is_hph_dac_on(codec, 1))
+		set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
+	if (tabla_is_hph_dac_on(codec, 0))
+		set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
+
+	snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
+			    0xC0, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
+			    0xC0, 0x00);
+	usleep_range(wg_time * 1000, wg_time * 1000);
+}
+
+static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
+{
+	bool pa_turned_on = false;
+	struct snd_soc_codec *codec = tabla->codec;
+	u8 wg_time;
+
+	wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
+	wg_time += 1;
+
+	if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
+				    0xC0, 0xC0);
+	}
+	if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
+				    0xC0, 0xC0);
+	}
+
+	if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
+				    1 << 4);
+		pa_turned_on = true;
+	}
+	if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
+				    1 << 5);
+		pa_turned_on = true;
+	}
+
+	if (pa_turned_on) {
+		pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
+				__func__);
+		usleep_range(wg_time * 1000, wg_time * 1000);
+	}
+}
+
+/* called under codec_resource_lock acquisition */
+static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
+				    enum snd_jack_types jack_type)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	if (!insertion) {
+		/* Report removal */
+		tabla->hph_status &= ~jack_type;
+		if (tabla->mbhc_cfg.headset_jack) {
+			/* cancel possibly scheduled btn work and
+			* report release if we reported button press */
+			if (tabla_cancel_btn_work(tabla)) {
+				pr_debug("%s: button press is canceled\n",
+					__func__);
+			} else if (tabla->buttons_pressed) {
+				pr_debug("%s: Reporting release for reported "
+					 "button press %d\n", __func__,
+					 jack_type);
+				tabla_snd_soc_jack_report(tabla,
+						 tabla->mbhc_cfg.button_jack, 0,
+						 tabla->buttons_pressed);
+				tabla->buttons_pressed &=
+							~TABLA_JACK_BUTTON_MASK;
+			}
+			pr_debug("%s: Reporting removal %d\n", __func__,
+				 jack_type);
+			tabla_snd_soc_jack_report(tabla,
+						  tabla->mbhc_cfg.headset_jack,
+						  tabla->hph_status,
+						  TABLA_JACK_MASK);
+		}
+		tabla_set_and_turnoff_hph_padac(codec);
+		hphocp_off_report(tabla, SND_JACK_OC_HPHR,
+				  TABLA_IRQ_HPH_PA_OCPR_FAULT);
+		hphocp_off_report(tabla, SND_JACK_OC_HPHL,
+				  TABLA_IRQ_HPH_PA_OCPL_FAULT);
+		tabla->current_plug = PLUG_TYPE_NONE;
+		tabla->mbhc_polling_active = false;
+	} else {
+		/* Report insertion */
+		tabla->hph_status |= jack_type;
+
+		if (jack_type == SND_JACK_HEADPHONE)
+			tabla->current_plug = PLUG_TYPE_HEADPHONE;
+		else if (jack_type == SND_JACK_HEADSET) {
+			tabla->mbhc_polling_active = true;
+			tabla->current_plug = PLUG_TYPE_HEADSET;
+		}
+		if (tabla->mbhc_cfg.headset_jack) {
+			pr_debug("%s: Reporting insertion %d\n", __func__,
+				 jack_type);
+			tabla_snd_soc_jack_report(tabla,
+						  tabla->mbhc_cfg.headset_jack,
+						  tabla->hph_status,
+						  TABLA_JACK_MASK);
+		}
+		tabla_clr_and_turnon_hph_padac(tabla);
+	}
+}
+
 static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
-		int insertion)
+					int insertion, int trigger,
+					bool padac_off)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	int central_bias_enabled = 0;
 	const struct tabla_mbhc_general_cfg *generic =
-	    TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
+	    TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
 	const struct tabla_mbhc_plug_detect_cfg *plug_det =
-	    TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
-	u8 wg_time;
+	    TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
 
-	if (!tabla->calibration) {
+	if (!tabla->mbhc_cfg.calibration) {
 		pr_err("Error, no tabla calibration\n");
 		return -EINVAL;
 	}
 
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
 
+	/* Make sure mic bias and Mic line schmitt trigger
+	 * are turned OFF
+	 */
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
+
 	if (insertion) {
-		/* Make sure mic bias and Mic line schmitt trigger
-		 * are turned OFF
-		 */
-		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
-			0x81, 0x01);
-		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
-			0x90, 0x00);
-		wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
-		wg_time += 1;
+		tabla_codec_switch_micbias(codec, 0);
 
-		/* Enable HPH Schmitt Trigger */
-		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
-		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
-				    plug_det->hph_current << 2);
+		/* DAPM can manipulate PA/DAC bits concurrently */
+		if (padac_off == true) {
+			tabla_set_and_turnoff_hph_padac(codec);
+		}
 
-		/* Turn off HPH PAs and DAC's during insertion detection to
-		 * avoid false insertion interrupts
-		 */
-		if (tabla->mbhc_micbias_switched)
-			tabla_codec_switch_micbias(codec, 0);
-		snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
-		snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
-				    0xC0, 0x00);
-		snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
-				    0xC0, 0x00);
-		usleep_range(wg_time * 1000, wg_time * 1000);
+		if (trigger == MBHC_USE_HPHL_TRIGGER) {
+			/* Enable HPH Schmitt Trigger */
+			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
+					    0x11);
+			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
+					    plug_det->hph_current << 2);
+			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
+					    0x02);
+		} else if (trigger == MBHC_USE_MB_TRIGGER) {
+			/* enable the mic line schmitt trigger */
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.mbhc_reg,
+					    0x60, plug_det->mic_current << 5);
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.mbhc_reg,
+					    0x80, 0x80);
+			usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.ctl_reg, 0x01,
+					    0x00);
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.mbhc_reg,
+					    0x10, 0x10);
+		}
 
 		/* setup for insetion detection */
-		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
+
 	} else {
+		pr_debug("setup for removal detection\n");
 		/* Make sure the HPH schmitt trigger is OFF */
 		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
 
 		/* enable the mic line schmitt trigger */
+		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
+				    0x01, 0x00);
 		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
 				    plug_det->mic_current << 5);
 		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
@@ -3548,6 +4527,7 @@
 	}
 
 	if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
+		/* called called by interrupt */
 		if (!(tabla->clock_active)) {
 			tabla_codec_enable_config_mode(codec, 1);
 			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
@@ -3582,9 +4562,9 @@
 	}
 
 	snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
-			    tabla->micbias);
+			    tabla->mbhc_cfg.micbias);
 
-	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
 	return 0;
 }
@@ -3592,9 +4572,10 @@
 static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
 				 s16 vin_mv)
 {
-	short diff, zero;
 	struct tabla_priv *tabla;
+	s16 diff, zero;
 	u32 mb_mv, in;
+	u16 value;
 
 	tabla = snd_soc_codec_get_drvdata(codec);
 	mb_mv = tabla->mbhc_data.micb_mv;
@@ -3605,72 +4586,76 @@
 	}
 
 	if (dce) {
-		diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
-		zero = tabla->mbhc_data.dce_z;
+		diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
+		zero = (tabla->mbhc_data.dce_z);
 	} else {
-		diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
-		zero = tabla->mbhc_data.sta_z;
+		diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
+		zero = (tabla->mbhc_data.sta_z);
 	}
 	in = (u32) diff * vin_mv;
 
-	return (u16) (in / mb_mv) + zero;
+	value = (u16) (in / mb_mv) + zero;
+	return value;
 }
 
 static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
 				 u16 bias_value)
 {
 	struct tabla_priv *tabla;
+	s16 value, z, mb;
 	s32 mv;
 
 	tabla = snd_soc_codec_get_drvdata(codec);
-
+	value = bias_value;
 	if (dce) {
-		mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
-		     (s32)tabla->mbhc_data.micb_mv /
-		     (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
+		z = (tabla->mbhc_data.dce_z);
+		mb = (tabla->mbhc_data.dce_mb);
+		mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
 	} else {
-		mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
-		     (s32)tabla->mbhc_data.micb_mv /
-		     (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
+		z = (tabla->mbhc_data.sta_z);
+		mb = (tabla->mbhc_data.sta_mb);
+		mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
 	}
 
 	return mv;
 }
 
-static void btn0_lpress_fn(struct work_struct *work)
+static void btn_lpress_fn(struct work_struct *work)
 {
 	struct delayed_work *delayed_work;
 	struct tabla_priv *tabla;
 	short bias_value;
 	int dce_mv, sta_mv;
-	struct tabla *core;
+	struct wcd9xxx *core;
 
 	pr_debug("%s:\n", __func__);
 
 	delayed_work = to_delayed_work(work);
-	tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
+	tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
 	core = dev_get_drvdata(tabla->codec->dev->parent);
 
 	if (tabla) {
-		if (tabla->button_jack) {
+		if (tabla->mbhc_cfg.button_jack) {
 			bias_value = tabla_codec_read_sta_result(tabla->codec);
 			sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
-						       bias_value);
+						bias_value);
 			bias_value = tabla_codec_read_dce_result(tabla->codec);
 			dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
-						       bias_value);
+						bias_value);
 			pr_debug("%s: Reporting long button press event"
 				 " STA: %d, DCE: %d\n", __func__,
 				 sta_mv, dce_mv);
-			tabla_snd_soc_jack_report(tabla, tabla->button_jack,
-						  SND_JACK_BTN_0,
-						  SND_JACK_BTN_0);
+			tabla_snd_soc_jack_report(tabla,
+						  tabla->mbhc_cfg.button_jack,
+						  tabla->buttons_pressed,
+						  tabla->buttons_pressed);
 		}
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
 	}
 
-	tabla_unlock_sleep(core);
+	pr_debug("%s: leave\n", __func__);
+	wcd9xxx_unlock_sleep(core);
 }
 
 void tabla_mbhc_cal(struct snd_soc_codec *codec)
@@ -3682,19 +4667,24 @@
 	u32 mclk_rate;
 	u32 dce_wait, sta_wait;
 	u8 *n_cic;
+	void *calibration;
 
 	tabla = snd_soc_codec_get_drvdata(codec);
+	calibration = tabla->mbhc_cfg.calibration;
+
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	tabla_turn_onoff_rel_detection(codec, false);
 
 	/* First compute the DCE / STA wait times
 	 * depending on tunable parameters.
 	 * The value is computed in microseconds
 	 */
-	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
 	ncic = n_cic[tabla_codec_mclk_index(tabla)];
-	nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
-	navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
-	mclk_rate = tabla->mclk_freq;
+	nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
+	navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
+	mclk_rate = tabla->mbhc_cfg.mclk_rate;
 	dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
 	sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
 
@@ -3714,7 +4704,7 @@
 	 * to perform ADC calibration
 	 */
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
-			    tabla->micbias << 5);
+			    tabla->mbhc_cfg.micbias << 5);
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
 	snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
 	snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
@@ -3764,6 +4754,9 @@
 
 	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
 	usleep_range(100, 100);
+
+	wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	tabla_turn_onoff_rel_detection(codec, true);
 }
 
 void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
@@ -3801,19 +4794,20 @@
 	int i;
 
 	tabla = snd_soc_codec_get_drvdata(codec);
-	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
-	plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
+	plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
 
 	n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
-	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
-		tabla->mbhc_data.npoll = 9;
+	if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
+		tabla->mbhc_data.npoll = 4;
 		tabla->mbhc_data.nbounce_wait = 30;
-	} else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
+	} else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
 		tabla->mbhc_data.npoll = 7;
 		tabla->mbhc_data.nbounce_wait = 23;
 	}
 
-	tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
+	tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
+				      (tabla->mbhc_cfg.mclk_rate / 1000) *
 				      n_ready[tabla_codec_mclk_index(tabla)]) +
 				     10;
 	tabla->mbhc_data.v_ins_hu =
@@ -3837,7 +4831,7 @@
 	    tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
 
 	tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
-	tabla->mbhc_data.v_brl = 0xFA55;
+	tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
 
 	tabla->mbhc_data.v_no_mic =
 	    tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
@@ -3850,11 +4844,11 @@
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	int n;
 	u8 *n_cic, *gain;
-	struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
 
 	tabla = snd_soc_codec_get_drvdata(codec);
-	generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
-	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+	generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
 
 	for (n = 0; n < 8; n++) {
 		if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
@@ -3893,6 +4887,8 @@
 			    TABLA_MICBIAS2);
 
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+
+	snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
 }
 
 static bool tabla_mbhc_fw_validate(const struct firmware *fw)
@@ -3926,126 +4922,6 @@
 
 	return true;
 }
-static void mbhc_fw_read(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	struct tabla_priv *tabla;
-	struct snd_soc_codec *codec;
-	const struct firmware *fw;
-	int ret = -1, retry = 0, rc;
-
-	dwork = to_delayed_work(work);
-	tabla = container_of(dwork, struct tabla_priv,
-				mbhc_firmware_dwork);
-	codec = tabla->codec;
-
-	while (retry < MBHC_FW_READ_ATTEMPTS) {
-		retry++;
-		pr_info("%s:Attempt %d to request MBHC firmware\n",
-			__func__, retry);
-		ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
-					codec->dev);
-
-		if (ret != 0) {
-			usleep_range(MBHC_FW_READ_TIMEOUT,
-					MBHC_FW_READ_TIMEOUT);
-		} else {
-			pr_info("%s: MBHC Firmware read succesful\n", __func__);
-			break;
-		}
-	}
-
-	if (ret != 0) {
-		pr_err("%s: Cannot load MBHC firmware use default cal\n",
-			__func__);
-	} else if (tabla_mbhc_fw_validate(fw) == false) {
-		pr_err("%s: Invalid MBHC cal data size use default cal\n",
-			 __func__);
-		release_firmware(fw);
-	} else {
-		tabla->calibration = (void *)fw->data;
-		tabla->mbhc_fw = fw;
-	}
-
-	tabla->mclk_cb(codec, 1);
-	tabla_mbhc_init(codec);
-	tabla_mbhc_cal(codec);
-	tabla_mbhc_calc_thres(codec);
-	tabla->mclk_cb(codec, 0);
-	tabla_codec_calibrate_hs_polling(codec);
-	rc = tabla_codec_enable_hs_detect(codec, 1);
-
-	if (IS_ERR_VALUE(rc))
-		pr_err("%s: Failed to setup MBHC detection\n", __func__);
-
-}
-
-int tabla_hs_detect(struct snd_soc_codec *codec,
-		    struct snd_soc_jack *headset_jack,
-		    struct snd_soc_jack *button_jack,
-		    void *calibration, enum tabla_micbias_num micbias,
-		    int (*mclk_cb_fn) (struct snd_soc_codec*, int),
-		    int read_fw_bin, u32 mclk_rate)
-{
-	struct tabla_priv *tabla;
-	int rc = 0;
-
-	if (!codec || !calibration) {
-		pr_err("Error: no codec or calibration\n");
-		return -EINVAL;
-	}
-
-	if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
-		if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
-			pr_err("Error: clock rate %dHz is not yet supported\n",
-			       mclk_rate);
-		else
-			pr_err("Error: unsupported clock rate %d\n", mclk_rate);
-		return -EINVAL;
-	}
-
-	tabla = snd_soc_codec_get_drvdata(codec);
-	tabla->headset_jack = headset_jack;
-	tabla->button_jack = button_jack;
-	tabla->micbias = micbias;
-	tabla->calibration = calibration;
-	tabla->mclk_cb = mclk_cb_fn;
-	tabla->mclk_freq = mclk_rate;
-	tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
-
-	/* Put CFILT in fast mode by default */
-	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
-		0x40, TABLA_CFILT_FAST_MODE);
-	INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
-	INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
-	INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
-	INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
-
-	if (!read_fw_bin) {
-		tabla->mclk_cb(codec, 1);
-		tabla_mbhc_init(codec);
-		tabla_mbhc_cal(codec);
-		tabla_mbhc_calc_thres(codec);
-		tabla->mclk_cb(codec, 0);
-		tabla_codec_calibrate_hs_polling(codec);
-		rc =  tabla_codec_enable_hs_detect(codec, 1);
-	} else {
-		schedule_delayed_work(&tabla->mbhc_firmware_dwork,
-				usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
-	}
-
-	if (!IS_ERR_VALUE(rc)) {
-		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
-			0x10);
-		tabla_enable_irq(codec->control_data,
-			TABLA_IRQ_HPH_PA_OCPL_FAULT);
-		tabla_enable_irq(codec->control_data,
-			TABLA_IRQ_HPH_PA_OCPR_FAULT);
-	}
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(tabla_hs_detect);
 
 static int tabla_determine_button(const struct tabla_priv *priv,
 				  const s32 bias_mv)
@@ -4054,10 +4930,10 @@
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	int i, btn = -1;
 
-	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
 	v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
 	v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
-					       TABLA_BTN_DET_V_BTN_HIGH);
+				TABLA_BTN_DET_V_BTN_HIGH);
 	for (i = 0; i < btn_det->num_btn; i++) {
 		if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
 			btn = i;
@@ -4107,30 +4983,72 @@
 static irqreturn_t tabla_dce_handler(int irq, void *data)
 {
 	int i, mask;
-	short bias_value_dce;
-	s32 bias_mv_dce;
+	short dce, sta, bias_value_dce;
+	s32 mv, stamv, bias_mv_dce;
 	int btn = -1, meas = 0;
 	struct tabla_priv *priv = data;
 	const struct tabla_mbhc_btn_detect_cfg *d =
-	    TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+	    TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
 	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
-	struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	int n_btn_meas = d->n_btn_meas;
+	u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
 
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	pr_debug("%s: enter\n", __func__);
 
-	bias_value_dce = tabla_codec_read_dce_result(codec);
-	bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
+	TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
+	if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
+		pr_debug("%s: mbhc is being recovered, skip button press\n",
+			 __func__);
+		goto done;
+	}
+
+	priv->mbhc_state = MBHC_STATE_POTENTIAL;
+
+	if (!priv->mbhc_polling_active) {
+		pr_warn("%s: mbhc polling is not active, skip button press\n",
+			__func__);
+		goto done;
+	}
+
+	dce = tabla_codec_read_dce_result(codec);
+	mv = tabla_codec_sta_dce_v(codec, 1, dce);
+
+	/* If GPIO interrupt already kicked in, ignore button press */
+	if (priv->in_gpio_handler) {
+		pr_debug("%s: GPIO State Changed, ignore button press\n",
+			 __func__);
+		btn = -1;
+		goto done;
+	}
+
+	if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
+		if (priv->mbhc_last_resume &&
+		    !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
+			pr_debug("%s: Button is already released shortly after "
+				 "resume\n", __func__);
+			n_btn_meas = 0;
+		} else {
+			pr_debug("%s: Button is already released without "
+				 "resume", __func__);
+			sta = tabla_codec_read_sta_result(codec);
+			stamv = tabla_codec_sta_dce_v(codec, 0, sta);
+			btn = tabla_determine_button(priv, mv);
+			if (btn != tabla_determine_button(priv, stamv))
+				btn = -1;
+			goto done;
+		}
+	}
 
 	/* determine pressed button */
-	btnmeas[meas++] = tabla_determine_button(priv, bias_mv_dce);
+	btnmeas[meas++] = tabla_determine_button(priv, mv);
 	pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
-		 meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
-	if (d->n_btn_meas == 0)
+		 meas - 1, dce, mv, btnmeas[meas - 1]);
+	if (n_btn_meas == 0)
 		btn = btnmeas[0];
 	for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
-		bias_value_dce = tabla_codec_sta_dce(codec, 1);
+		bias_value_dce = tabla_codec_sta_dce(codec, 1, false);
 		bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
 		btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
 		pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
@@ -4148,104 +5066,129 @@
 				/* button pressed */
 				btn = btnmeas[meas];
 				break;
+			} else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
+				/* if left measurements are less than n_btn_con,
+				 * it's impossible to find button number */
+				break;
 			}
 		}
-		/* if left measurements are less than n_btn_con,
-		 * it's impossible to find button number */
-		if ((d->n_btn_meas - meas) < d->n_btn_con)
-			break;
 	}
 
 	if (btn >= 0) {
+		if (priv->in_gpio_handler) {
+			pr_debug("%s: GPIO already triggered, ignore button "
+				 "press\n", __func__);
+			goto done;
+		}
 		mask = tabla_get_button_mask(btn);
 		priv->buttons_pressed |= mask;
-
-		msleep(100);
-
-		/* XXX: assuming button 0 has the lowest micbias voltage */
-		if (btn == 0) {
-			tabla_lock_sleep(core);
-			if (schedule_delayed_work(&priv->btn0_dwork,
-						  msecs_to_jiffies(400)) == 0) {
-				WARN(1, "Button pressed twice without release"
-				     "event\n");
-				tabla_unlock_sleep(core);
-			}
-		} else {
-			pr_debug("%s: Reporting short button %d(0x%x) press\n",
-				  __func__, btn, mask);
-			tabla_snd_soc_jack_report(priv, priv->button_jack, mask,
-						  mask);
+		wcd9xxx_lock_sleep(core);
+		if (schedule_delayed_work(&priv->mbhc_btn_dwork,
+					  msecs_to_jiffies(400)) == 0) {
+			WARN(1, "Button pressed twice without release"
+			     "event\n");
+			wcd9xxx_unlock_sleep(core);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
 			 __func__);
 	}
 
+ done:
+	pr_debug("%s: leave\n", __func__);
+	TABLA_RELEASE_LOCK(priv->codec_resource_lock);
 	return IRQ_HANDLED;
 }
 
+static int tabla_is_fake_press(struct tabla_priv *priv)
+{
+	int i;
+	int r = 0;
+	struct snd_soc_codec *codec = priv->codec;
+	const int dces = MBHC_NUM_DCE_PLUG_DETECT;
+	short mb_v;
+
+	for (i = 0; i < dces; i++) {
+		usleep_range(10000, 10000);
+		if (i == 0) {
+			mb_v = tabla_codec_sta_dce(codec, 0, true);
+			pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
+				 tabla_codec_sta_dce_v(codec, 0, mb_v));
+			if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
+			    mb_v > (short)priv->mbhc_data.v_ins_hu) {
+				r = 1;
+				break;
+			}
+		} else {
+			mb_v = tabla_codec_sta_dce(codec, 1, true);
+			pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
+				 tabla_codec_sta_dce_v(codec, 1, mb_v));
+			if (mb_v < (short)priv->mbhc_data.v_b1_h ||
+			    mb_v > (short)priv->mbhc_data.v_ins_h) {
+				r = 1;
+				break;
+			}
+		}
+	}
+
+	return r;
+}
+
 static irqreturn_t tabla_release_handler(int irq, void *data)
 {
 	int ret;
-	short mb_v;
 	struct tabla_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
 
 	pr_debug("%s: enter\n", __func__);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 
-	if (priv->buttons_pressed & SND_JACK_BTN_0) {
-		ret = cancel_delayed_work(&priv->btn0_dwork);
+	TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
+	priv->mbhc_state = MBHC_STATE_RELEASE;
+
+	if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
+		ret = tabla_cancel_btn_work(priv);
 		if (ret == 0) {
-			pr_debug("%s: Reporting long button 0 release event\n",
+			pr_debug("%s: Reporting long button release event\n",
 				 __func__);
-			if (priv->button_jack)
+			if (priv->mbhc_cfg.button_jack)
 				tabla_snd_soc_jack_report(priv,
-							  priv->button_jack, 0,
-							  SND_JACK_BTN_0);
+						  priv->mbhc_cfg.button_jack, 0,
+						  priv->buttons_pressed);
 		} else {
-			/* if scheduled btn0_dwork is canceled from here,
-			 * we have to unlock from here instead btn0_work */
-			tabla_unlock_sleep(core);
-			mb_v = tabla_codec_sta_dce(codec, 0);
-			pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
-				 __func__, mb_v,
-				 tabla_codec_sta_dce_v(codec, 0, mb_v));
-
-			if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
-			    mb_v > (short)priv->mbhc_data.v_ins_hu)
-				pr_debug("%s: Fake buttton press interrupt\n",
+			if (tabla_is_fake_press(priv)) {
+				pr_debug("%s: Fake button press interrupt\n",
 					 __func__);
-			else if (priv->button_jack) {
-				pr_debug("%s: Reporting short button 0 "
-					 "press and release\n", __func__);
-				tabla_snd_soc_jack_report(priv,
-							  priv->button_jack,
-							  SND_JACK_BTN_0,
-							  SND_JACK_BTN_0);
-				tabla_snd_soc_jack_report(priv,
-							  priv->button_jack, 0,
-							  SND_JACK_BTN_0);
+			} else if (priv->mbhc_cfg.button_jack) {
+				if (priv->in_gpio_handler) {
+					pr_debug("%s: GPIO kicked in, ignore\n",
+						 __func__);
+				} else {
+					pr_debug("%s: Reporting short button 0 "
+						 "press and release\n",
+						 __func__);
+					tabla_snd_soc_jack_report(priv,
+						     priv->mbhc_cfg.button_jack,
+						     priv->buttons_pressed,
+						     priv->buttons_pressed);
+					tabla_snd_soc_jack_report(priv,
+						  priv->mbhc_cfg.button_jack, 0,
+						  priv->buttons_pressed);
+				}
 			}
 		}
 
-		priv->buttons_pressed &= ~SND_JACK_BTN_0;
-	}
-
-	if (priv->buttons_pressed) {
-		pr_debug("%s:reporting button release mask 0x%x\n", __func__,
-			 priv->buttons_pressed);
-		tabla_snd_soc_jack_report(priv, priv->button_jack, 0,
-					  priv->buttons_pressed);
-		/* hardware doesn't detect another button press until
-		 * already pressed button is released.
-		 * therefore buttons_pressed has only one button's mask. */
 		priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
 	}
 
+	tabla_codec_calibrate_hs_polling(codec);
+
+	if (priv->mbhc_cfg.gpio)
+		msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
+
 	tabla_codec_start_hs_polling(codec);
+
+	pr_debug("%s: leave\n", __func__);
+	TABLA_RELEASE_LOCK(priv->codec_resource_lock);
 	return IRQ_HANDLED;
 }
 
@@ -4253,7 +5196,7 @@
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	const struct tabla_mbhc_general_cfg *generic =
-	    TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
+	    TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
 
 	if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
 		tabla_codec_enable_config_mode(codec, 1);
@@ -4273,19 +5216,19 @@
 	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
 }
 
-static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
+static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	tabla_codec_shutdown_hs_removal_detect(codec);
 
 	if (!tabla->mclk_enabled) {
-		snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
 		tabla_codec_disable_clock_block(codec);
 		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
 	}
 
 	tabla->mbhc_polling_active = false;
+	tabla->mbhc_state = MBHC_STATE_NONE;
 }
 
 static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
@@ -4304,15 +5247,15 @@
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 					    0x10);
 		} else {
-			tabla_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(codec->control_data,
 					  TABLA_IRQ_HPH_PA_OCPL_FAULT);
 			tabla->hphlocp_cnt = 0;
 			tabla->hph_status |= SND_JACK_OC_HPHL;
-			if (tabla->headset_jack)
+			if (tabla->mbhc_cfg.headset_jack)
 				tabla_snd_soc_jack_report(tabla,
-							  tabla->headset_jack,
-							  tabla->hph_status,
-							  TABLA_JACK_MASK);
+						   tabla->mbhc_cfg.headset_jack,
+						   tabla->hph_status,
+						   TABLA_JACK_MASK);
 		}
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
@@ -4337,15 +5280,15 @@
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 					    0x10);
 		} else {
-			tabla_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(codec->control_data,
 					  TABLA_IRQ_HPH_PA_OCPR_FAULT);
 			tabla->hphrocp_cnt = 0;
 			tabla->hph_status |= SND_JACK_OC_HPHR;
-			if (tabla->headset_jack)
+			if (tabla->mbhc_cfg.headset_jack)
 				tabla_snd_soc_jack_report(tabla,
-							  tabla->headset_jack,
-							  tabla->hph_status,
-							  TABLA_JACK_MASK);
+						   tabla->mbhc_cfg.headset_jack,
+						   tabla->hph_status,
+						   TABLA_JACK_MASK);
 		}
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
@@ -4354,254 +5297,956 @@
 	return IRQ_HANDLED;
 }
 
-static void tabla_sync_hph_state(struct tabla_priv *tabla)
+static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
+				       s32 mic_volt)
 {
-	if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
-		pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
-		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
-				    1 << 4);
-	}
-	if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
-		pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
-		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
-				    1 << 5);
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct tabla_mbhc_plug_type_cfg *plug_type =
+		TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
+	int fake_insert_high;
+	bool invalid = false;
+
+	if (tabla->mbhc_cfg.gpio)
+		fake_insert_high = TABLA_MBHC_FAKE_INSERT_HIGH;
+	else
+		fake_insert_high = TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
+
+	/* Perform this check only when the high voltage headphone
+	 * needs to be considered as invalid
+	 */
+	if (!tabla->mbhc_inval_hs_range_override
+		&& (mic_volt > plug_type->v_hs_max)) {
+		invalid = true;
+	} else if (mic_volt < fake_insert_high
+			&& (mic_volt > TABLA_MBHC_FAKE_INSERT_LOW)) {
+		invalid = true;
 	}
 
-	if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
-		pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
-		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
-				    0xC0, 0xC0);
+	return invalid;
+}
+
+static bool tabla_is_invalid_insert_delta(struct snd_soc_codec *codec,
+					int mic_volt, int mic_volt_prev)
+{
+	int delta = abs(mic_volt - mic_volt_prev);
+	if (delta > TABLA_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
+		pr_debug("%s: volt delta %dmv\n", __func__, delta);
+		return true;
 	}
-	if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
-		pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
-		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
-				    0xC0, 0xC0);
+	return false;
+}
+
+static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
+					s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
+					enum tabla_mbhc_plug_type
+					    plug_type[MBHC_NUM_DCE_PLUG_DETECT])
+{
+	int i;
+	bool r = false;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
+		TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
+
+	for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
+		if (mic_mv[i] < plug_type_ptr->v_no_mic)
+			plug_type[i] = PLUG_TYPE_HEADPHONE;
+		else if (mic_mv[i] < plug_type_ptr->v_hs_max)
+			plug_type[i] = PLUG_TYPE_HEADSET;
+		else if (mic_mv[i] > plug_type_ptr->v_hs_max)
+			plug_type[i] = PLUG_TYPE_HIGH_HPH;
+
+		r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
+		if (!r && i > 0) {
+			if (plug_type[i-1] != plug_type[i])
+				r = true;
+			else
+				r = tabla_is_invalid_insert_delta(codec,
+							mic_mv[i],
+							mic_mv[i - 1]);
+		}
+	}
+
+	return r;
+}
+
+/* called under codec_resource_lock acquisition */
+void tabla_find_plug_and_report(struct snd_soc_codec *codec,
+				enum tabla_mbhc_plug_type plug_type)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	if (plug_type == PLUG_TYPE_HEADPHONE
+		&& tabla->current_plug == PLUG_TYPE_NONE) {
+		/* Nothing was reported previously
+		 * reporte a headphone
+		 */
+		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+		tabla_codec_cleanup_hs_polling(codec);
+	} else if (plug_type == PLUG_TYPE_HEADSET) {
+		/* If Headphone was reported previously, this will
+		 * only report the mic line
+		 */
+		tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+		msleep(100);
+		tabla_codec_start_hs_polling(codec);
+	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		if (tabla->current_plug == PLUG_TYPE_NONE)
+			tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+		tabla_codec_cleanup_hs_polling(codec);
+		pr_debug("setup mic trigger for further detection\n");
+		tabla->lpi_enabled = true;
+		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
+					     false);
 	}
 }
 
-static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
+/* should be called under interrupt context that hold suspend */
+static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
 {
-	struct tabla_priv *priv = data;
-	struct snd_soc_codec *codec = priv->codec;
-	const struct tabla_mbhc_plug_detect_cfg *plug_det =
-	    TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
-	int ldo_h_on, micb_cfilt_on;
-	short mb_v;
-	u8 is_removal;
-	int mic_mv;
+	pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
+	tabla->hs_detect_work_stop = false;
+	wcd9xxx_lock_sleep(tabla->codec->control_data);
+	schedule_work(&tabla->hs_correct_plug_work);
+}
+
+/* called under codec_resource_lock acquisition */
+static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
+{
+	pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
+	tabla->hs_detect_work_stop = true;
+	wmb();
+	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+	if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
+		pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
+		wcd9xxx_unlock_sleep(tabla->codec->control_data);
+	}
+	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+}
+
+static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+}
+
+static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
+{
+	return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
+		tabla->mbhc_cfg.gpio_level_insert);
+}
+
+static void tabla_hs_correct_gpio_plug(struct work_struct *work)
+{
+	struct tabla_priv *tabla;
+	struct snd_soc_codec *codec;
+	int retry = 0, i;
+	bool correction = false;
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+	enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+	unsigned long timeout;
+
+	tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
+	codec = tabla->codec;
 
 	pr_debug("%s: enter\n", __func__);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
 
-	is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
-	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
+	/* Keep override on during entire plug type correction work.
+	 *
+	 * This is okay under the assumption that any GPIO irqs which use
+	 * MBHC block cancel and sync this work so override is off again
+	 * prior to GPIO interrupt handler's MBHC block usage.
+	 * Also while this correction work is running, we can guarantee
+	 * DAPM doesn't use any MBHC block as this work only runs with
+	 * headphone detection.
+	 */
+	tabla_turn_onoff_override(codec, true);
 
-	/* Turn off both HPH and MIC line schmitt triggers */
-	snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
-	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
+	timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
+	while (!time_after(jiffies, timeout)) {
+		++retry;
+		rmb();
+		if (tabla->hs_detect_work_stop) {
+			pr_debug("%s: stop requested\n", __func__);
+			break;
+		}
 
-	if (priv->mbhc_fake_ins_start &&
-	    time_after(jiffies, priv->mbhc_fake_ins_start +
-		       msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
-		pr_debug("%s: fake context interrupt, reset insertion\n",
-			 __func__);
-		priv->mbhc_fake_ins_start = 0;
-		tabla_codec_shutdown_hs_polling(codec);
-		tabla_codec_enable_hs_detect(codec, 1);
-		return IRQ_HANDLED;
+		msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
+		if (tabla_hs_gpio_level_remove(tabla)) {
+			pr_debug("%s: GPIO value is low\n", __func__);
+			break;
+		}
+
+		/* can race with removal interrupt */
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
+			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
+			pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
+				 __func__, retry, mic_mv[i], mb_v[i]);
+		}
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+
+		if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+			pr_debug("Invalid plug in attempt # %d\n", retry);
+			if (retry == NUM_ATTEMPTS_TO_REPORT &&
+			    tabla->current_plug == PLUG_TYPE_NONE) {
+				tabla_codec_report_plug(codec, 1,
+							SND_JACK_HEADPHONE);
+			}
+		} else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
+							plug_type) &&
+			   plug_type[0] == PLUG_TYPE_HEADPHONE) {
+			pr_debug("Good headphone detected, continue polling mic\n");
+			if (tabla->current_plug == PLUG_TYPE_NONE) {
+				tabla_codec_report_plug(codec, 1,
+							SND_JACK_HEADPHONE);
+			}
+		} else {
+			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+			/* Turn off override */
+			tabla_turn_onoff_override(codec, false);
+			tabla_find_plug_and_report(codec, plug_type[0]);
+			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+			pr_debug("Attempt %d found correct plug %d\n", retry,
+				 plug_type[0]);
+			correction = true;
+			break;
+		}
 	}
 
-	ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
-	micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
-			    & 0x80;
+	/* Turn off override */
+	if (!correction)
+		tabla_turn_onoff_override(codec, false);
 
-	if (!ldo_h_on)
-		snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
-	if (!micb_cfilt_on)
-		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
-				    0x80, 0x80);
+	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+	pr_debug("%s: leave\n", __func__);
+	/* unlock sleep */
+	wcd9xxx_unlock_sleep(tabla->codec->control_data);
+}
+
+/* called under codec_resource_lock acquisition */
+static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+	enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+	int i;
+
+	pr_debug("%s: enter\n", __func__);
+
+	tabla_turn_onoff_override(codec, true);
+	mb_v[0] = tabla_codec_setup_hs_polling(codec);
+	mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
+	pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
+
+	for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+		mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
+		mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
+		pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
+			 mic_mv[i]);
+	}
+	tabla_turn_onoff_override(codec, false);
+
+	if (tabla_hs_gpio_level_remove(tabla)) {
+		pr_debug("%s: GPIO value is low when determining plug\n",
+			 __func__);
+		return;
+	}
+
+	if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+		tabla_schedule_hs_detect_plug(tabla);
+	} else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
+		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+
+		tabla_schedule_hs_detect_plug(tabla);
+	} else {
+		pr_debug("%s: Valid plug found, determine plug type\n",
+			 __func__);
+		tabla_find_plug_and_report(codec, plug_type[0]);
+	}
+}
+
+/* called under codec_resource_lock acquisition */
+static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
+{
+	int i;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	const struct tabla_mbhc_plug_detect_cfg *plug_det =
+	    TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
+	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+	enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+	struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
+
+	/* Turn on the override,
+	 * tabla_codec_setup_hs_polling requires override on */
+	tabla_turn_onoff_override(codec, true);
+
 	if (plug_det->t_ins_complete > 20)
 		msleep(plug_det->t_ins_complete);
 	else
 		usleep_range(plug_det->t_ins_complete * 1000,
 			     plug_det->t_ins_complete * 1000);
 
-	if (!ldo_h_on)
-		snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
-	if (!micb_cfilt_on)
-		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
-				    0x80, 0x0);
+	if (tabla->mbhc_cfg.gpio) {
+		/* Turn off the override */
+		tabla_turn_onoff_override(codec, false);
+		if (tabla_hs_gpio_level_remove(tabla))
+			pr_debug("%s: GPIO value is low when determining "
+				 "plug\n", __func__);
+		else
+			tabla_codec_decide_gpio_plug(codec);
+		return;
+	}
+
+	/*
+	 * First DCE measurement,
+	 * IF this is fake, discontinue detection
+	 * and restart insertion detection
+	 */
+	mb_v[0] = tabla_codec_setup_hs_polling(codec);
+	mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
+	if (tabla_is_invalid_insertion_range(codec, mic_mv[0])) {
+		pr_debug("%s: Detect attempt 1, detected Fake\n", __func__);
+		tabla_turn_onoff_override(codec, false);
+		tabla_codec_cleanup_hs_polling(codec);
+		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
+					     false);
+		return;
+	}
+	pr_debug("%s: DCE run 1, %x, mic_mv = %d\n", __func__, mb_v[0],
+		 mic_mv[0]);
+
+	/*
+	 * Perform two more DCE measurements,
+	 * IF any of them is fake, discontinue detection
+	 * and restart insertion detection
+	 */
+	for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+		mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
+		mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
+		pr_debug("%s: DCE run %d, %x, mic_mv = %d\n", __func__, i + 1,
+			 mb_v[1], mic_mv[i]);
+		if (tabla_is_invalid_insertion_range(codec, mic_mv[i])
+			|| tabla_is_invalid_insert_delta(codec, mic_mv[i],
+			   mic_mv[i - 1])) {
+			pr_debug("%s: Detect attempt %d, detected Fake\n",
+				 __func__, i + 1);
+			tabla_turn_onoff_override(codec, false);
+			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
+					    0x02, 0x02);
+			tabla_codec_cleanup_hs_polling(codec);
+			tabla_codec_enable_hs_detect(codec, 1,
+						     MBHC_USE_MB_TRIGGER,
+						     false);
+			return;
+		}
+	}
+	tabla_turn_onoff_override(codec, false);
+
+	plug_type_ptr =
+	    TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
+
+	/*
+	 * If we are here, means none of the three
+	 * measurements are fake, continue plug type detection.
+	 * If all three measurements do not produce same
+	 * plug type, restart insertion detection
+	 */
+	for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+		if (mic_mv[i] < plug_type_ptr->v_no_mic) {
+			plug_type[i] = PLUG_TYPE_HEADPHONE;
+			pr_debug("%s: Detect attempt %d, detected Headphone\n",
+				 __func__, i);
+		} else {
+			plug_type[i] = PLUG_TYPE_HEADSET;
+			pr_debug("%s: Detect attempt %d, detected Headset\n",
+				 __func__, i);
+		}
+
+		if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
+			pr_err("%s: Detect attempt %d and %d are not same",
+			       __func__, i - 1, i);
+			tabla_codec_cleanup_hs_polling(codec);
+			tabla_codec_enable_hs_detect(codec, 1,
+						     MBHC_USE_MB_TRIGGER,
+						     false);
+			return;
+		}
+	}
+
+	if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
+		pr_debug("%s: Headphone Detected\n", __func__);
+		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+		tabla_codec_cleanup_hs_polling(codec);
+		tabla_codec_enable_hs_detect(codec, 0, 0, false);
+	} else if (plug_type[0] == PLUG_TYPE_HEADSET) {
+		pr_debug("%s: Headset detected\n", __func__);
+		tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+
+		/* avoid false button press detect */
+		msleep(50);
+		tabla_codec_start_hs_polling(codec);
+	}
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
+{
+	struct snd_soc_codec *codec = priv->codec;
+
+	if (!is_removal) {
+		pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
+
+		rmb();
+		if (priv->lpi_enabled)
+			msleep(100);
+
+		rmb();
+		if (!priv->lpi_enabled) {
+			pr_debug("%s: lpi is disabled\n", __func__);
+		} else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
+			   priv->mbhc_cfg.gpio_level_insert) {
+			pr_debug("%s: Valid insertion, "
+				 "detect plug type\n", __func__);
+			tabla_codec_decide_gpio_plug(codec);
+		} else {
+			pr_debug("%s: Invalid insertion, "
+				 "stop plug detection\n", __func__);
+		}
+	} else {
+		pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
+	}
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
+				       bool is_mb_trigger)
+{
+	int ret;
+	struct snd_soc_codec *codec = priv->codec;
+	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
 
 	if (is_removal) {
+		/* cancel possiblely running hs detect work */
+		tabla_cancel_hs_detect_plug(priv);
+
 		/*
 		 * If headphone is removed while playback is in progress,
 		 * it is possible that micbias will be switched to VDDIO.
 		 */
-		if (priv->mbhc_micbias_switched)
-			tabla_codec_switch_micbias(codec, 0);
-		priv->hph_status &= ~SND_JACK_HEADPHONE;
-
-		/* If headphone PA is on, check if userspace receives
-		 * removal event to sync-up PA's state */
-		if (tabla_is_hph_pa_on(codec)) {
-			set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
-			set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
-		}
-
-		if (tabla_is_hph_dac_on(codec, 1))
-			set_bit(TABLA_HPHL_DAC_OFF_ACK,
-				&priv->hph_pa_dac_state);
-		if (tabla_is_hph_dac_on(codec, 0))
-			set_bit(TABLA_HPHR_DAC_OFF_ACK,
-				&priv->hph_pa_dac_state);
-
-		if (priv->headset_jack) {
-			pr_debug("%s: Reporting removal\n", __func__);
-			tabla_snd_soc_jack_report(priv, priv->headset_jack,
-						  priv->hph_status,
-						  TABLA_JACK_MASK);
-		}
+		tabla_codec_switch_micbias(codec, 0);
+		tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
 		tabla_codec_shutdown_hs_removal_detect(codec);
-		tabla_codec_enable_hs_detect(codec, 1);
-		return IRQ_HANDLED;
-	}
-
-	mb_v = tabla_codec_setup_hs_polling(codec);
-	mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
-
-	if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
-		pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
-			 "STA : %d,%d\n", __func__,
-			 (priv->mbhc_fake_ins_start ?
-			     jiffies_to_msecs(jiffies -
-					      priv->mbhc_fake_ins_start) :
-			     0),
-			 mb_v, mic_mv);
-		if (time_after(jiffies,
-			       priv->mbhc_fake_ins_start +
-			       msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
-			/* Disable HPH trigger and enable MIC line trigger */
-			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
-					    0x00);
-			snd_soc_update_bits(codec,
-					    priv->mbhc_bias_regs.mbhc_reg, 0x60,
-					    plug_det->mic_current << 5);
-			snd_soc_update_bits(codec,
-					    priv->mbhc_bias_regs.mbhc_reg,
-					    0x80, 0x80);
-			usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
-			snd_soc_update_bits(codec,
-					    priv->mbhc_bias_regs.mbhc_reg,
-					    0x10, 0x10);
+		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
+					     true);
+	} else if (is_mb_trigger && !is_removal) {
+		pr_debug("%s: Waiting for Headphone left trigger\n",
+			__func__);
+		wcd9xxx_lock_sleep(core);
+		if (schedule_delayed_work(&priv->mbhc_insert_dwork,
+					  usecs_to_jiffies(1000000)) == 0) {
+			pr_err("%s: mbhc_insert_dwork is already scheduled\n",
+			       __func__);
+			wcd9xxx_unlock_sleep(core);
+		}
+		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
+					     false);
+	} else  {
+		ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
+		if (ret != 0) {
+			pr_debug("%s: Complete plug insertion, Detecting plug "
+				 "type\n", __func__);
+			tabla_codec_detect_plug_type(codec);
+			wcd9xxx_unlock_sleep(core);
 		} else {
-			if (priv->mbhc_fake_ins_start == 0)
-				priv->mbhc_fake_ins_start = jiffies;
-			/* Setup normal insert detection
-			 * Enable HPH Schmitt Trigger
-			 */
-			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
-					    0x13 | 0x0C,
-					    0x13 | plug_det->hph_current << 2);
+			wcd9xxx_enable_irq(codec->control_data,
+					   TABLA_IRQ_MBHC_INSERTION);
+			pr_err("%s: Error detecting plug insertion\n",
+			       __func__);
 		}
-		/* Setup for insertion detection */
-		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
-		tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
-		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
-
-	} else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
-		pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
-			 __func__, mb_v, mic_mv);
-		priv->mbhc_fake_ins_start = 0;
-		priv->hph_status |= SND_JACK_HEADPHONE;
-		if (priv->headset_jack) {
-			pr_debug("%s: Reporting insertion %d\n", __func__,
-				 SND_JACK_HEADPHONE);
-			tabla_snd_soc_jack_report(priv, priv->headset_jack,
-						  priv->hph_status,
-						  TABLA_JACK_MASK);
-		}
-		tabla_codec_shutdown_hs_polling(codec);
-		tabla_codec_enable_hs_detect(codec, 0);
-		tabla_sync_hph_state(priv);
-	} else {
-		pr_debug("%s: Headset detected, mb_v: %d,%d\n",
-			__func__, mb_v, mic_mv);
-		priv->mbhc_fake_ins_start = 0;
-		priv->hph_status |= SND_JACK_HEADSET;
-		if (priv->headset_jack) {
-			pr_debug("%s: Reporting insertion %d\n", __func__,
-				 SND_JACK_HEADSET);
-			tabla_snd_soc_jack_report(priv, priv->headset_jack,
-						  priv->hph_status,
-						  TABLA_JACK_MASK);
-		}
-		/* avoid false button press detect */
-		msleep(50);
-		tabla_codec_start_hs_polling(codec);
-		tabla_sync_hph_state(priv);
 	}
+}
 
+static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
+{
+	bool is_mb_trigger, is_removal;
+	struct tabla_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+
+	pr_debug("%s: enter\n", __func__);
+	TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+
+	is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
+					0x10);
+	is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
+
+	/* Turn off both HPH and MIC line schmitt triggers */
+	snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
+	snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+
+	if (priv->mbhc_cfg.gpio)
+		tabla_hs_insert_irq_gpio(priv, is_removal);
+	else
+		tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
+
+	TABLA_RELEASE_LOCK(priv->codec_resource_lock);
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
+static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct tabla_mbhc_plug_type_cfg *plug_type =
+		TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
+
+	return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
+		&& (mic_mv < plug_type->v_hs_max)) ? true : false;
+}
+
+/* called under codec_resource_lock acquisition
+ * returns true if mic voltage range is back to normal insertion
+ * returns false either if timedout or removed */
+static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
+{
+	int i;
+	bool timedout, settled = false;
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+	unsigned long retry = 0, timeout;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct tabla_mbhc_plug_type_cfg *plug_type =
+		TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
+
+	timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
+	while (!(timedout = time_after(jiffies, timeout))) {
+		retry++;
+		if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
+			pr_debug("%s: GPIO indicates removal\n", __func__);
+			break;
+		}
+
+		if (tabla->mbhc_cfg.gpio) {
+			if (retry > 1)
+				msleep(250);
+			else
+				msleep(50);
+		}
+
+		if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
+			pr_debug("%s: GPIO indicates removal\n", __func__);
+			break;
+		}
+
+		for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+			mb_v[i] = tabla_codec_sta_dce(codec, 1,  true);
+			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
+			pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+				 __func__, retry, mic_mv[i], mb_v[i]);
+		}
+
+		if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
+			pr_debug("%s: GPIO indicates removal\n", __func__);
+			break;
+		}
+
+		if (tabla->current_plug == PLUG_TYPE_NONE) {
+			pr_debug("%s : headset/headphone is removed\n",
+				 __func__);
+			break;
+		}
+
+		for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
+			if (!is_valid_mic_voltage(codec, mic_mv[i]))
+				break;
+
+		if (i == MBHC_NUM_DCE_PLUG_DETECT) {
+			pr_debug("%s: MIC voltage settled\n", __func__);
+			settled = true;
+			msleep(200);
+			break;
+		}
+
+		/* only for non-GPIO remove irq */
+		if (!tabla->mbhc_cfg.gpio) {
+			for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
+				if (mic_mv[i] < plug_type->v_hs_max)
+					break;
+			if (i == MBHC_NUM_DCE_PLUG_DETECT) {
+				pr_debug("%s: Headset is removed\n", __func__);
+				break;
+			}
+		}
+	}
+
+	if (timedout)
+		pr_debug("%s: Microphone did not settle in %d seconds\n",
+			 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
+	return settled;
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
+{
+	struct snd_soc_codec *codec = priv->codec;
+
+	if (tabla_hs_remove_settle(codec))
+		tabla_codec_start_hs_polling(codec);
+	pr_debug("%s: remove settle done\n", __func__);
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
 {
 	short bias_value;
-	struct tabla_priv *priv = data;
+	bool removed = true;
 	struct snd_soc_codec *codec = priv->codec;
 	const struct tabla_mbhc_general_cfg *generic =
-	    TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
-	int fake_removal = 0;
+	    TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
 	int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
 
-	pr_debug("%s: enter, removal interrupt\n", __func__);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+	if (priv->current_plug != PLUG_TYPE_HEADSET) {
+		pr_debug("%s(): Headset is not inserted, ignore removal\n",
+			 __func__);
+		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
+				    0x08, 0x08);
+		return;
+	}
 
 	usleep_range(generic->t_shutdown_plug_rem,
 		     generic->t_shutdown_plug_rem);
 
 	do {
-		bias_value = tabla_codec_sta_dce(codec, 1);
+		bias_value = tabla_codec_sta_dce(codec, 1,  true);
 		pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
 			 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
 		if (bias_value < (short)priv->mbhc_data.v_ins_h) {
-			fake_removal = 1;
+			pr_debug("%s: checking false removal\n", __func__);
+			msleep(500);
+			removed = !tabla_hs_remove_settle(codec);
+			pr_debug("%s: headset %sactually removed\n", __func__,
+				 removed ? "" : "not ");
 			break;
 		}
 		min_us -= priv->mbhc_data.t_dce;
 	} while (min_us > 0);
 
-	if (fake_removal) {
-		pr_debug("False alarm, headset not actually removed\n");
-		tabla_codec_start_hs_polling(codec);
-	} else {
+	if (removed) {
+		/* cancel possiblely running hs detect work */
+		tabla_cancel_hs_detect_plug(priv);
 		/*
 		 * If this removal is not false, first check the micbias
 		 * switch status and switch it to LDOH if it is already
 		 * switched to VDDIO.
 		 */
-		if (priv->mbhc_micbias_switched)
-			tabla_codec_switch_micbias(codec, 0);
-		priv->hph_status &= ~SND_JACK_HEADSET;
-		if (priv->headset_jack) {
-			pr_debug("%s: Reporting removal\n", __func__);
-			tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
-						  TABLA_JACK_MASK);
-		}
-		tabla_codec_shutdown_hs_polling(codec);
+		tabla_codec_switch_micbias(codec, 0);
 
-		tabla_codec_enable_hs_detect(codec, 1);
+		tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+		tabla_codec_cleanup_hs_polling(codec);
+		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
+					     true);
+	} else {
+		tabla_codec_start_hs_polling(codec);
 	}
+}
 
+static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
+{
+	struct tabla_priv *priv = data;
+	pr_debug("%s: enter, removal interrupt\n", __func__);
+
+	TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
+	if (priv->mbhc_cfg.gpio)
+		tabla_hs_remove_irq_gpio(priv);
+	else
+		tabla_hs_remove_irq_nogpio(priv);
+
+	TABLA_RELEASE_LOCK(priv->codec_resource_lock);
 	return IRQ_HANDLED;
 }
 
+void mbhc_insert_work(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct tabla_priv *tabla;
+	struct snd_soc_codec *codec;
+	struct wcd9xxx *tabla_core;
+
+	dwork = to_delayed_work(work);
+	tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
+	codec = tabla->codec;
+	tabla_core = dev_get_drvdata(codec->dev->parent);
+
+	pr_debug("%s:\n", __func__);
+
+	/* Turn off both HPH and MIC line schmitt triggers */
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+	wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	tabla_codec_detect_plug_type(codec);
+	wcd9xxx_unlock_sleep(tabla_core);
+}
+
+static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
+{
+	bool insert;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	bool is_removed = false;
+
+	pr_debug("%s: enter\n", __func__);
+
+	tabla->in_gpio_handler = true;
+	/* Wait here for debounce time */
+	usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
+		     TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
+
+	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+
+	/* cancel pending button press */
+	if (tabla_cancel_btn_work(tabla))
+		pr_debug("%s: button press is canceled\n", __func__);
+
+	insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
+		  tabla->mbhc_cfg.gpio_level_insert);
+	if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
+		tabla->lpi_enabled = false;
+		wmb();
+
+		/* cancel detect plug */
+		tabla_cancel_hs_detect_plug(tabla);
+
+		/* Disable Mic Bias pull down and HPH Switch to GND */
+		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
+				    0x00);
+		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
+		tabla_codec_detect_plug_type(codec);
+	} else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
+		tabla->lpi_enabled = false;
+		wmb();
+
+		/* cancel detect plug */
+		tabla_cancel_hs_detect_plug(tabla);
+
+		if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
+			tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+			is_removed = true;
+		} else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
+			tabla_codec_pause_hs_polling(codec);
+			tabla_codec_cleanup_hs_polling(codec);
+			tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+			is_removed = true;
+		}
+
+		if (is_removed) {
+			/* Enable Mic Bias pull down and HPH Switch to GND */
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.ctl_reg, 0x01,
+					    0x01);
+			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
+					    0x01);
+			/* Make sure mic trigger is turned off */
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.ctl_reg,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.mbhc_reg,
+					    0x90, 0x00);
+			/* Reset MBHC State Machine */
+			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
+					    0x08, 0x08);
+			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
+					    0x08, 0x00);
+			/* Turn off override */
+			tabla_turn_onoff_override(codec, false);
+		}
+	}
+
+	tabla->in_gpio_handler = false;
+	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
+{
+	int r = IRQ_HANDLED;
+	struct snd_soc_codec *codec = data;
+
+	if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+		pr_warn("%s: failed to hold suspend\n", __func__);
+		r = IRQ_NONE;
+	} else {
+		tabla_hs_gpio_handler(codec);
+		wcd9xxx_unlock_sleep(codec->control_data);
+	}
+
+	return r;
+}
+
+static void mbhc_fw_read(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct tabla_priv *tabla;
+	struct snd_soc_codec *codec;
+	const struct firmware *fw;
+	int ret = -1, retry = 0, rc;
+
+	dwork = to_delayed_work(work);
+	tabla = container_of(dwork, struct tabla_priv,
+				mbhc_firmware_dwork);
+	codec = tabla->codec;
+
+	while (retry < MBHC_FW_READ_ATTEMPTS) {
+		retry++;
+		pr_info("%s:Attempt %d to request MBHC firmware\n",
+			__func__, retry);
+		ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
+					codec->dev);
+
+		if (ret != 0) {
+			usleep_range(MBHC_FW_READ_TIMEOUT,
+					MBHC_FW_READ_TIMEOUT);
+		} else {
+			pr_info("%s: MBHC Firmware read succesful\n", __func__);
+			break;
+		}
+	}
+
+	if (ret != 0) {
+		pr_err("%s: Cannot load MBHC firmware use default cal\n",
+			__func__);
+	} else if (tabla_mbhc_fw_validate(fw) == false) {
+		pr_err("%s: Invalid MBHC cal data size use default cal\n",
+			 __func__);
+		release_firmware(fw);
+	} else {
+		tabla->mbhc_cfg.calibration = (void *)fw->data;
+		tabla->mbhc_fw = fw;
+	}
+
+	tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+	tabla_mbhc_init(codec);
+	tabla_mbhc_cal(codec);
+	tabla_mbhc_calc_thres(codec);
+	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+	tabla_codec_calibrate_hs_polling(codec);
+	if (!tabla->mbhc_cfg.gpio) {
+		tabla->mbhc_inval_hs_range_override = false;
+		rc = tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
+						  false);
+
+		if (IS_ERR_VALUE(rc))
+			pr_err("%s: Failed to setup MBHC detection\n",
+			       __func__);
+	} else {
+		tabla->mbhc_inval_hs_range_override = true;
+		/* Enable Mic Bias pull down and HPH Switch to GND */
+		snd_soc_update_bits(codec,
+				    tabla->mbhc_bias_regs.ctl_reg, 0x01,
+				    0x01);
+		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
+				    0x01);
+		INIT_WORK(&tabla->hs_correct_plug_work,
+				  tabla_hs_correct_gpio_plug);
+	}
+
+}
+
+int tabla_hs_detect(struct snd_soc_codec *codec,
+		    const struct tabla_mbhc_config *cfg)
+{
+	struct tabla_priv *tabla;
+	int rc = 0;
+
+	if (!codec || !cfg->calibration) {
+		pr_err("Error: no codec or calibration\n");
+		return -EINVAL;
+	}
+
+	if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
+		if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
+			pr_err("Error: clock rate %dHz is not yet supported\n",
+			       cfg->mclk_rate);
+		else
+			pr_err("Error: unsupported clock rate %d\n",
+			       cfg->mclk_rate);
+		return -EINVAL;
+	}
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+	tabla->mbhc_cfg = *cfg;
+	tabla->in_gpio_handler = false;
+	tabla->current_plug = PLUG_TYPE_NONE;
+	tabla->lpi_enabled = false;
+	tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
+
+	/* Put CFILT in fast mode by default */
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
+			    0x40, TABLA_CFILT_FAST_MODE);
+	INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
+	INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
+	INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
+	INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
+	INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
+
+	if (!tabla->mbhc_cfg.read_fw_bin) {
+		tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+		tabla_mbhc_init(codec);
+		tabla_mbhc_cal(codec);
+		tabla_mbhc_calc_thres(codec);
+		tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+		tabla_codec_calibrate_hs_polling(codec);
+		if (!tabla->mbhc_cfg.gpio) {
+			tabla->mbhc_inval_hs_range_override = false;
+			rc =  tabla_codec_enable_hs_detect(codec, 1,
+							   MBHC_USE_MB_TRIGGER,
+							   false);
+		} else {
+			tabla->mbhc_inval_hs_range_override = true;
+			/* Enable Mic Bias pull down and HPH Switch to GND */
+			snd_soc_update_bits(codec,
+					    tabla->mbhc_bias_regs.ctl_reg, 0x01,
+					    0x01);
+			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
+					    0x01);
+			INIT_WORK(&tabla->hs_correct_plug_work,
+				  tabla_hs_correct_gpio_plug);
+		}
+	} else {
+		schedule_delayed_work(&tabla->mbhc_firmware_dwork,
+				      usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
+	}
+
+	if (!IS_ERR_VALUE(rc)) {
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
+		wcd9xxx_enable_irq(codec->control_data,
+				 TABLA_IRQ_HPH_PA_OCPL_FAULT);
+		wcd9xxx_enable_irq(codec->control_data,
+				 TABLA_IRQ_HPH_PA_OCPR_FAULT);
+	}
+
+	if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
+		rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
+					   tabla_mechanical_plug_detect_irq,
+					   (IRQF_TRIGGER_RISING |
+					    IRQF_TRIGGER_FALLING),
+					   "tabla-gpio", codec);
+		if (!IS_ERR_VALUE(rc)) {
+			rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
+			/* Bootup time detection */
+			tabla_hs_gpio_handler(codec);
+		}
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tabla_hs_detect);
+
 static unsigned long slimbus_value;
 
 static irqreturn_t tabla_slimbus_irq(int irq, void *data)
@@ -4611,11 +6256,11 @@
 	int i, j;
 	u8 val;
 
-	for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
-		slimbus_value = tabla_interface_reg_read(codec->control_data,
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
+		slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
 			TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
 		for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
-			val = tabla_interface_reg_read(codec->control_data,
+			val = wcd9xxx_interface_reg_read(codec->control_data,
 				TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
 			if (val & 0x1)
 				pr_err_ratelimited("overflow error on port %x,"
@@ -4624,7 +6269,7 @@
 				pr_err_ratelimited("underflow error on port %x,"
 					" value %x\n", i*8 + j, val);
 		}
-		tabla_interface_reg_write(codec->control_data,
+		wcd9xxx_interface_reg_write(codec->control_data,
 			TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
 	}
 
@@ -4635,7 +6280,7 @@
 static int tabla_handle_pdata(struct tabla_priv *tabla)
 {
 	struct snd_soc_codec *codec = tabla->codec;
-	struct tabla_pdata *pdata = tabla->pdata;
+	struct wcd9xxx_pdata *pdata = tabla->pdata;
 	int k1, k2, k3, rc = 0;
 	u8 leg_mode = pdata->amic_settings.legacy_mode;
 	u8 txfe_bypass = pdata->amic_settings.txfe_enable;
@@ -4739,6 +6384,27 @@
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
 			0xE0, (pdata->ocp.hph_ocp_limit << 5));
 	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
+			if (pdata->regulator[i].min_uV == 1800000 &&
+			    pdata->regulator[i].max_uV == 1800000) {
+				snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
+					      0x1C);
+			} else if (pdata->regulator[i].min_uV == 2200000 &&
+				   pdata->regulator[i].max_uV == 2200000) {
+				snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
+					      0x1E);
+			} else {
+				pr_err("%s: unsupported CDC_VDDA_RX voltage "
+				       "min %d, max %d\n", __func__,
+				       pdata->regulator[i].min_uV,
+				       pdata->regulator[i].max_uV);
+				rc = -EINVAL;
+			}
+			break;
+		}
+	}
 done:
 	return rc;
 }
@@ -4802,7 +6468,7 @@
 static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
 {
 	u32 i;
-	struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
 
 	for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
 		snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
@@ -4894,7 +6560,7 @@
 static void tabla_codec_init_reg(struct snd_soc_codec *codec)
 {
 	u32 i;
-	struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
 
 	for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
 		snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
@@ -4918,23 +6584,23 @@
 
 static void tabla_update_reg_address(struct tabla_priv *priv)
 {
-	struct tabla *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
 	struct tabla_reg_address *reg_addr = &priv->reg_addr;
 
 	if (TABLA_IS_1_X(tabla_core->version)) {
+		reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
+		reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
 		reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
-		reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
-		reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
 	} else if (TABLA_IS_2_0(tabla_core->version)) {
+		reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
+		reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
 		reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
-		reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
-		reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
 	}
 }
 
 static int tabla_codec_probe(struct snd_soc_codec *codec)
 {
-	struct tabla *control;
+	struct wcd9xxx *control;
 	struct tabla_priv *tabla;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret = 0;
@@ -4949,6 +6615,12 @@
 		dev_err(codec->dev, "Failed to allocate private data\n");
 		return -ENOMEM;
 	}
+	for (i = 0 ; i < NUM_DECIMATORS; i++) {
+		tx_hpf_work[i].tabla = tabla;
+		tx_hpf_work[i].decimator = i + 1;
+		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+			tx_hpf_corner_freq_callback);
+	}
 
 	/* Make sure mbhc micbias register addresses are zeroed out */
 	memset(&tabla->mbhc_bias_regs, 0,
@@ -4971,10 +6643,20 @@
 	tabla->mbhc_polling_active = false;
 	tabla->mbhc_fake_ins_start = 0;
 	tabla->no_mic_headset_override = false;
+	tabla->hs_polling_irq_prepared = false;
+	mutex_init(&tabla->codec_resource_lock);
 	tabla->codec = codec;
+	tabla->mbhc_state = MBHC_STATE_NONE;
+	tabla->mbhc_last_resume = 0;
+	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 = tabla_get_intf_type();
-
+	tabla->intf_type = wcd9xxx_get_intf_type();
+	tabla->aux_pga_cnt = 0;
+	tabla->aux_l_gain = 0x1F;
+	tabla->aux_r_gain = 0x1F;
 	tabla_update_reg_address(tabla);
 	tabla_update_reg_defaults(codec);
 	tabla_codec_init_reg(codec);
@@ -5002,7 +6684,7 @@
 		snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
 				    ARRAY_SIZE(tabla_2_higher_dapm_widgets));
 
-	if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+	if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 		snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
 			ARRAY_SIZE(tabla_dapm_i2s_widgets));
 		snd_soc_dapm_add_routes(dapm, audio_i2s_map,
@@ -5018,49 +6700,46 @@
 				      ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
 	} else  {
 		pr_err("%s : ERROR.  Unsupported Tabla version 0x%2x\n",
-		       __func__, control->version);
+			__func__, control->version);
 		goto err_pdata;
 	}
 
 	snd_soc_dapm_sync(dapm);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
 		tabla_hs_insert_irq, "Headset insert detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_INSERTION);
 		goto err_insert_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
 		tabla_hs_remove_irq, "Headset remove detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_REMOVAL);
 		goto err_remove_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
 		tabla_dce_handler, "DC Estimation detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_POTENTIAL);
 		goto err_potential_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
 		tabla_release_handler, "Button Release detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_RELEASE);
 		goto err_release_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
 		tabla_slimbus_irq, "SLIMBUS Slave", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -5068,11 +6747,11 @@
 		goto err_slimbus_irq;
 	}
 
-	for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
-		tabla_interface_reg_write(codec->control_data,
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+		wcd9xxx_interface_reg_write(codec->control_data,
 			TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
 
-	ret = tabla_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(codec->control_data,
 		TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
 		"HPH_L OCP detect", tabla);
 	if (ret) {
@@ -5080,9 +6759,9 @@
 			TABLA_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = tabla_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(codec->control_data,
 		TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
 		"HPH_R OCP detect", tabla);
 	if (ret) {
@@ -5090,7 +6769,7 @@
 			TABLA_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
 	for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
 		switch (tabla_dai[i].id) {
 		case AIF1_PB:
@@ -5116,19 +6795,21 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
+	wcd9xxx_free_irq(codec->control_data,
+			TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
 err_hphl_ocp_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
 err_slimbus_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
 err_release_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
 err_potential_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
 err_remove_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
 err_insert_irq:
 err_pdata:
+	mutex_destroy(&tabla->codec_resource_lock);
 	kfree(tabla);
 	return ret;
 }
@@ -5136,17 +6817,20 @@
 {
 	int i;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 	tabla_codec_disable_clock_block(codec);
+	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 	tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
 	if (tabla->mbhc_fw)
 		release_firmware(tabla->mbhc_fw);
 	for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
 		kfree(tabla->dai[i].ch_num);
+	mutex_destroy(&tabla->codec_resource_lock);
 	kfree(tabla);
 	return 0;
 }
@@ -5209,7 +6893,10 @@
 
 static int tabla_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tabla_priv *tabla = platform_get_drvdata(pdev);
 	dev_dbg(dev, "%s: system resume\n", __func__);
+	tabla->mbhc_last_resume = jiffies;
 	return 0;
 }
 
@@ -5227,10 +6914,10 @@
 		S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
 
 #endif
-	if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
 			tabla_dai, ARRAY_SIZE(tabla_dai));
-	else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
+	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
 		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
 			tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
 	return ret;
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 9c430b9..6e80284 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -11,7 +11,7 @@
  */
 #include <sound/soc.h>
 #include <sound/jack.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 
 #define TABLA_NUM_REGISTERS 0x400
 #define TABLA_MAX_REGISTER (TABLA_NUM_REGISTERS-1)
@@ -39,7 +39,7 @@
 extern const u8 tabla_reg_defaults[TABLA_CACHE_SIZE];
 
 enum tabla_micbias_num {
-	TABLA_MICBIAS1,
+	TABLA_MICBIAS1 = 0,
 	TABLA_MICBIAS2,
 	TABLA_MICBIAS3,
 	TABLA_MICBIAS4,
@@ -156,19 +156,37 @@
 	u16 _beta[3];
 } __packed;
 
+struct tabla_mbhc_config {
+	struct snd_soc_jack *headset_jack;
+	struct snd_soc_jack *button_jack;
+	bool read_fw_bin;
+	/* void* calibration contains:
+	 *  struct tabla_mbhc_general_cfg generic;
+	 *  struct tabla_mbhc_plug_detect_cfg plug_det;
+	 *  struct tabla_mbhc_plug_type_cfg plug_type;
+	 *  struct tabla_mbhc_btn_detect_cfg btn_det;
+	 *  struct tabla_mbhc_imped_detect_cfg imped_det;
+	 * Note: various size depends on btn_det->num_btn
+	 */
+	void *calibration;
+	enum tabla_micbias_num micbias;
+	int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
+	unsigned int mclk_rate;
+	unsigned int gpio;
+	unsigned int gpio_irq;
+	int gpio_level_insert;
+};
+
 extern int tabla_hs_detect(struct snd_soc_codec *codec,
-			   struct snd_soc_jack *headset_jack,
-			   struct snd_soc_jack *button_jack,
-			   void *calibration, enum tabla_micbias_num micbis,
-			   int (*mclk_cb_fn) (struct snd_soc_codec*, int),
-			   int read_fw_bin, u32 mclk_rate);
+			   const struct tabla_mbhc_config *cfg);
 
 struct anc_header {
 	u32 reserved[3];
 	u32 num_anc_slots;
 };
 
-extern int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
+extern int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
+			     bool dapm);
 
 extern void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg
 				       *btn_det,
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index a537e4a..1dae5c4 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -150,7 +150,7 @@
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct wm8711_priv *wm8711 =  snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
+	u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfff3;
 	int i = get_coeff(wm8711->sysclk, params_rate(params));
 	u16 srate = (coeff_div[i].sr << 2) |
 		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
@@ -231,7 +231,7 @@
 		unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = 0;
+	u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0x000c;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 76b4361..f5a0ec4 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -463,6 +463,7 @@
 		snd_soc_write(codec, WM8731_PWR, 0xffff);
 		regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
 				       wm8731->supplies);
+		codec->cache_sync = 1;
 		break;
 	}
 	codec->dapm.bias_level = level;
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 25af901..c173aee 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -337,10 +337,10 @@
 		iface |= 0x0004;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
-		iface |= 0x0003;
+		iface |= 0x000C;
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		iface |= 0x0013;
+		iface |= 0x001C;
 		break;
 	default:
 		return -EINVAL;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index aa091a0..66d18a3 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -189,6 +189,9 @@
 	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 	u16 ioctl;
 
+	if (wm8753->dai_func == ucontrol->value.integer.value[0])
+		return 0;
+
 	if (codec->active)
 		return -EBUSY;
 
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 9b3bba4..0fce199 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -868,7 +868,7 @@
 SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0,
 	     WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0),
 SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
-	     WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0),
+	     WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 1),
 
 SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
 SOC_ENUM("High Pass Filter Mode", hpf_mode),
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 25580e3..d4ecb3f 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -472,6 +472,8 @@
 		break;
 	}
 
+	codec->dapm.bias_level = level;
+
 	return ret;
 }
 
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 5e05eed..6d0cae4 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1957,7 +1957,13 @@
 
 static int wm8962_reset(struct snd_soc_codec *codec)
 {
-	return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243);
+	int ret;
+
+	ret = snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243);
+	if (ret != 0)
+		return ret;
+
+	return snd_soc_write(codec, WM8962_PLL_SOFTWARE_RESET, 0);
 }
 
 static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
@@ -2018,7 +2024,6 @@
 			    struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	u16 *reg_cache = codec->reg_cache;
 	int ret;
 
 	/* Apply the update (if any) */
@@ -2027,16 +2032,19 @@
 		return 0;
 
 	/* If the left PGA is enabled hit that VU bit... */
-	if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
-		return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
-				     reg_cache[WM8962_SPKOUTL_VOLUME]);
+	ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+	if (ret & WM8962_SPKOUTL_PGA_ENA) {
+		snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+			      snd_soc_read(codec, WM8962_SPKOUTL_VOLUME));
+		return 1;
+	}
 
 	/* ...otherwise the right.  The VU is stereo. */
-	if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
-		return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
-				     reg_cache[WM8962_SPKOUTR_VOLUME]);
+	if (ret & WM8962_SPKOUTR_PGA_ENA)
+		snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+			      snd_soc_read(codec, WM8962_SPKOUTR_VOLUME));
 
-	return 0;
+	return 1;
 }
 
 static const char *cap_hpf_mode_text[] = {
@@ -2336,7 +2344,6 @@
 			 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 *reg_cache = codec->reg_cache;
 	int reg;
 
 	switch (w->shift) {
@@ -2359,7 +2366,7 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		return snd_soc_write(codec, reg, reg_cache[reg]);
+		return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
 	default:
 		BUG();
 		return -EINVAL;
@@ -2968,13 +2975,13 @@
 	case SNDRV_PCM_FORMAT_S16_LE:
 		break;
 	case SNDRV_PCM_FORMAT_S20_3LE:
-		aif0 |= 0x40;
+		aif0 |= 0x4;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
-		aif0 |= 0x80;
+		aif0 |= 0x8;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
-		aif0 |= 0xc0;
+		aif0 |= 0xc;
 		break;
 	default:
 		return -EINVAL;
@@ -3027,9 +3034,9 @@
 	int aif0 = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_DSP_A:
-		aif0 |= WM8962_LRCLK_INV;
 	case SND_SOC_DAIFMT_DSP_B:
+		aif0 |= WM8962_LRCLK_INV | 3;
+	case SND_SOC_DAIFMT_DSP_A:
 		aif0 |= 3;
 
 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -3822,6 +3829,11 @@
 	 */
 	snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
 
+	/* Ensure that the oscillator and PLLs are disabled */
+	snd_soc_update_bits(codec, WM8962_PLL2,
+			    WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+			    0);
+
 	regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
 
 	if (pdata) {
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 83014a7..2194912 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -56,7 +56,7 @@
 static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	struct wm8994 *control = wm8994->control_data;
+	struct wm8994 *control = codec->control_data;
 
 	switch (reg) {
 	case WM8994_GPIO_1:
@@ -1266,7 +1266,7 @@
 SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
 
 SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
-SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
 
 SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
 
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 9e370d1..8712a9f 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -562,14 +562,14 @@
 };
 
 static const struct snd_kcontrol_new line2_mix[] = {
-SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0),
-SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0),
 SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new line2n_mix[] = {
-SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
-SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
 };
 
 static const struct snd_kcontrol_new line2p_mix[] = {
@@ -589,6 +589,8 @@
 SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0),
 SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0),
 
+SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0),
+
 SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
 		   in1l_pga, ARRAY_SIZE(in1l_pga)),
 SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
@@ -794,9 +796,11 @@
 };
 
 static const struct snd_soc_dapm_route lineout1_se_routes[] = {
+	{ "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
 	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
 
+	{ "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
 
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
@@ -804,8 +808,8 @@
 };
 
 static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
-	{ "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
-	{ "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
+	{ "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" },
+	{ "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" },
 	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
@@ -813,9 +817,11 @@
 };
 
 static const struct snd_soc_dapm_route lineout2_se_routes[] = {
+	{ "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
 	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
 
+	{ "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 313e0cc..bd811a0 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -698,6 +698,7 @@
 
 	/* Initialize the the device_attribute structure */
 	dev_attr = &ssi_private->dev_attr;
+	sysfs_attr_init(&dev_attr->attr);
 	dev_attr->attr.name = "statistics";
 	dev_attr->attr.mode = S_IRUGO;
 	dev_attr->show = fsl_sysfs_ssi_show;
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 1ed5f74..6bbbe5e 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -126,12 +126,25 @@
 	select SND_SOC_QDSP6
 	select SND_SOC_MSM_STUB
 	select SND_SOC_WCD9310
+	select SND_SOC_WCD9304
 	select SND_SOC_MSM_HOSTLESS_PCM
 	select SND_SOC_MSM_QDSP6_HDMI_AUDIO
 	default n
 	help
 	 To add support for SoC audio on MSM8960 and APQ8064 boards
 
+config SND_SOC_MDM9615
+	tristate "SoC Machine driver for MDM9615 boards"
+	depends on ARCH_MSM9615
+	select SND_SOC_VOICE
+	select SND_SOC_QDSP6
+	select SND_SOC_MSM_STUB
+	select SND_SOC_WCD9310
+	select SND_SOC_MSM_HOSTLESS_PCM
+	select SND_DYNAMIC_MINORS
+	help
+	 To add support for SoC audio on MDM9615 boards
+
 config SND_SOC_MSM8660_APQ
         tristate "Soc Machine driver for APQ8060 WM8903 codec"
         depends on ARCH_MSM8X60
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 6f2d651..a6ec1a7 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -62,7 +62,7 @@
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
 obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
 
-snd-soc-msm8960-objs := msm8960.o apq8064.o
+snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o
 obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
 
 # Generic MSM drivers
@@ -71,3 +71,7 @@
 
 snd-soc-msm8660-apq-objs := msm8660-apq-wm8903.o
 obj-$(CONFIG_SND_SOC_MSM8660_APQ) += snd-soc-msm8660-apq.o
+
+# for MDM 9615 sound card driver
+snd-soc-mdm9615-objs := mdm9615.o
+obj-$(CONFIG_SND_SOC_MDM9615) += snd-soc-mdm9615.o
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index bcf6784..3388261 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -55,9 +55,19 @@
 
 #define TABLA_EXT_CLK_RATE 12288000
 
-#define TABLA_MBHC_DEF_BUTTONS 3
+#define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+	SLIM_2_RX_1 = 147, /* HDMI RX */
+	SLIM_3_RX_1 = 148, /* In-call recording RX */
+	SLIM_3_RX_2 = 149, /* In-call recording RX */
+	SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
+};
+
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
 static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
 static int msm_spk_control;
@@ -77,7 +87,21 @@
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
-static void *tabla_mbhc_cal;
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm);
+
+static struct tabla_mbhc_config mbhc_cfg = {
+	.headset_jack = &hs_jack,
+	.button_jack = &button_jack,
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = TABLA_MICBIAS2,
+	.mclk_cb_fn = msm_enable_codec_ext_clk,
+	.mclk_rate = TABLA_EXT_CLK_RATE,
+	.gpio = 0, /* MBHC GPIO is not configured */
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+};
 
 static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
 {
@@ -300,8 +324,8 @@
 	return 0;
 }
 
-int msm_enable_codec_ext_clk(
-		struct snd_soc_codec *codec, int enable)
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+				    bool dapm)
 {
 	pr_debug("%s: enable = %d\n", __func__, enable);
 	if (enable) {
@@ -313,7 +337,7 @@
 		if (codec_clk) {
 			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
 			clk_enable(codec_clk);
-			tabla_mclk_enable(codec, 1);
+			tabla_mclk_enable(codec, 1, dapm);
 		} else {
 			pr_err("%s: Error setting Tabla MCLK\n", __func__);
 			clk_users--;
@@ -328,7 +352,7 @@
 			pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					 __func__, clk_users);
 			clk_disable(codec_clk);
-			tabla_mclk_enable(codec, 0);
+			tabla_mclk_enable(codec, 0, dapm);
 		}
 	}
 	return 0;
@@ -351,7 +375,7 @@
 		if (codec_clk) {
 			clk_set_rate(codec_clk, 12288000);
 			clk_enable(codec_clk);
-			tabla_mclk_enable(w->codec, 1);
+			tabla_mclk_enable(w->codec, 1, true);
 
 		} else {
 			pr_err("%s: Error setting Tabla MCLK\n", __func__);
@@ -373,7 +397,7 @@
 					__func__, clk_users);
 
 			clk_disable(codec_clk);
-			tabla_mclk_enable(w->codec, 0);
+			tabla_mclk_enable(w->codec, 0, true);
 		}
 		break;
 	}
@@ -604,7 +628,7 @@
 	void *tabla_cal;
 	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
 	u16 *btn_low, *btn_high;
-	u8 *n_cic, *gain;
+	u8 *n_ready, *n_cic, *gain;
 
 	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
 						TABLA_MBHC_DEF_RLOADS),
@@ -625,25 +649,21 @@
 	S(mic_current, TABLA_PID_MIC_5_UA);
 	S(hph_current, TABLA_PID_MIC_5_UA);
 	S(t_mic_pid, 100);
-	S(t_ins_complete, 1000);
+	S(t_ins_complete, 250);
 	S(t_ins_retry, 200);
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
 	S(v_no_mic, 30);
-	S(v_hs_max, 1450);
+	S(v_hs_max, 1550);
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
-	S(c[0], 6);
-	S(c[1], 10);
-	S(c[2], 10);
-	S(c[3], 14);
-	S(c[4], 14);
-	S(c[5], 16);
-	S(c[6], 0);
-	S(c[7], 0);
-	S(nc, 5);
-	S(n_meas, 11);
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 3);
 	S(mbhc_nsc, 11);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
 	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
 	S(v_btn_press_delta_sta, 100);
 	S(v_btn_press_delta_cic, 50);
@@ -651,15 +671,28 @@
 	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
 	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
 	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
-	btn_low[0] = 0;
-	btn_high[0] = 40;
-	btn_low[1] = 60;
-	btn_high[1] = 140;
-	btn_low[2] = 160;
-	btn_high[2] = 240;
+	btn_low[0] = -50;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 38;
+	btn_low[2] = 39;
+	btn_high[2] = 64;
+	btn_low[3] = 65;
+	btn_high[3] = 91;
+	btn_low[4] = 92;
+	btn_high[4] = 115;
+	btn_low[5] = 116;
+	btn_high[5] = 141;
+	btn_low[6] = 142;
+	btn_high[6] = 163;
+	btn_low[7] = 164;
+	btn_high[7] = 250;
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
+	n_ready[0] = 48;
+	n_ready[1] = 38;
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
-	n_cic[0] = 120;
-	n_cic[1] = 94;
+	n_cic[0] = 60;
+	n_cic[1] = 47;
 	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
 	gain[0] = 11;
 	gain[1] = 9;
@@ -727,6 +760,49 @@
 	return ret;
 }
 
+static int msm_stubrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	rtd->pmdown_time = 0;
+
+	return 0;
+}
+
+static int msm_slimbus_1_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch = SLIM_1_RX_1, tx_ch = SLIM_1_TX_1;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: APQ BT/USB TX -> SLIMBUS_1_RX -> MDM TX shared ch %d\n",
+			__func__, rx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 RX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	} else {
+		pr_debug("%s: MDM RX -> SLIMBUS_1_TX -> APQ BT/USB Rx shared ch %d\n",
+			__func__, tx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 1, &tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 TX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	}
+
+end:
+	return ret;
+}
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -770,7 +846,7 @@
 	}
 
 	err = snd_soc_jack_new(codec, "Button Jack",
-				SND_JACK_BTN_0, &button_jack);
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
 		return err;
@@ -778,11 +854,9 @@
 
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
-	tabla_hs_detect(codec, &hs_jack, &button_jack, tabla_mbhc_cal,
-			TABLA_MICBIAS2, msm_enable_codec_ext_clk, 0,
-			TABLA_EXT_CLK_RATE);
+	err = tabla_hs_detect(codec, &mbhc_cfg);
 
-	return 0;
+	return err;
 }
 
 static struct snd_soc_dsp_link lpa_fe_media = {
@@ -910,6 +984,7 @@
 
 	return 0;
 }
+
 static int msm_aux_pcm_get_gpios(void)
 {
 	int ret = 0;
@@ -1009,6 +1084,12 @@
 	.shutdown = msm_auxpcm_shutdown,
 };
 
+static struct snd_soc_ops msm_slimbus_1_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_1_hw_params,
+	.shutdown = msm_shutdown,
+};
+
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link msm_dai[] = {
 	/* FrontEnd DAI Links */
@@ -1109,7 +1190,7 @@
 		.dsp_link = &fe_media,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
-		/* .be_id = do not care */
+		.be_id = MSM_FRONTEND_DAI_VOICE_STUB,
 	},
 	/* Backend DAI Links */
 	{
@@ -1253,6 +1334,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,
 	},
 	{
@@ -1267,10 +1349,35 @@
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm_be_ops,
 	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup =  msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+	},
 };
 
 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),
 };
@@ -1337,8 +1444,8 @@
 		return -ENODEV;
 	}
 
-	tabla_mbhc_cal = def_tabla_mbhc_cal();
-	if (!tabla_mbhc_cal) {
+	mbhc_cfg.calibration = def_tabla_mbhc_cal();
+	if (!mbhc_cfg.calibration) {
 		pr_err("Calibration data allocation failed\n");
 		return -ENOMEM;
 	}
@@ -1346,7 +1453,7 @@
 	msm_snd_device = platform_device_alloc("soc-audio", 0);
 	if (!msm_snd_device) {
 		pr_err("Platform device allocation failed\n");
-		kfree(tabla_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return -ENOMEM;
 	}
 
@@ -1354,7 +1461,7 @@
 	ret = platform_device_add(msm_snd_device);
 	if (ret) {
 		platform_device_put(msm_snd_device);
-		kfree(tabla_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return ret;
 	}
 
@@ -1377,6 +1484,7 @@
 	}
 	msm_free_headset_mic_gpios();
 	platform_device_unregister(msm_snd_device);
+	kfree(mbhc_cfg.calibration);
 }
 module_exit(msm_audio_exit);
 
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
new file mode 100644
index 0000000..b122f64
--- /dev/null
+++ b/sound/soc/msm/mdm9615.c
@@ -0,0 +1,1249 @@
+/* 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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8018.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dsp.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9310.h"
+
+/* 9615 machine driver */
+
+#define PM8018_GPIO_BASE		NR_GPIO_IRQS
+#define PM8018_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8018_GPIO_BASE)
+
+#define MDM9615_SPK_ON 1
+#define MDM9615_SPK_OFF 0
+
+#define MDM9615_SLIM_0_RX_MAX_CHANNELS		2
+#define MDM9615_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS	0x1
+#define BOTTOM_SPK_AMP_NEG	0x2
+#define TOP_SPK_AMP_POS		0x4
+#define TOP_SPK_AMP_NEG		0x8
+
+#define GPIO_AUX_PCM_DOUT 63
+#define GPIO_AUX_PCM_DIN 64
+#define GPIO_AUX_PCM_SYNC 65
+#define GPIO_AUX_PCM_CLK 66
+
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 8
+#define TABLA_MBHC_DEF_RLOADS 5
+
+static u32 top_spk_pamp_gpio  = PM8018_GPIO_PM_TO_SYS(18);
+static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(19);
+static int mdm9615_spk_control;
+static int mdm9615_ext_bottom_spk_pamp;
+static int mdm9615_ext_top_spk_pamp;
+static int mdm9615_slim_0_rx_ch = 1;
+static int mdm9615_slim_0_tx_ch = 1;
+
+static int mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+static int mdm9615_btsco_ch = 1;
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static int mdm9615_headset_gpios_configured;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+static int mdm9615_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm);
+static struct tabla_mbhc_config mbhc_cfg = {
+	.headset_jack = &hs_jack,
+	.button_jack = &button_jack,
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = TABLA_MICBIAS2,
+	.mclk_cb_fn = mdm9615_enable_codec_ext_clk,
+	.mclk_rate = TABLA_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+};
+
+static void mdm9615_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+{
+	int ret = 0;
+
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull           = PM_GPIO_PULL_NO,
+		.vin_sel        = PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+
+		ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
+				__func__, bottom_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Bottom Spk Ampl"
+				" gpio %u\n", __func__, bottom_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
+			gpio_direction_output(bottom_spk_pamp_gpio, 1);
+		}
+
+	} else if (spk_amp_gpio == top_spk_pamp_gpio) {
+
+		ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting GPIO %d\n", __func__,
+				top_spk_pamp_gpio);
+			return;
+		}
+		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
+		if (ret)
+			pr_err("%s: Failed to configure Top Spk Ampl"
+				" gpio %u\n", __func__, top_spk_pamp_gpio);
+		else {
+			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
+			gpio_direction_output(top_spk_pamp_gpio, 1);
+		}
+	} else {
+		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
+			" gpio = %u\n", __func__, spk_amp_gpio);
+		return;
+	}
+}
+
+static void mdm9615_ext_spk_power_amp_on(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Bottom Speaker Ampl already "
+				"turned on. spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		mdm9615_ext_bottom_spk_pamp |= spk;
+
+		if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+			(mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+			mdm9615_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
+			pr_debug("%s: slepping 4 ms after turning on external "
+				" Bottom Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+
+		if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Top Speaker Ampl already"
+				"turned on. spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		mdm9615_ext_top_spk_pamp |= spk;
+
+		if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+			(mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+
+			mdm9615_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
+			pr_debug("%s: sleeping 4 ms after turning on "
+				" external Top Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+	} else  {
+
+		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void mdm9615_ext_spk_power_amp_off(u32 spk)
+{
+	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+		if (!mdm9615_ext_bottom_spk_pamp)
+			return;
+
+		gpio_direction_output(bottom_spk_pamp_gpio, 0);
+		gpio_free(bottom_spk_pamp_gpio);
+		mdm9615_ext_bottom_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Bottom"
+			" Speaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+
+	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+
+		if (!mdm9615_ext_top_spk_pamp)
+			return;
+
+		gpio_direction_output(top_spk_pamp_gpio, 0);
+		gpio_free(top_spk_pamp_gpio);
+		mdm9615_ext_top_spk_pamp = 0;
+
+		pr_debug("%s: sleeping 4 ms after turning off external Top"
+			" Spkaker Ampl\n", __func__);
+
+		usleep_range(4000, 4000);
+	} else  {
+
+		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void mdm9615_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
+	if (mdm9615_spk_control == MDM9615_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+	}
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int mdm9615_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
+	ucontrol->value.integer.value[0] = mdm9615_spk_control;
+	return 0;
+}
+static int mdm9615_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (mdm9615_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	mdm9615_spk_control = ucontrol->value.integer.value[0];
+	mdm9615_ext_control(codec);
+	return 1;
+}
+static int mdm9615_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+
+	} else {
+		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+			mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+			mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
+		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+			mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
+		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
+			mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+static int mdm9615_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm)
+{
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	if (enable) {
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users != 1)
+			return 0;
+
+		if (codec_clk) {
+			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+			clk_enable(codec_clk);
+			tabla_mclk_enable(codec, 1, dapm);
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+	} else {
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users == 0)
+			return 0;
+		clk_users--;
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					 __func__, clk_users);
+			clk_disable(codec_clk);
+			tabla_mclk_enable(codec, 0, dapm);
+		}
+	}
+	return 0;
+}
+
+static int mdm9615_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return mdm9615_enable_codec_ext_clk(w->codec, 1, true);
+	case SND_SOC_DAPM_POST_PMD:
+		return mdm9615_enable_codec_ext_clk(w->codec, 0, true);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget mdm9615_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	mdm9615_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", mdm9615_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", mdm9615_spkramp_event),
+
+	SND_SOC_DAPM_SPK("Ext Spk Top Pos", mdm9615_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top Neg", mdm9615_spkramp_event),
+
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+
+};
+
+static const struct snd_soc_dapm_route common_audio_map[] = {
+
+	{"RX_BIAS", NULL, "MCLK"},
+	{"LDO_H", NULL, "MCLK"},
+
+	/* Speaker path */
+	{"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+
+	{"Ext Spk Top Pos", NULL, "LINEOUT2"},
+	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+
+	/* Microphone path */
+	{"AMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Handset Mic"},
+
+	{"AMIC2", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Headset Mic"},
+
+	/**
+	 * AMIC3 and AMIC4 inputs are connected to ANC microphones
+	 * These mics are biased differently on CDP and FLUID
+	 * routing entries below are based on bias arrangement
+	 * on FLUID.
+	 */
+	{"AMIC3", NULL, "MIC BIAS3 Internal1"},
+	{"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
+
+	{"AMIC4", NULL, "MIC BIAS1 Internal2"},
+	{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+
+	{"HEADPHONE", NULL, "LDO_H"},
+
+	/**
+	 * The digital Mic routes are setup considering
+	 * fluid as default device.
+	 */
+
+	/**
+	 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
+	 * Digital Mic GM5 on CDP mainboard.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
+	 * Digital Mic GM6 on CDP mainboard.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3. Back Bottom Digital Mic on Fluid.
+	 * Digital Mic GM1 on CDP mainboard.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4. Back top Digital Mic on Fluid.
+	 * Digital Mic GM2 on CDP mainboard.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5. Front top Digital Mic on Fluid.
+	 * Digital Mic GM3 on CDP mainboard.
+	 * Conncted to DMIC5 Input on Tabla codec.
+	 */
+	{"DMIC5", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+	/* Tabla digital Mic6 - back bottom digital Mic on Liquid and
+	 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic6"},
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *slim0_rx_ch_text[] = {"One", "Two"};
+static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum mdm9615_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+};
+
+static const char *btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum mdm9615_btsco_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int mdm9615_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: mdm9615_slim_0_rx_ch  = %d\n", __func__,
+		 mdm9615_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = mdm9615_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int mdm9615_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	mdm9615_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: mdm9615_slim_0_rx_ch = %d\n", __func__,
+		 mdm9615_slim_0_rx_ch);
+	return 1;
+}
+
+static int mdm9615_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: mdm9615_slim_0_tx_ch  = %d\n", __func__,
+		 mdm9615_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = mdm9615_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int mdm9615_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	mdm9615_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: mdm9615_slim_0_tx_ch = %d\n", __func__,
+		 mdm9615_slim_0_tx_ch);
+	return 1;
+}
+
+static int mdm9615_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: mdm9615_btsco_rate  = %d", __func__, mdm9615_btsco_rate);
+	ucontrol->value.integer.value[0] = mdm9615_btsco_rate;
+	return 0;
+}
+
+static int mdm9615_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 1:
+		mdm9615_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: mdm9615_btsco_rate = %d\n", __func__, mdm9615_btsco_rate);
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_mdm9615_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], mdm9615_get_spk,
+		mdm9615_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", mdm9615_enum[1],
+		mdm9615_slim_0_rx_ch_get, mdm9615_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", mdm9615_enum[2],
+		mdm9615_slim_0_tx_ch_get, mdm9615_slim_0_tx_ch_put),
+};
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", mdm9615_btsco_enum[0],
+		mdm9615_btsco_rate_get, mdm9615_btsco_rate_put),
+};
+
+static int mdm9615_btsco_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err = 0;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	err = snd_soc_add_platform_controls(platform,
+			int_btsco_rate_mixer_controls,
+		ARRAY_SIZE(int_btsco_rate_mixer_controls));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static void *def_tabla_mbhc_cal(void)
+{
+	void *tabla_cal;
+	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_ready, *n_cic, *gain;
+
+	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+						TABLA_MBHC_DEF_RLOADS),
+			    GFP_KERNEL);
+	if (!tabla_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 4);
+	S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+	S(mic_current, TABLA_PID_MIC_5_UA);
+	S(hph_current, TABLA_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 250);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 1550);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 3);
+	S(mbhc_nsc, 11);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
+	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
+	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
+	btn_low[0] = -50;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 38;
+	btn_low[2] = 39;
+	btn_high[2] = 64;
+	btn_low[3] = 65;
+	btn_high[3] = 91;
+	btn_low[4] = 92;
+	btn_high[4] = 115;
+	btn_low[5] = 116;
+	btn_high[5] = 141;
+	btn_low[6] = 142;
+	btn_high[6] = 163;
+	btn_low[7] = 164;
+	btn_high[7] = 250;
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
+	n_ready[0] = 48;
+	n_ready[1] = 38;
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+	n_cic[0] = 60;
+	n_cic[1] = 47;
+	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 9;
+
+	return tabla_cal;
+}
+
+static int mdm9615_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+	pr_debug("%s: ch=%d\n", __func__,
+					mdm9615_slim_0_rx_ch);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				mdm9615_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+				mdm9615_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+	} else {
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				mdm9615_slim_0_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai,
+				mdm9615_slim_0_tx_ch, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+								__func__);
+			goto end;
+		}
+
+
+	}
+end:
+	return ret;
+}
+
+static int mdm9615_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+	rtd->pmdown_time = 0;
+	err = snd_soc_add_controls(codec, tabla_mdm9615_controls,
+				ARRAY_SIZE(tabla_mdm9615_controls));
+	if (err < 0)
+		return err;
+
+	snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
+				ARRAY_SIZE(mdm9615_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, common_audio_map,
+		ARRAY_SIZE(common_audio_map));
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+				SND_JACK_OC_HPHR),
+			       &hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	err = snd_soc_jack_new(codec, "Button Jack",
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+	err = tabla_hs_detect(codec, &mbhc_cfg);
+
+	return err;
+}
+
+static struct snd_soc_dsp_link fe_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+/* bi-directional media definition for hostless PCM device */
+static struct snd_soc_dsp_link bidir_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static int mdm9615_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = mdm9615_slim_0_rx_ch;
+
+	return 0;
+}
+
+static int mdm9615_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = mdm9615_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int mdm9615_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = mdm9615_btsco_rate;
+	channels->min = channels->max = mdm9615_btsco_ch;
+
+	return 0;
+}
+static int mdm9615_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+static int mdm9615_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int mdm9615_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+static int mdm9615_startup(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	return 0;
+}
+
+static int mdm9615_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = mdm9615_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void mdm9615_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	mdm9615_aux_pcm_free_gpios();
+}
+
+static void mdm9615_shutdown(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+}
+
+static struct snd_soc_ops mdm9615_be_ops = {
+	.startup = mdm9615_startup,
+	.hw_params = mdm9615_hw_params,
+	.shutdown = mdm9615_shutdown,
+};
+
+static struct snd_soc_ops mdm9615_auxpcm_be_ops = {
+	.startup = mdm9615_auxpcm_startup,
+	.shutdown = mdm9615_auxpcm_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mdm9615_dai_common[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MDM9615 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MDM9615 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name	= "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	/* Hostless PMC purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &bidir_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name	= "AUXPCM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &bidir_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	/* Backend BT DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6.12288",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-rx",
+		.init = &mdm9615_btsco_init,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+		.be_hw_params_fixup = mdm9615_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = mdm9615_btsco_be_hw_params_fixup,
+	},
+
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6.224",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+		.ops = &mdm9615_auxpcm_be_ops,
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+	},
+
+};
+
+static struct snd_soc_dai_link mdm9615_dai_delta_tabla[] = {
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &mdm9615_audrx_init,
+		.be_hw_params_fixup = mdm9615_slim_0_rx_be_hw_params_fixup,
+		.ops = &mdm9615_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = mdm9615_slim_0_tx_be_hw_params_fixup,
+		.ops = &mdm9615_be_ops,
+	},
+};
+
+static struct snd_soc_dai_link mdm9615_dai[
+					 ARRAY_SIZE(mdm9615_dai_common) +
+					 ARRAY_SIZE(mdm9615_dai_delta_tabla)];
+
+static struct snd_soc_card snd_soc_card_mdm9615 = {
+		.name		= "mdm9615-tabla-snd-card",
+		.dai_link	= mdm9615_dai,
+		.num_links	= ARRAY_SIZE(mdm9615_dai),
+};
+
+static struct platform_device *mdm9615_snd_device;
+
+static int mdm9615_configure_headset_mic_gpios(void)
+{
+	int ret;
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull	   = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	ret = gpio_request(PM8018_GPIO_PM_TO_SYS(23), "AV_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			PM8018_GPIO_PM_TO_SYS(23));
+		return ret;
+	}
+
+	ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(23), &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			PM8018_GPIO_PM_TO_SYS(23));
+	else
+		gpio_direction_output(PM8018_GPIO_PM_TO_SYS(23), 0);
+
+	ret = gpio_request(PM8018_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			PM8018_GPIO_PM_TO_SYS(35));
+		gpio_free(PM8018_GPIO_PM_TO_SYS(23));
+		return ret;
+	}
+	ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(35), &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			PM8018_GPIO_PM_TO_SYS(35));
+	else
+		gpio_direction_output(PM8018_GPIO_PM_TO_SYS(35), 0);
+
+	return 0;
+}
+static void mdm9615_free_headset_mic_gpios(void)
+{
+	if (mdm9615_headset_gpios_configured) {
+		gpio_free(PM8018_GPIO_PM_TO_SYS(23));
+		gpio_free(PM8018_GPIO_PM_TO_SYS(35));
+	}
+}
+
+static int __init mdm9615_audio_init(void)
+{
+	int ret;
+
+	if (!cpu_is_msm9615()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return -ENODEV ;
+	}
+
+	mbhc_cfg.calibration = def_tabla_mbhc_cal();
+	if (!mbhc_cfg.calibration) {
+		pr_err("Calibration data allocation failed\n");
+		return -ENOMEM;
+	}
+
+	mdm9615_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!mdm9615_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		kfree(mbhc_cfg.calibration);
+		return -ENOMEM;
+	}
+
+	memcpy(mdm9615_dai, mdm9615_dai_common, sizeof(mdm9615_dai_common));
+	memcpy(mdm9615_dai + ARRAY_SIZE(mdm9615_dai_common),
+		mdm9615_dai_delta_tabla, sizeof(mdm9615_dai_delta_tabla));
+
+	platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
+	ret = platform_device_add(mdm9615_snd_device);
+	if (ret) {
+		platform_device_put(mdm9615_snd_device);
+		kfree(mbhc_cfg.calibration);
+		return ret;
+	}
+
+	if (mdm9615_configure_headset_mic_gpios()) {
+		pr_err("%s Fail to configure headset mic gpios\n", __func__);
+		mdm9615_headset_gpios_configured = 0;
+	} else
+		mdm9615_headset_gpios_configured = 1;
+
+	return ret;
+
+}
+module_init(mdm9615_audio_init);
+
+static void __exit mdm9615_audio_exit(void)
+{
+	if (!cpu_is_msm9615()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
+	mdm9615_free_headset_mic_gpios();
+	platform_device_unregister(mdm9615_snd_device);
+	kfree(mbhc_cfg.calibration);
+}
+module_exit(mdm9615_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MDM9615");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index f0f17a9..7d99322 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.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
@@ -179,6 +179,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
+	struct asm_aac_cfg aac_cfg;
 	int ret;
 
 	pr_debug("%s\n", __func__);
@@ -189,14 +190,33 @@
 	prtd->samp_rate = runtime->rate;
 	prtd->channel_mode = runtime->channels;
 	prtd->out_head = 0;
+	atomic_set(&prtd->out_count, runtime->periods);
+
 	if (prtd->enabled)
 		return 0;
 
-	ret = q6asm_media_format_block(prtd->audio_client, compr->codec);
-	if (ret < 0)
-		pr_info("%s: CMD Format block failed\n", __func__);
-
-	atomic_set(&prtd->out_count, runtime->periods);
+	switch (compr->info.codec_param.codec.id) {
+	case SND_AUDIOCODEC_MP3:
+		ret = q6asm_media_format_block(prtd->audio_client,
+				compr->codec);
+		if (ret < 0)
+			pr_info("%s: CMD Format block failed\n", __func__);
+		break;
+	case SND_AUDIOCODEC_AAC:
+		pr_debug("SND_AUDIOCODEC_AAC\n");
+		memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
+		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+		aac_cfg.format = 0x03;
+		aac_cfg.ch_cfg = runtime->channels;
+		aac_cfg.sample_rate =  runtime->rate;
+		ret = q6asm_media_format_block_aac(prtd->audio_client,
+					&aac_cfg);
+		if (ret < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	prtd->enabled = 1;
 	prtd->cmd_ack = 0;
@@ -250,6 +270,7 @@
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
 	compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
 	compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
+	compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	/* Add new codecs here */
 }
 
@@ -504,6 +525,10 @@
 			pr_debug("SND_AUDIOCODEC_MP3\n");
 			compr->codec = FORMAT_MP3;
 			break;
+		case SND_AUDIOCODEC_AAC:
+			pr_debug("SND_AUDIOCODEC_AAC\n");
+			compr->codec = FORMAT_MPEG4_AAC;
+			break;
 		default:
 			pr_debug("FORMAT_LINEAR_PCM\n");
 			compr->codec = FORMAT_LINEAR_PCM;
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index 6907ded..3333344 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -14,10 +14,8 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/wcd9310/core.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <linux/clk.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
@@ -25,7 +23,6 @@
 #include <sound/q6afe.h>
 #include <sound/q6adm.h>
 #include <sound/msm-dai-q6.h>
-#include <mach/clk.h>
 #include <mach/msm_hdmi_audio.h>
 
 
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index f23a6a0..3dca43b 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -14,7 +14,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
@@ -24,6 +24,7 @@
 #include <sound/apr_audio.h>
 #include <sound/q6afe.h>
 #include <sound/msm-dai-q6.h>
+#include <sound/pcm_params.h>
 #include <mach/clk.h>
 
 enum {
@@ -39,6 +40,9 @@
 };
 
 static struct clk *pcm_clk;
+static DEFINE_MUTEX(aux_pcm_mutex);
+static int aux_pcm_count;
+static struct msm_dai_auxpcm_pdata *auxpcm_plat_data;
 
 static u8 num_of_bits_set(u8 sd_line_mask)
 {
@@ -100,6 +104,7 @@
 			break;
 		}
 	}
+	dai_data->rate = params_rate(params);
 	/* Q6 only supports 16 as now */
 	dai_data->port_config.mi2s.bitwidth = 16;
 
@@ -215,7 +220,6 @@
 	dai_data->channels = params_channels(params);
 	dai_data->rate = params_rate(params);
 
-	dai_data->port_config.slimbus.slimbus_dev_id =  AFE_SLIMBUS_DEVICE_1;
 	/* Q6 only supports 16 as now */
 	dai_data->port_config.slim_sch.bit_width = 16;
 	dai_data->port_config.slim_sch.data_format = 0;
@@ -283,27 +287,6 @@
 	return 0;
 }
 
-static int get_frame_size(u16 rate, u16 ch)
-{
-	if (rate == 8000) {
-		if (ch == 1)
-			return 128 * 2;
-		else
-			return 128 * 2 * 2;
-	} else if (rate == 16000) {
-		if (ch == 1)
-			return 128 * 2 * 2;
-		else
-			return 128 * 2 * 4;
-	} else if (rate == 48000) {
-		if (ch == 1)
-			return 128 * 2 * 6;
-		else
-			return 128 * 2 * 12;
-	} else
-		return 128 * 2 * 12;
-}
-
 static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
@@ -318,8 +301,7 @@
 
 	dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
 	dai_data->port_config.rtproxy.interleaved = 1;
-	dai_data->port_config.rtproxy.frame_sz = get_frame_size(dai_data->rate,
-					dai_data->port_config.rtproxy.num_ch);
+	dai_data->port_config.rtproxy.frame_sz = params_period_bytes(params);
 	dai_data->port_config.rtproxy.jitter =
 				dai_data->port_config.rtproxy.frame_sz/2;
 	dai_data->port_config.rtproxy.lw_mark = 0;
@@ -349,7 +331,9 @@
 		rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
 		break;
 	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
 		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
 				substream->stream);
 		break;
@@ -382,24 +366,46 @@
 static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
-	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	int rc = 0;
 
-	pr_debug("%s: dai->id = %d", __func__, dai->id);
+	mutex_lock(&aux_pcm_mutex);
 
-	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-		clk_disable(pcm_clk);
-		rc = afe_close(dai->id); /* can block */
-		if (IS_ERR_VALUE(rc))
-			dev_err(dai->dev, "fail to close AFE port\n");
-		pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
-			*dai_data->status_mask);
-		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
-
-		rc = afe_close(PCM_TX);
-		if (IS_ERR_VALUE(rc))
-			dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+	if (aux_pcm_count == 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
+				" return\n", __func__, dai->id);
+		mutex_unlock(&aux_pcm_mutex);
+		return;
 	}
+
+	aux_pcm_count--;
+
+	if (aux_pcm_count > 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+			__func__, dai->id, aux_pcm_count);
+		mutex_unlock(&aux_pcm_mutex);
+		return;
+	} else if (aux_pcm_count < 0) {
+		dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+			" aux_pcm_count = %d < 0\n",
+			__func__, dai->id, aux_pcm_count);
+		aux_pcm_count = 0;
+		mutex_unlock(&aux_pcm_mutex);
+		return;
+	}
+
+	pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
+			dai->id, aux_pcm_count);
+
+	clk_disable(pcm_clk);
+	rc = afe_close(PCM_RX); /* can block */
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close PCM_RX  AFE port\n");
+
+	rc = afe_close(PCM_TX);
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+
+	mutex_unlock(&aux_pcm_mutex);
 }
 
 static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
@@ -438,49 +444,65 @@
 	struct msm_dai_auxpcm_pdata *auxpcm_pdata =
 			(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
 
-	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-		rc = afe_q6_interface_prepare();
-		if (IS_ERR_VALUE(rc))
-			dev_err(dai->dev, "fail to open AFE APR\n");
+	mutex_lock(&aux_pcm_mutex);
 
-		rc = afe_q6_interface_prepare();
-		if (IS_ERR_VALUE(rc))
-			dev_err(dai->dev, "fail to open AFE APR\n");
-
-		pr_debug("%s:dai->id:%d dai_data->status_mask = %ld\n",
-			__func__, dai->id, *dai_data->status_mask);
-
-		/*
-		 * For AUX PCM Interface the below sequence of clk
-		 * settings and afe_open is a strict requirement.
-		 *
-		 * Also using afe_open instead of afe_port_start_nowait
-		 * to make sure the port is open before deasserting the
-		 * clock line. This is required because pcm register is
-		 * not written before clock deassert. Hence the hw does
-		 * not get updated with new setting if the below clock
-		 * assert/deasset and afe_open sequence is not followed.
-		 */
-
-		clk_reset(pcm_clk, CLK_RESET_ASSERT);
-
-		afe_open(dai->id, &dai_data->port_config,
-			dai_data->rate);
-		set_bit(STATUS_PORT_STARTED,
-			dai_data->status_mask);
-
-		afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
-
-		rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
-		if (rc < 0) {
-			pr_err("%s: clk_set_rate failed\n", __func__);
-			return rc;
-		}
-
-		clk_enable(pcm_clk);
-		clk_reset(pcm_clk, CLK_RESET_DEASSERT);
-
+	if (aux_pcm_count == 2) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
+			" return.\n", __func__, dai->id);
+		mutex_unlock(&aux_pcm_mutex);
+		return 0;
+	} else if (aux_pcm_count > 2) {
+		dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+			" aux_pcm_count = %d > 2\n",
+			__func__, dai->id, aux_pcm_count);
+		mutex_unlock(&aux_pcm_mutex);
+		return 0;
 	}
+
+	aux_pcm_count++;
+	if (aux_pcm_count == 2)  {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
+			" increment\n", __func__, dai->id, aux_pcm_count);
+		mutex_unlock(&aux_pcm_mutex);
+		return 0;
+	}
+
+	pr_debug("%s:dai->id:%d  aux_pcm_count = %d. opening afe\n",
+			__func__, dai->id, aux_pcm_count);
+
+	rc = afe_q6_interface_prepare();
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to open AFE APR\n");
+
+	/*
+	 * For AUX PCM Interface the below sequence of clk
+	 * settings and afe_open is a strict requirement.
+	 *
+	 * Also using afe_open instead of afe_port_start_nowait
+	 * to make sure the port is open before deasserting the
+	 * clock line. This is required because pcm register is
+	 * not written before clock deassert. Hence the hw does
+	 * not get updated with new setting if the below clock
+	 * assert/deasset and afe_open sequence is not followed.
+	 */
+
+	clk_reset(pcm_clk, CLK_RESET_ASSERT);
+
+	afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
+
+	afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
+
+	rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
+	if (rc < 0) {
+		pr_err("%s: clk_set_rate failed\n", __func__);
+		return rc;
+	}
+
+	clk_enable(pcm_clk);
+	clk_reset(pcm_clk, CLK_RESET_DEASSERT);
+
+	mutex_unlock(&aux_pcm_mutex);
+
 	return rc;
 }
 
@@ -502,11 +524,10 @@
 static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
 		int cmd, struct snd_soc_dai *dai)
 {
-	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	int rc = 0;
 
-	pr_debug("%s:port:%d  cmd:%d dai_data->status_mask = %ld",
-		__func__, dai->id, cmd, *dai_data->status_mask);
+	pr_debug("%s:port:%d  cmd:%d  aux_pcm_count= %d",
+		__func__, dai->id, cmd, aux_pcm_count);
 
 	switch (cmd) {
 
@@ -519,16 +540,7 @@
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-
-			clk_disable(pcm_clk);
-			afe_port_stop_nowait(dai->id);
-			clear_bit(STATUS_PORT_STARTED,
-				dai_data->status_mask);
-
-			afe_port_stop_nowait(PCM_TX);
-		}
-		break;
+		return 0;
 
 	default:
 		rc = -EINVAL;
@@ -603,8 +615,36 @@
 	struct msm_dai_auxpcm_pdata *auxpcm_pdata =
 			(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
 
-	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
-		GFP_KERNEL);
+	mutex_lock(&aux_pcm_mutex);
+
+	if (!auxpcm_plat_data)
+		auxpcm_plat_data = auxpcm_pdata;
+	else if (auxpcm_plat_data != auxpcm_pdata) {
+
+		dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
+				" same platform data\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * The clk name for AUX PCM operation is passed as platform
+	 * data to the cpu driver, since cpu drive is unaware of any
+	 * boarc specific configuration.
+	 */
+	if (!pcm_clk) {
+
+		pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
+
+		if (IS_ERR(pcm_clk)) {
+			pr_err("%s: could not get pcm_clk\n", __func__);
+			pcm_clk = NULL;
+			return -ENODEV;
+		}
+	}
+
+	mutex_unlock(&aux_pcm_mutex);
+
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
 
 	if (!dai_data) {
 		dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
@@ -613,18 +653,7 @@
 	} else
 		dev_set_drvdata(dai->dev, dai_data);
 
-	/*
-	 * The clk name for AUX PCM operation is passed as platform
-	 * data to the cpu driver, since cpu drive is unaware of any
-	 * boarc specific configuration.
-	 */
-	pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
-	if (IS_ERR(pcm_clk)) {
-		pr_err("%s: could not get pcm_clk\n", __func__);
-		return PTR_ERR(pcm_clk);
-		kfree(dai_data);
-	}
-
+	pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
 	return rc;
 }
 
@@ -635,22 +664,45 @@
 
 	dai_data = dev_get_drvdata(dai->dev);
 
-	/* If AFE port is still up, close it */
-	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-		rc = afe_close(dai->id); /* can block */
-		if (IS_ERR_VALUE(rc))
-			dev_err(dai->dev, "fail to close AFE port\n");
-		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	mutex_lock(&aux_pcm_mutex);
 
-		rc = afe_close(PCM_TX);
-		if (IS_ERR_VALUE(rc))
-			dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+	if (aux_pcm_count == 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
+				" up and return\n", __func__, dai->id);
+		goto done;
 	}
 
+	aux_pcm_count--;
 
+	if (aux_pcm_count > 0) {
+		dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+			__func__, dai->id, aux_pcm_count);
+		goto done;
+	} else if (aux_pcm_count < 0) {
+		dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+			" aux_pcm_count = %d < 0\n",
+			__func__, dai->id, aux_pcm_count);
+		goto done;
+	}
+
+	dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
+			"closing afe\n",
+		__func__, dai->id, aux_pcm_count);
+
+	rc = afe_close(PCM_RX); /* can block */
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
+
+	rc = afe_close(PCM_TX);
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
+
+done:
 	kfree(dai_data);
 	snd_soc_unregister_dai(dai->dev);
 
+	mutex_unlock(&aux_pcm_mutex);
+
 	return 0;
 }
 static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
@@ -760,14 +812,16 @@
 
 	dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
 							dai->id);
-	if (!tx_slot && !rx_slot)
-		return -EINVAL;
 	switch (dai->id) {
 	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
 		/* channel number to be between 128 and 255. For RX port
 		 * use channel numbers from 138 to 144, for TX port
 		 * use channel numbers from 128 to 137
+		 * For ports between MDM-APQ use channel numbers from 145
 		 */
+		if (!rx_slot)
+			return -EINVAL;
 		for (i = 0; i < rx_num; i++) {
 			dai_data->port_config.slim_sch.slave_ch_mapping[i] =
 							rx_slot[i];
@@ -782,10 +836,14 @@
 
 		break;
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
 		/* channel number to be between 128 and 255. For RX port
 		 * use channel numbers from 138 to 144, for TX port
 		 * use channel numbers from 128 to 137
+		 * For ports between MDM-APQ use channel numbers from 145
 		 */
+		if (!tx_slot)
+			return -EINVAL;
 		for (i = 0; i < tx_num; i++) {
 			dai_data->port_config.slim_sch.slave_ch_mapping[i] =
 							tx_slot[i];
@@ -1022,6 +1080,9 @@
 		.rate_max = 8000,
 		.rate_min = 8000,
 	},
+	.ops = &msm_dai_q6_auxpcm_ops,
+	.probe = msm_dai_q6_dai_auxpcm_probe,
+	.remove = msm_dai_q6_dai_auxpcm_remove,
 };
 
 static struct snd_soc_dai_driver msm_dai_q6_mi2s_rx_dai = {
@@ -1038,6 +1099,34 @@
 	.remove = msm_dai_q6_dai_probe,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_min = 8000,
+		.rate_max = 16000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_min = 8000,
+		.rate_max = 16000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 /* To do: change to register DAIs as batch */
 static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
 {
@@ -1072,6 +1161,16 @@
 	case SLIMBUS_0_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_tx_dai);
+		break;
+
+	case SLIMBUS_1_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_1_rx_dai);
+		break;
+	case SLIMBUS_1_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_1_tx_dai);
+		break;
 	case INT_BT_SCO_RX:
 		rc = snd_soc_register_dai(&pdev->dev,
 					&msm_dai_q6_bt_sco_rx_dai);
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index 01b8463..2135a35 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.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
@@ -63,7 +63,6 @@
 	struct snd_pcm_substream *substream = prtd->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	if (prtd->start) {
-		snd_pcm_period_elapsed(prtd->substream);
 		pr_debug("sending frame to DSP: poll_time: %d\n",
 				prtd->poll_time);
 		if (prtd->dsp_cnt == runtime->periods)
@@ -74,10 +73,6 @@
 				snd_pcm_lib_period_bytes(prtd->substream))),
 				snd_pcm_lib_period_bytes(prtd->substream));
 		prtd->dsp_cnt++;
-		prtd->poll_time = ((unsigned long)((
-				snd_pcm_lib_period_bytes(prtd->substream)
-				 * 1000 * 1000)/(runtime->rate
-				* runtime->channels * 2)));
 		hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
 					* 1000));
 
@@ -99,10 +94,6 @@
 			* snd_pcm_lib_period_bytes(prtd->substream))),
 			snd_pcm_lib_period_bytes(prtd->substream));
 		prtd->dsp_cnt++;
-		prtd->poll_time = ((unsigned long)((
-				snd_pcm_lib_period_bytes(prtd->substream)
-					* 1000 * 1000)/(runtime->rate
-					* runtime->channels * 2)));
 		pr_debug("sending frame rec to DSP: poll_time: %d\n",
 				prtd->poll_time);
 		hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
@@ -140,15 +131,17 @@
 						1000 * 1000)/
 						(runtime->rate *
 						runtime->channels * 2)));
-				pr_info("prtd->poll_time: %d",
+				pr_debug("prtd->poll_time: %d",
 						prtd->poll_time);
 				hrtimer_start(&prtd->hrt,
-				ns_to_ktime(prtd->poll_time * 1000),
-				      HRTIMER_MODE_REL);
+					ns_to_ktime(0),
+					HRTIMER_MODE_REL);
 				break;
 			}
 			case AFE_EVENT_RTPORT_STOP:
 				pr_debug("%s: event!=0\n", __func__);
+				prtd->start = 0;
+				snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
 				break;
 			case AFE_EVENT_RTPORT_LOW_WM:
 				pr_debug("%s: Underrun\n", __func__);
@@ -167,6 +160,7 @@
 			pr_debug("write done\n");
 			prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
 							(prtd->substream);
+			snd_pcm_period_elapsed(prtd->substream);
 			break;
 		default:
 			break;
@@ -206,13 +200,15 @@
 					* 1000 * 1000)/(runtime->rate
 					* runtime->channels * 2)));
 			hrtimer_start(&prtd->hrt,
-			ns_to_ktime(prtd->poll_time * 1000),
-			      HRTIMER_MODE_REL);
-			pr_info("prtd->poll_time : %d", prtd->poll_time);
+				ns_to_ktime(0),
+				HRTIMER_MODE_REL);
+			pr_debug("prtd->poll_time : %d", prtd->poll_time);
 			break;
 		}
 		case AFE_EVENT_RTPORT_STOP:
 			pr_debug("%s: event!=0\n", __func__);
+			prtd->start = 0;
+			snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
 			break;
 		case AFE_EVENT_RTPORT_LOW_WM:
 			pr_debug("%s: Underrun\n", __func__);
@@ -261,7 +257,7 @@
 		pr_err("afe-pcm:register for events failed\n");
 		return ret;
 	}
-	pr_info("%s:success\n", __func__);
+	pr_debug("%s:success\n", __func__);
 	prtd->prepared++;
 	return ret;
 }
@@ -283,7 +279,7 @@
 		pr_err("afe-pcm:register for events failed\n");
 		return ret;
 	}
-	pr_info("%s:success\n", __func__);
+	pr_debug("%s:success\n", __func__);
 	prtd->prepared++;
 	return 0;
 }
@@ -522,7 +518,7 @@
 	struct snd_card *card = rtd->card->snd_card;
 	int ret = 0;
 
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 	return ret;
@@ -530,7 +526,7 @@
 
 static int msm_afe_afe_probe(struct snd_soc_platform *platform)
 {
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	return 0;
 }
 
@@ -542,14 +538,14 @@
 
 static __devinit int msm_afe_probe(struct platform_device *pdev)
 {
-	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
 	return snd_soc_register_platform(&pdev->dev,
 				   &msm_soc_platform);
 }
 
 static int msm_afe_remove(struct platform_device *pdev)
 {
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	snd_soc_unregister_platform(&pdev->dev);
 	return 0;
 }
@@ -565,14 +561,14 @@
 
 static int __init msm_soc_platform_init(void)
 {
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	return platform_driver_register(&msm_afe_driver);
 }
 module_init(msm_soc_platform_init);
 
 static void __exit msm_soc_platform_exit(void)
 {
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	platform_driver_unregister(&msm_afe_driver);
 }
 module_exit(msm_soc_platform_exit);
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 83fd691..575839d6 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.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
@@ -27,6 +27,10 @@
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+#include <sound/timer.h>
 
 #include "msm-pcm-q6.h"
 #include "msm-pcm-routing.h"
@@ -90,8 +94,14 @@
 		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
 		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
 		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (prtd->pcm_irq_pos >= prtd->pcm_size)
+			prtd->pcm_irq_pos = 0;
 		if (atomic_read(&prtd->start))
 			snd_pcm_period_elapsed(substream);
+		else
+			if (substream->timer_running)
+				snd_timer_interrupt(substream->timer, 1);
+
 		atomic_inc(&prtd->out_count);
 		wake_up(&the_locks.write_wait);
 		if (!atomic_read(&prtd->start)) {
@@ -407,8 +417,6 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
 
-	if (prtd->pcm_irq_pos >= prtd->pcm_size)
-		prtd->pcm_irq_pos = 0;
 	pr_debug("%s: pcm_irq_pos = %d\n", __func__, prtd->pcm_irq_pos);
 	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
 }
@@ -459,7 +467,8 @@
 		return -ENOMEM;
 	}
 	buf = prtd->audio_client->port[dir].buf;
-	if (!buf && !buf[0].data)
+
+	if (buf == NULL || buf[0].data == NULL)
 		return -ENOMEM;
 
 	pr_debug("%s:buf = %p\n", __func__, buf);
@@ -482,8 +491,37 @@
 	int rc = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
+	uint64_t timestamp;
+	uint64_t temp;
 
 	switch (cmd) {
+	case SNDRV_COMPRESS_TSTAMP: {
+		struct snd_compr_tstamp tstamp;
+		pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+
+		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
+		timestamp = q6asm_get_session_time(prtd->audio_client);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * runtime->channels);
+		temp = temp * (runtime->rate/1000);
+		temp = div_u64(temp, 1000);
+		tstamp.sampling_rate = runtime->rate;
+		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
+		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
+		tstamp.timestamp = timestamp;
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld,\n",
+			__func__, tstamp.rendered, tstamp.decoded,
+			tstamp.timestamp);
+		if (copy_to_user((void *) arg, &tstamp,
+			sizeof(struct snd_compr_tstamp)))
+			return -EFAULT;
+		return 0;
+	}
 	case SNDRV_PCM_IOCTL1_RESET:
 		prtd->cmd_ack = 0;
 		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index ed880e8..dd194d6 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -638,6 +638,8 @@
 		return -ENOMEM;
 	}
 	buf = prtd->audio_client->port[dir].buf;
+	if (buf == NULL || buf[0].data == NULL)
+		return -ENOMEM;
 
 	pr_debug("%s:buf = %p\n", __func__, buf);
 	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index b01c22c..bce1455 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -120,6 +120,9 @@
 	{ VOICE_RECORD_TX, 0, NULL, 0, 0},
 	{ MI2S_RX, 0, NULL, 0, 0},
 	{ SECONDARY_I2S_RX, 0, NULL, 0, 0},
+	{ SLIMBUS_1_RX, 0, NULL, 0, 0},
+	{ SLIMBUS_1_TX, 0, NULL, 0, 0},
+	{ SLIMBUS_INVALID, 0, NULL, 0, 0},
 };
 
 
@@ -167,7 +170,7 @@
 
 	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
 		/* bad ID assigned in machine driver */
-		pr_err("%s: bad MM ID\n", __func__);
+		pr_err("%s: bad MM ID %d\n", __func__, fedai_id);
 		return;
 	}
 
@@ -254,6 +257,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 (fe_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 +370,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);
 	}
@@ -451,6 +473,55 @@
 	return 1;
 }
 
+static int msm_routing_get_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	mutex_lock(&routing_lock);
+
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	mutex_unlock(&routing_lock);
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_routing_put_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (ucontrol->value.integer.value[0]) {
+		mutex_lock(&routing_lock);
+		set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		mutex_unlock(&routing_lock);
+
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	} else {
+		mutex_lock(&routing_lock);
+		clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		mutex_unlock(&routing_lock);
+
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	}
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	return 1;
+}
+
 static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -892,6 +963,9 @@
 	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -901,6 +975,9 @@
 	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -910,6 +987,9 @@
 	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -921,6 +1001,18 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INVALID,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+};
+
 static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -957,6 +1049,18 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
+	SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_INVALID,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+};
+
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
 	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
@@ -978,6 +1082,18 @@
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new sbus_1_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
 static const struct snd_kcontrol_new fm_switch_mixer_controls =
 	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
 	0, 1, 0, msm_routing_get_switch_mixer,
@@ -1234,6 +1350,8 @@
 	SND_SOC_DAPM_AIF_OUT("VOICE_STUB_UL", "VOICE_STUB Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("STUB_RX", "Stub Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
 
 	/* Switch Definitions */
 	SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1299,12 +1417,24 @@
 	int_fm_rx_mixer_controls, ARRAY_SIZE(int_fm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AFE_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	afe_pcm_rx_mixer_controls, ARRAY_SIZE(afe_pcm_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Voice Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+	tx_voice_stub_mixer_controls, ARRAY_SIZE(tx_voice_stub_mixer_controls)),
+	SND_SOC_DAPM_MIXER("STUB_RX Mixer", SND_SOC_NOPM, 0, 0,
+	stub_rx_mixer_controls, ARRAY_SIZE(stub_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Mixer", SND_SOC_NOPM, 0, 0,
+	slimbus_1_rx_mixer_controls, ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
 	ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUXPCM_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, auxpcm_rx_port_mixer_controls,
 	ARRAY_SIZE(auxpcm_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	sbus_1_rx_port_mixer_controls,
+	ARRAY_SIZE(sbus_1_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	bt_sco_rx_port_mixer_controls,
+	ARRAY_SIZE(bt_sco_rx_port_mixer_controls)),
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -1438,8 +1568,22 @@
 	{"AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_RX Port Mixer"},
-	{"STUB_RX", NULL, "VOICE_STUB_DL"},
-	{"VOICE_STUB_UL", NULL, "STUB_TX"},
+
+	{"Voice Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+	{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
+
+	{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"STUB_RX", NULL, "STUB_RX Mixer"},
+	{"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+
+	{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
+	{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
 };
 
 static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 9515ab3..423ff5f 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -34,6 +34,8 @@
 #define LPASS_BE_MI2S_RX "(Backend) MI2S_RX"
 #define LPASS_BE_STUB_RX "(Backend) STUB_RX"
 #define LPASS_BE_STUB_TX "(Backend) STUB_TX"
+#define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
+#define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
 
 /* For multimedia front-ends, asm session is allocated dynamically.
  * Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -50,6 +52,7 @@
 	MSM_FRONTEND_DAI_VOIP,
 	MSM_FRONTEND_DAI_AFE_RX,
 	MSM_FRONTEND_DAI_AFE_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB,
 	MSM_FRONTEND_DAI_MAX,
 };
 
@@ -75,6 +78,9 @@
 	MSM_BACKEND_DAI_INCALL_RECORD_TX,
 	MSM_BACKEND_DAI_MI2S_RX,
 	MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_BACKEND_DAI_INVALID,
 	MSM_BACKEND_DAI_MAX,
 };
 
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index eafe0f9..5a0f27a 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -129,7 +129,7 @@
 
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_voice *prtd = runtime->private_data;
-	int ret;
+	int ret = 0;
 
 	mutex_lock(&prtd->lock);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -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/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index 56b4cf5..2301472 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -108,6 +108,7 @@
 	uint32_t mode;
 	uint32_t rate_type;
 	uint32_t rate;
+	uint32_t dtx_mode;
 
 	uint8_t capture_start;
 	uint8_t playback_start;
@@ -200,6 +201,31 @@
 	return 0;
 }
 
+static int msm_voip_dtx_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	voip_info.dtx_mode  = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: dtx: %d\n", __func__, voip_info.dtx_mode);
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+static int msm_voip_dtx_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	ucontrol->value.integer.value[0] = voip_info.dtx_mode;
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
 static struct snd_kcontrol_new msm_voip_controls[] = {
 	SOC_SINGLE_EXT("Voip Tx Mute", SND_SOC_NOPM, 0, 1, 0,
 				msm_voip_mute_get, msm_voip_mute_put),
@@ -208,6 +234,8 @@
 	SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
 				0, 2, msm_voip_mode_rate_config_get,
 				msm_voip_mode_rate_config_put),
+	SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
+				msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
 };
 
 static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
@@ -713,11 +741,13 @@
 		if ((prtd->play_samp_rate == 8000) &&
 					(prtd->cap_samp_rate == 8000))
 			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_NB);
+					VSS_NETWORK_ID_VOIP_NB,
+					voip_info.dtx_mode);
 		else if ((prtd->play_samp_rate == 16000) &&
 					(prtd->cap_samp_rate == 16000))
 			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_WB);
+					VSS_NETWORK_ID_VOIP_WB,
+					voip_info.dtx_mode);
 		else {
 			pr_debug("%s: Invalid rate playback %d, capture %d\n",
 				 __func__, prtd->play_samp_rate,
diff --git a/sound/soc/msm/msm-pcm.c b/sound/soc/msm/msm-pcm.c
index bea528f..ea31985 100644
--- a/sound/soc/msm/msm-pcm.c
+++ b/sound/soc/msm/msm-pcm.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -45,8 +45,6 @@
 	msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
 
 int intcnt;
-static int audio_dsp_send_buffer(struct msm_audio *prtd,
-			unsigned idx, unsigned len);
 
 struct audio_frame {
 	uint16_t count_low;
@@ -139,12 +137,15 @@
 			if (prtd->ops->playback)
 				prtd->ops->playback(prtd);
 
+			if (prtd->mmap_flag)
+				break;
+
 			spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
 			if (prtd->running) {
 				prtd->out[idx].used = 0;
 				frame = prtd->out + prtd->out_tail;
 				if (frame->used) {
-					audio_dsp_send_buffer(prtd,
+					alsa_dsp_send_buffer(prtd,
 							      prtd->out_tail,
 							      frame->used);
 					prtd->out_tail ^= 1;
@@ -414,7 +415,7 @@
 		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
 		frame = prtd->out + prtd->out_tail;
 		if (frame->used && prtd->out_needed) {
-			audio_dsp_send_buffer(prtd, prtd->out_tail,
+			alsa_dsp_send_buffer(prtd, prtd->out_tail,
 					      frame->used);
 			prtd->out_tail ^= 1;
 			prtd->out_needed--;
@@ -583,7 +584,7 @@
 }
 EXPORT_SYMBOL(alsa_buffer_read);
 
-static int audio_dsp_send_buffer(struct msm_audio *prtd,
+int alsa_dsp_send_buffer(struct msm_audio *prtd,
 					unsigned idx, unsigned len)
 {
 	audpp_cmd_pcm_intf_send_buffer cmd;
diff --git a/sound/soc/msm/msm-pcm.h b/sound/soc/msm/msm-pcm.h
index e7ddd30..6e1325b 100644
--- a/sound/soc/msm/msm-pcm.h
+++ b/sound/soc/msm/msm-pcm.h
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -173,11 +173,15 @@
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
 	int eos_ack;
+	int mmap_flag;
+	int period;
 };
 
 
 
 /* platform data */
+extern int alsa_dsp_send_buffer(struct msm_audio *prtd,
+			unsigned idx, unsigned len);
 extern int audio_dsp_out_enable(struct msm_audio *prtd, int yes);
 extern struct snd_soc_platform_driver msm_soc_platform;
 
diff --git a/sound/soc/msm/msm7201.c b/sound/soc/msm/msm7201.c
index 6408cef..f814a21 100644
--- a/sound/soc/msm/msm7201.c
+++ b/sound/soc/msm/msm7201.c
@@ -197,6 +197,12 @@
 	} req;
 
 	snd_rpc_ids.device = (int)ucontrol->value.integer.value[0];
+
+	if (ucontrol->value.integer.value[1] > 1)
+		ucontrol->value.integer.value[1] = 1;
+	if (ucontrol->value.integer.value[2] > 1)
+		ucontrol->value.integer.value[2] = 1;
+
 	req.hdr.type = 0;
 	req.hdr.rpc_vers = 2;
 
@@ -221,6 +227,8 @@
 		printk(KERN_INFO "snd device connected\n");
 		snd_mute_ear_mute = ucontrol->value.integer.value[1];
 		snd_mute_mic_mute = ucontrol->value.integer.value[2];
+		printk(KERN_ERR "%s: snd_mute_ear_mute =%d, snd_mute_mic_mute = %d\n",
+				__func__, snd_mute_ear_mute, snd_mute_mic_mute);
 	}
 
 	return rc;
@@ -251,7 +259,7 @@
 static struct snd_kcontrol_new snd_msm_controls[] = {
 	MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
 	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
-	MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
+	MSM_EXT("device", 0, snd_msm_device_info, snd_msm_device_get, \
 						 snd_msm_device_put, 0),
 };
 
@@ -331,6 +339,8 @@
 	}
 
 	ret = msm_snd_rpc_connect();
+	snd_mute_ear_mute = 0;
+	snd_mute_mic_mute = 0;
 
 	return ret;
 }
diff --git a/sound/soc/msm/msm7k-pcm.c b/sound/soc/msm/msm7k-pcm.c
index 1f36e3b..6ef924f 100644
--- a/sound/soc/msm/msm7k-pcm.c
+++ b/sound/soc/msm/msm7k-pcm.c
@@ -1,6 +1,6 @@
 /* linux/sound/soc/msm/msm7k-pcm.c
  *
- * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2012 Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -109,18 +109,20 @@
 }
 
 static struct snd_pcm_hardware msm_pcm_playback_hardware = {
-	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.info =                 SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED,
 	.formats =              USE_FORMATS,
 	.rates =                USE_RATE,
 	.rate_min =             USE_RATE_MIN,
 	.rate_max =             USE_RATE_MAX,
 	.channels_min =         USE_CHANNELS_MIN,
 	.channels_max =         USE_CHANNELS_MAX,
-	.buffer_bytes_max =     MAX_BUFFER_PLAYBACK_SIZE,
-	.period_bytes_min =     64,
-	.period_bytes_max =     MAX_PERIOD_SIZE,
-	.periods_min =          USE_PERIODS_MIN,
-	.periods_max =          USE_PERIODS_MAX,
+	.buffer_bytes_max =     4800 * 2,
+	.period_bytes_min =     4800,
+	.period_bytes_max =     4800,
+	.periods_min =          2,
+	.periods_max =          2,
 	.fifo_size =            0,
 };
 
@@ -151,10 +153,36 @@
 	.mask = 0,
 };
 
+static void msm_pcm_enqueue_data(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	unsigned int period_size;
+
+	pr_debug("prtd->out_tail =%d mmap_flag=%d\n",
+			prtd->out_tail, prtd->mmap_flag);
+	period_size = snd_pcm_lib_period_bytes(substream);
+	alsa_dsp_send_buffer(prtd, prtd->out_tail, period_size);
+	prtd->out_tail ^= 1;
+	++copy_count;
+	prtd->period++;
+	if (unlikely(prtd->period >= runtime->periods))
+		prtd->period = 0;
+
+}
+
 static void playback_event_handler(void *data)
 {
 	struct msm_audio *prtd = data;
 	snd_pcm_period_elapsed(prtd->playback_substream);
+	if (prtd->mmap_flag) {
+		if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE)
+			return;
+		if (!prtd->stopped)
+			msm_pcm_enqueue_data(prtd->playback_substream);
+		else
+			prtd->out_needed++;
+	}
 }
 
 static void capture_event_handler(void *data)
@@ -177,6 +205,26 @@
 	prtd->out_sample_rate = runtime->rate;
 	prtd->out_channel_mode = runtime->channels;
 
+	if (prtd->enabled | !(prtd->mmap_flag))
+		return 0;
+
+	prtd->data = substream->dma_buffer.area;
+	prtd->phys = substream->dma_buffer.addr;
+	prtd->out[0].data = prtd->data + 0;
+	prtd->out[0].addr = prtd->phys + 0;
+	prtd->out[0].size = BUFSZ;
+	prtd->out[1].data = prtd->data + BUFSZ;
+	prtd->out[1].addr = prtd->phys + BUFSZ;
+	prtd->out[1].size = BUFSZ;
+
+	prtd->out[0].used = prtd->pcm_count;
+	prtd->out[1].used = prtd->pcm_count;
+
+	mutex_lock(&the_locks.lock);
+	alsa_audio_configure(prtd);
+	mutex_unlock(&the_locks.lock);
+
+
 	return 0;
 }
 
@@ -231,16 +279,55 @@
 
 static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	unsigned long flag = 0;
 	int ret = 0;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			|| !prtd->mmap_flag)
+			break;
+		if (!prtd->out_needed) {
+			prtd->stopped = 0;
+			break;
+		}
+		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+		if (prtd->running == 1) {
+			if (prtd->stopped == 1) {
+				prtd->stopped = 0;
+				prtd->period = 0;
+				if (prtd->pcm_irq_pos == 0) {
+					prtd->out_tail = 0;
+					msm_pcm_enqueue_data(
+						prtd->playback_substream);
+					prtd->out_needed--;
+				} else {
+					prtd->out_tail = 1;
+					msm_pcm_enqueue_data(
+						prtd->playback_substream);
+					prtd->out_needed--;
+				}
+				if (prtd->out_needed) {
+					prtd->out_tail ^= 1;
+					msm_pcm_enqueue_data(
+						prtd->playback_substream);
+					prtd->out_needed--;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			|| !prtd->mmap_flag)
+			break;
+		prtd->stopped = 1;
 		break;
 	default:
 		ret = -EINVAL;
@@ -376,7 +463,6 @@
 	fbytes = frames_to_bytes(runtime, frames);
 	rc = alsa_send_buffer(prtd, buf, fbytes, NULL);
 	++copy_count;
-	prtd->pcm_buf_pos += fbytes;
 	if (copy_count == 1) {
 		mutex_lock(&the_locks.lock);
 		alsa_audio_configure(prtd);
@@ -469,10 +555,27 @@
 		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
 		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
 	}
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	return 0;
 
 }
 
+int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	prtd->out_head = 0; /* point to First buffer on startup */
+	prtd->mmap_flag = 1;
+	runtime->dma_bytes = snd_pcm_lib_period_bytes(substream)*2;
+	dma_mmap_coherent(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+	return 0;
+}
+
 static struct snd_pcm_ops msm_pcm_ops = {
 	.open           = msm_pcm_open,
 	.copy		= msm_pcm_copy,
@@ -482,6 +585,7 @@
 	.prepare        = msm_pcm_prepare,
 	.trigger        = msm_pcm_trigger,
 	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
 };
 
 static int pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
new file mode 100644
index 0000000..a081253
--- /dev/null
+++ b/sound/soc/msm/msm8930.c
@@ -0,0 +1,1083 @@
+/* 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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dsp.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9304.h"
+
+/* 8930 machine driver */
+
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8930_SPK_ON 1
+#define MSM8930_SPK_OFF 0
+
+#define msm8930_SLIM_0_RX_MAX_CHANNELS		2
+#define msm8930_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS	0x1
+#define BOTTOM_SPK_AMP_NEG	0x2
+#define TOP_SPK_AMP_POS		0x4
+#define TOP_SPK_AMP_NEG		0x8
+
+#define GPIO_AUX_PCM_DOUT 63
+#define GPIO_AUX_PCM_DIN 64
+#define GPIO_AUX_PCM_SYNC 65
+#define GPIO_AUX_PCM_CLK 66
+
+#define SITAR_EXT_CLK_RATE 12288000
+
+#define SITAR_MBHC_DEF_BUTTONS 3
+#define SITAR_MBHC_DEF_RLOADS 5
+
+static int msm8930_spk_control;
+static int msm8930_slim_0_rx_ch = 1;
+static int msm8930_slim_0_tx_ch = 1;
+
+static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm8930_btsco_ch = 1;
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static int msm8930_headset_gpios_configured;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+struct sitar_mbhc_calibration sitar_calib = {
+	.bias = SITAR_MICBIAS2,
+	.tldoh = 100,
+	.bg_fast_settle = 100,
+	.mic_current = SITAR_PID_MIC_5_UA,
+	.mic_pid = 100,
+	.hph_current = SITAR_PID_MIC_5_UA,
+	.setup_plug_removal_delay = 1000000,
+	.shutdown_plug_removal = 100000,
+};
+
+static void msm8930_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
+	if (msm8930_spk_control == MSM8930_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Right Pos");
+	}
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int msm8930_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
+	ucontrol->value.integer.value[0] = msm8930_spk_control;
+	return 0;
+}
+static int msm8930_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm8930_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm8930_spk_control = ucontrol->value.integer.value[0];
+	msm8930_ext_control(codec);
+	return 1;
+}
+
+static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+	/* TODO: add external speaker power amps support */
+	return 0;
+}
+int msm8930_enable_codec_ext_clk(
+		struct snd_soc_codec *codec, int enable)
+{
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	if (enable) {
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users != 1)
+			return 0;
+
+		if (codec_clk) {
+			clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
+			clk_enable(codec_clk);
+			sitar_mclk_enable(codec, 1);
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+	} else {
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users == 0)
+			return 0;
+		clk_users--;
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					 __func__, clk_users);
+			clk_disable(codec_clk);
+			sitar_mclk_enable(codec, 0);
+		}
+	}
+	return 0;
+}
+
+static int msm8930_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return msm8930_enable_codec_ext_clk(w->codec, 1);
+	case SND_SOC_DAPM_POST_PMD:
+		return msm8930_enable_codec_ext_clk(w->codec, 0);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8930_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Right Pos", msm8930_spkramp_event),
+
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+
+};
+
+static const struct snd_soc_dapm_route common_audio_map[] = {
+
+	{"RX_BIAS", NULL, "MCLK"},
+	{"LDO_H", NULL, "MCLK"},
+
+	{"MIC BIAS1 Internal1", NULL, "MCLK"},
+	{"MIC BIAS2 Internal1", NULL, "MCLK"},
+
+	/* Speaker path */
+	{"Ext Spk Left Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Right Pos", NULL, "LINEOUT2"},
+
+
+	{"AMIC2", NULL, "MIC BIAS2 Internal1"},
+	{"MIC BIAS2 Internal1", NULL, "Headset Mic"},
+
+	/* Microphone path */
+	{"AMIC1", NULL, "MIC BIAS1 Internal1"},
+	{"MIC BIAS1 Internal1", NULL, "Handset Mic"},
+
+	{"HEADPHONE", NULL, "LDO_H"},
+
+	/**
+	 * The digital Mic routes are setup considering
+	 * fluid as default device.
+	 */
+
+	/**
+	 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
+	 * Digital Mic GM5 on CDP mainboard.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
+	 * Digital Mic GM6 on CDP mainboard.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+	/**
+	 * Digital Mic3. Back Bottom Digital Mic on Fluid.
+	 * Digital Mic GM1 on CDP mainboard.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4. Back top Digital Mic on Fluid.
+	 * Digital Mic GM2 on CDP mainboard.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Digital Mic4"},
+
+
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *slim0_rx_ch_text[] = {"One", "Two"};
+static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm8930_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+};
+
+static const char *btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm8930_btsco_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm8930_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_slim_0_rx_ch  = %d\n", __func__,
+		 msm8930_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int msm8930_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
+		 msm8930_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm8930_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_slim_0_tx_ch  = %d\n", __func__,
+		 msm8930_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm8930_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int msm8930_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm8930_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
+		 msm8930_slim_0_tx_ch);
+	return 1;
+}
+
+static int msm8930_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_btsco_rate  = %d", __func__, msm8930_btsco_rate);
+	ucontrol->value.integer.value[0] = msm8930_btsco_rate;
+	return 0;
+}
+
+static int msm8930_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 1:
+		msm8930_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm8930_btsco_rate = %d\n", __func__, msm8930_btsco_rate);
+	return 0;
+}
+
+static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
+		msm8930_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm8930_enum[1],
+		msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
+		msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
+};
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
+		msm8930_btsco_rate_get, msm8930_btsco_rate_put),
+};
+
+static int msm8930_btsco_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err = 0;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	err = snd_soc_add_platform_controls(platform,
+			int_btsco_rate_mixer_controls,
+		ARRAY_SIZE(int_btsco_rate_mixer_controls));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int msm8930_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+	pr_debug("%s: ch=%d\n", __func__,
+					msm8930_slim_0_rx_ch);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				msm8930_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+				msm8930_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+							       __func__);
+			goto end;
+		}
+	} else {
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				msm8930_slim_0_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai,
+				msm8930_slim_0_tx_ch, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+							       __func__);
+			goto end;
+		}
+
+	}
+end:
+	return ret;
+}
+
+static int msm8930_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	pr_debug("%s()\n", __func__);
+
+
+	rtd->pmdown_time = 0;
+
+	err = snd_soc_add_controls(codec, sitar_msm8930_controls,
+				ARRAY_SIZE(sitar_msm8930_controls));
+	if (err < 0)
+		return err;
+
+	snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
+				ARRAY_SIZE(msm8930_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, common_audio_map,
+		ARRAY_SIZE(common_audio_map));
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+		(SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
+		&hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+
+	err = snd_soc_jack_new(codec, "Button Jack",
+				SND_JACK_BTN_0, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+	sitar_hs_detect(codec, &hs_jack, &button_jack, &sitar_calib);
+	return 0;
+}
+
+static struct snd_soc_dsp_link lpa_fe_media = {
+	.playback = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link fe_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link slimbus0_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link int_fm_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+/* bi-directional media definition for hostless PCM device */
+static struct snd_soc_dsp_link bidir_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link hdmi_rx_hl = {
+	.playback = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static int msm8930_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm8930_slim_0_rx_ch;
+
+	return 0;
+}
+
+static int msm8930_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm8930_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int msm8930_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm8930_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
+static int msm8930_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = msm8930_btsco_rate;
+	channels->min = channels->max = msm8930_btsco_ch;
+
+	return 0;
+}
+static int msm8930_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+static int msm8930_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int msm8930_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+static int msm8930_startup(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	return 0;
+}
+
+static int msm8930_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = msm8930_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	msm8930_aux_pcm_free_gpios();
+}
+
+static void msm8930_shutdown(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+}
+
+static struct snd_soc_ops msm8930_be_ops = {
+	.startup = msm8930_startup,
+	.hw_params = msm8930_hw_params,
+	.shutdown = msm8930_shutdown,
+};
+
+static struct snd_soc_ops msm8930_auxpcm_be_ops = {
+	.startup = msm8930_auxpcm_startup,
+	.shutdown = msm8930_auxpcm_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm8930_dai[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8930 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8930 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name	= "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{
+		.name = "MSM8930 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+	/* Hostless PMC purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &slimbus0_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &int_fm_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM8930 Compr",
+		.stream_name = "COMPR",
+		.cpu_dai_name	= "MultiMedia4",
+		.platform_name  = "msm-compr-dsp",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+	},
+	 {
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name   = "AUXPCM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &bidir_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	/* HDMI Hostless */
+	{
+		.name = "HDMI_RX_HOSTLESS",
+		.stream_name = "HDMI_RX_HOSTLESS",
+		.cpu_dai_name = "HDMI_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &hdmi_rx_hl,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.no_codec = 1,
+		.ignore_suspend = 1,
+	},
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "sitar_codec",
+		.codec_dai_name	= "sitar_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm8930_audrx_init,
+		.be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8930_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "sitar_codec",
+		.codec_dai_name	= "sitar_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8930_be_ops,
+	},
+	/* Backend BT/FM DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6.12288",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-rx",
+		.init = &msm8930_btsco_init,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+		.be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6.12292",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6.12293",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_TX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	/* HDMI BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI,
+		.stream_name = "HDMI Playback",
+		.cpu_dai_name = "msm-dai-q6-hdmi.8",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_HDMI_RX,
+		.be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
+	},
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6.224",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+		.ops = &msm8930_auxpcm_be_ops,
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6.32773",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+};
+
+struct snd_soc_card snd_soc_card_msm8930 = {
+	.name		= "msm8930-sitar-snd-card",
+	.dai_link	= msm8930_dai,
+	.num_links	= ARRAY_SIZE(msm8930_dai),
+};
+
+static struct platform_device *msm8930_snd_device;
+
+static int msm8930_configure_headset_mic_gpios(void)
+{
+	int ret;
+	ret = gpio_request(80, "US_EURO_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio 80\n", __func__);
+		return ret;
+	}
+	ret = gpio_direction_output(80, 0);
+	if (ret) {
+		pr_err("%s: Unable to set direction\n", __func__);
+		gpio_free(80);
+	}
+	msm8930_headset_gpios_configured = 0;
+	return 0;
+}
+static void msm8930_free_headset_mic_gpios(void)
+{
+	if (msm8930_headset_gpios_configured)
+		gpio_free(80);
+}
+
+static int __init msm8930_audio_init(void)
+{
+	int ret;
+
+	if (!cpu_is_msm8930()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return -ENODEV ;
+	}
+
+	msm8930_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm8930_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
+	ret = platform_device_add(msm8930_snd_device);
+	if (ret) {
+		platform_device_put(msm8930_snd_device);
+		return ret;
+	}
+
+	if (msm8930_configure_headset_mic_gpios()) {
+		pr_err("%s Fail to configure headset mic gpios\n", __func__);
+		msm8930_headset_gpios_configured = 0;
+	} else
+		msm8930_headset_gpios_configured = 1;
+
+	return ret;
+
+}
+module_init(msm8930_audio_init);
+
+static void __exit msm8930_audio_exit(void)
+{
+	if (!cpu_is_msm8930()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
+	msm8930_free_headset_mic_gpios();
+	platform_device_unregister(msm8930_snd_device);
+}
+module_exit(msm8930_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MSM8930");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index eb363e7..0d45e82 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -15,7 +15,6 @@
 #include <linux/gpio.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/platform_device.h>
-#include <linux/gpio.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -26,12 +25,14 @@
 #include <sound/jack.h>
 #include <asm/mach-types.h>
 #include <mach/socinfo.h>
+#include <linux/mfd/wcd9xxx/core.h>
 #include "msm-pcm-routing.h"
 #include "../codecs/wcd9310.h"
 
 /* 8960 machine driver */
 
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
 #define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
 
 #define MSM8960_SPK_ON 1
@@ -58,6 +59,10 @@
 #define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
+#define JACK_DETECT_GPIO 38
+#define JACK_DETECT_INT PM8921_GPIO_IRQ(PM8921_IRQ_BASE, JACK_DETECT_GPIO)
+#define GPIO_DETECT_USED false
+
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
 static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
 static int msm8960_spk_control;
@@ -77,7 +82,23 @@
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
-static void *tabla_mbhc_cal;
+static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm);
+
+static struct tabla_mbhc_config mbhc_cfg = {
+	.headset_jack = &hs_jack,
+	.button_jack = &button_jack,
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = TABLA_MICBIAS2,
+	.mclk_cb_fn = msm8960_enable_codec_ext_clk,
+	.mclk_rate = TABLA_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+};
+
+static struct mutex cdc_mclk_mutex;
 
 static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
 {
@@ -299,38 +320,46 @@
 	}
 	return 0;
 }
-int msm8960_enable_codec_ext_clk(
-		struct snd_soc_codec *codec, int enable)
+
+static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm)
 {
+	int r = 0;
 	pr_debug("%s: enable = %d\n", __func__, enable);
+
+	mutex_lock(&cdc_mclk_mutex);
 	if (enable) {
 		clk_users++;
 		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
-		if (clk_users != 1)
-			return 0;
-
-		if (codec_clk) {
-			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
-			clk_enable(codec_clk);
-			tabla_mclk_enable(codec, 1);
-		} else {
-			pr_err("%s: Error setting Tabla MCLK\n", __func__);
-			clk_users--;
-			return -EINVAL;
+		if (clk_users == 1) {
+			if (codec_clk) {
+				clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+				clk_enable(codec_clk);
+				tabla_mclk_enable(codec, 1, dapm);
+			} else {
+				pr_err("%s: Error setting Tabla MCLK\n",
+				       __func__);
+				clk_users--;
+				r = -EINVAL;
+			}
 		}
 	} else {
-		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
-		if (clk_users == 0)
-			return 0;
-		clk_users--;
-		if (!clk_users) {
-			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+		if (clk_users > 0) {
+			clk_users--;
+			pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+			if (clk_users == 0) {
+				pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					 __func__, clk_users);
-			clk_disable(codec_clk);
-			tabla_mclk_enable(codec, 0);
+				clk_disable(codec_clk);
+				tabla_mclk_enable(codec, 0, dapm);
+			}
+		} else {
+			pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+			r = -EINVAL;
 		}
 	}
-	return 0;
+	mutex_unlock(&cdc_mclk_mutex);
+	return r;
 }
 
 static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
@@ -340,9 +369,9 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		return msm8960_enable_codec_ext_clk(w->codec, 1);
+		return msm8960_enable_codec_ext_clk(w->codec, 1, true);
 	case SND_SOC_DAPM_POST_PMD:
-		return msm8960_enable_codec_ext_clk(w->codec, 0);
+		return msm8960_enable_codec_ext_clk(w->codec, 0, true);
 	}
 	return 0;
 }
@@ -707,6 +736,13 @@
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct pm_gpio jack_gpio_cfg = {
+		.direction = PM_GPIO_DIR_IN,
+		.pull = PM_GPIO_PULL_UP_1P5,
+		.function = PM_GPIO_FUNC_NORMAL,
+		.vin_sel = 2,
+		.inv_int_pol = 0,
+	};
 
 	pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 
@@ -753,11 +789,22 @@
 
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
-	tabla_hs_detect(codec, &hs_jack, &button_jack, tabla_mbhc_cal,
-			TABLA_MICBIAS2, msm8960_enable_codec_ext_clk, 0,
-			TABLA_EXT_CLK_RATE);
+	if (GPIO_DETECT_USED) {
+		mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
+		mbhc_cfg.gpio_irq = JACK_DETECT_INT;
+	}
 
-	return 0;
+	if (mbhc_cfg.gpio) {
+		err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
+		if (err) {
+			pr_err("%s: pm8xxx_gpio_config failed %d\n", __func__,
+			       err);
+			return err;
+		}
+	}
+	err = tabla_hs_detect(codec, &mbhc_cfg);
+
+	return err;
 }
 
 static struct snd_soc_dsp_link lpa_fe_media = {
@@ -1391,13 +1438,13 @@
 {
 	int ret;
 
-	if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
+	if (!cpu_is_msm8960()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return -ENODEV ;
 	}
 
-	tabla_mbhc_cal = def_tabla_mbhc_cal();
-	if (!tabla_mbhc_cal) {
+	mbhc_cfg.calibration = def_tabla_mbhc_cal();
+	if (!mbhc_cfg.calibration) {
 		pr_err("Calibration data allocation failed\n");
 		return -ENOMEM;
 	}
@@ -1405,7 +1452,7 @@
 	msm8960_snd_device = platform_device_alloc("soc-audio", 0);
 	if (!msm8960_snd_device) {
 		pr_err("Platform device allocation failed\n");
-		kfree(tabla_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return -ENOMEM;
 	}
 
@@ -1417,14 +1464,14 @@
 	ret = platform_device_add(msm8960_snd_device);
 	if (ret) {
 		platform_device_put(msm8960_snd_device);
-		kfree(tabla_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return ret;
 	}
 
 	msm8960_snd_tabla1x_device = platform_device_alloc("soc-audio", 1);
 	if (!msm8960_snd_tabla1x_device) {
 		pr_err("Platform device allocation failed\n");
-		kfree(tabla_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return -ENOMEM;
 	}
 
@@ -1438,7 +1485,7 @@
 	ret = platform_device_add(msm8960_snd_tabla1x_device);
 	if (ret) {
 		platform_device_put(msm8960_snd_tabla1x_device);
-		kfree(tabla_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return ret;
 	}
 
@@ -1448,6 +1495,7 @@
 	} else
 		msm8960_headset_gpios_configured = 1;
 
+	mutex_init(&cdc_mclk_mutex);
 	return ret;
 
 }
@@ -1455,14 +1503,15 @@
 
 static void __exit msm8960_audio_exit(void)
 {
-	if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
+	if (!cpu_is_msm8960()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return ;
 	}
 	msm8960_free_headset_mic_gpios();
 	platform_device_unregister(msm8960_snd_device);
 	platform_device_unregister(msm8960_snd_tabla1x_device);
-	kfree(tabla_mbhc_cal);
+	kfree(mbhc_cfg.calibration);
+	mutex_destroy(&cdc_mclk_mutex);
 }
 module_exit(msm8960_audio_exit);
 
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 2710fbb..f928c00 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -76,7 +76,11 @@
 		index = afe_get_port_index(data->token);
 		pr_debug("%s: Port ID %d, index %d\n", __func__,
 			data->token, index);
-
+		if (index < 0 || index >= AFE_MAX_PORTS) {
+			pr_err("%s: invalid port idx %d token %d\n",
+					__func__, index, data->token);
+			return 0;
+		}
 		if (data->opcode == APR_BASIC_RSP_RESULT) {
 			pr_debug("APR_BASIC_RSP_RESULT\n");
 			switch (payload[0]) {
@@ -139,6 +143,11 @@
 	s32				result = 0;
 	struct adm_set_params_command	adm_params;
 	int index = afe_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d portid %d\n",
+				__func__, index, port_id);
+		return 0;
+	}
 
 	pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
 
@@ -205,8 +214,10 @@
 	get_audproc_cal(acdb_path, &aud_cal);
 
 	/* map & cache buffers used */
-	if ((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
-		(aud_cal.cal_size > 0)) {
+	if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+		(aud_cal.cal_size > 0)) ||
+		(aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
+
 		if (mem_addr_audproc[acdb_path].cal_paddr != 0)
 			adm_memory_unmap_regions(
 				&mem_addr_audproc[acdb_path].cal_paddr,
@@ -233,8 +244,9 @@
 	get_audvol_cal(acdb_path, &aud_cal);
 
 	/* map & cache buffers used */
-	if ((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
-		(aud_cal.cal_size > 0)) {
+	if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+		(aud_cal.cal_size > 0))  ||
+		(aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
 		if (mem_addr_audvol[acdb_path].cal_paddr != 0)
 			adm_memory_unmap_regions(
 				&mem_addr_audvol[acdb_path].cal_paddr,
@@ -316,9 +328,7 @@
 			if ((open.topology_id ==
 				VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
 			    (open.topology_id ==
-				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
-			    (open.topology_id ==
-				VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY))
+				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 		}
 
@@ -328,8 +338,8 @@
 		open.channel_config = channel_mode & 0x00FF;
 		open.rate  = rate;
 
-		pr_debug("%s: channel_config=%d port_id=%d rate=%d\
-			topology_id=0x%X\n", __func__, open.channel_config,\
+		pr_debug("%s: channel_config=%d port_id=%d rate=%d"
+			"topology_id=0x%X\n", __func__, open.channel_config,\
 			open.endpoint_id1, open.rate,\
 			open.topology_id);
 
@@ -495,6 +505,11 @@
 	int ret = 0, i = 0;
 	/* Assumes port_ids have already been validated during adm_open */
 	int index = afe_get_port_index(copp_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d token %d\n",
+					__func__, index, copp_id);
+		return 0;
+	}
 
 	pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0]:%d\n",
 		 __func__, session_id, path, num_copps, port_id[0]);
@@ -523,7 +538,8 @@
 		pr_debug("%s: port_id[%d]: %d, index: %d\n", __func__, i,
 			 port_id[i], tmp);
 
-		route.session[0].copp_id[i] =
+		if (tmp >= 0 && tmp < AFE_MAX_PORTS)
+			route.session[0].copp_id[i] =
 					atomic_read(&this_adm.copp_id[tmp]);
 	}
 	if (num_copps % 2)
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 59506f1..bac432d 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -37,7 +37,7 @@
 
 static struct afe_ctl this_afe;
 
-static uint32_t afe_cal_addr[MAX_AUDPROC_TYPES];
+static struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
 
 #define TIMEOUT_MS 1000
 #define Q6AFE_MAX_VOLUME 0x3FFF
@@ -145,6 +145,7 @@
 	case MI2S_RX:
 	case HDMI_RX:
 	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
 	case INT_BT_SCO_RX:
 	case INT_BT_A2DP_RX:
 	case INT_FM_RX:
@@ -160,6 +161,7 @@
 	case DIGI_MIC_TX:
 	case VOICE_RECORD_TX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
 	case INT_FM_TX:
 	case VOICE_RECORD_RX:
 	case INT_BT_SCO_TX:
@@ -168,7 +170,7 @@
 		break;
 
 	default:
-		pr_err("%s: invalid port id\n", __func__);
+		pr_err("%s: invalid port id %d\n", __func__, port_id);
 		ret = -EINVAL;
 	}
 
@@ -197,6 +199,8 @@
 	case VOICE_PLAYBACK_TX:
 	case SLIMBUS_0_RX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
 	case INT_BT_SCO_RX:
 	case INT_BT_SCO_TX:
 	case INT_BT_A2DP_RX:
@@ -257,6 +261,8 @@
 	case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
 	case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
 	case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
+	case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
+	case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
 	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
 	case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -286,6 +292,8 @@
 		break;
 	case SLIMBUS_0_RX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
 		break;
 	case RT_PROXY_PORT_001_RX:
@@ -332,12 +340,16 @@
 		goto done;
 	}
 
-	if (afe_cal_addr[path] != cal_block.cal_paddr) {
-		if (afe_cal_addr[path] != 0)
-			afe_cmd_memory_unmap_nowait(afe_cal_addr[path]);
+	if ((afe_cal_addr[path].cal_paddr != cal_block.cal_paddr) ||
+		(cal_block.cal_size > afe_cal_addr[path].cal_size)) {
+		if (afe_cal_addr[path].cal_paddr != 0)
+			afe_cmd_memory_unmap_nowait(
+				afe_cal_addr[path].cal_paddr);
+
 		afe_cmd_memory_map_nowait(cal_block.cal_paddr,
 						cal_block.cal_size);
-		afe_cal_addr[path] = cal_block.cal_paddr;
+		afe_cal_addr[path].cal_paddr = cal_block.cal_paddr;
+		afe_cal_addr[path].cal_size = cal_block.cal_size;
 	}
 
 	afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -1565,8 +1577,9 @@
 		debugfs_remove(debugfs_afelb_gain);
 #endif
 	for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
-		if (afe_cal_addr[i] != 0)
-			afe_cmd_memory_unmap_nowait(afe_cal_addr[i]);
+		if (afe_cal_addr[i].cal_paddr != 0)
+			afe_cmd_memory_unmap_nowait(
+				afe_cal_addr[i].cal_paddr);
 	}
 }
 
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index dc49f12..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;
 	}
@@ -3211,7 +3315,7 @@
 {
 	pr_debug("%s\n", __func__);
 
-	if (session_id < 0) {
+	if (session_id < 0 || session_id > SESSION_MAX) {
 		pr_err("%s: invalid session_id = %d\n", __func__, session_id);
 		return -EINVAL;
 	}
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 532d92b..3b46a50 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -34,6 +34,11 @@
 #define VOC_PATH_PASSIVE 0
 #define VOC_PATH_FULL 1
 
+/* CVP CAL Size: 245760 = 240 * 1024 */
+#define CVP_CAL_SIZE 245760
+/* CVS CAL Size: 49152 = 48 * 1024 */
+#define CVS_CAL_SIZE 49152
+
 static struct common_data common;
 
 static int voice_send_enable_vocproc_cmd(struct voice_data *v);
@@ -662,6 +667,59 @@
 	return -EINVAL;
 }
 
+static int voice_set_dtx(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+	struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	/* Set DTX */
+	cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+	cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+	cvs_set_dtx.hdr.src_port = v->session_id;
+	cvs_set_dtx.hdr.dest_port = cvs_handle;
+	cvs_set_dtx.hdr.token = 0;
+	cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+	cvs_set_dtx.dtx_mode.enable = common.mvs_info.dtx_mode;
+
+	pr_debug("%s: Setting DTX %d\n", __func__, common.mvs_info.dtx_mode);
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_DTX\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_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_config_cvs_vocoder(struct voice_data *v)
 {
 	int ret = 0;
@@ -753,7 +811,6 @@
 	}
 	case VSS_MEDIA_ID_AMR_NB_MODEM: {
 		struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
-		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
 
 		pr_debug("Setting AMR rate\n");
 
@@ -785,40 +842,15 @@
 			pr_err("%s: wait_event timeout\n", __func__);
 			goto fail;
 		}
-		/* Disable DTX */
-		pr_debug("Disabling DTX\n");
 
-		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						      APR_HDR_LEN(APR_HDR_SIZE),
-						      APR_PKT_VER);
-		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-					sizeof(cvs_set_dtx) - APR_HDR_SIZE);
-		cvs_set_dtx.hdr.src_port = v->session_id;
-		cvs_set_dtx.hdr.dest_port = cvs_handle;
-		cvs_set_dtx.hdr.token = 0;
-		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
-		cvs_set_dtx.dtx_mode.enable = 0;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_DTX\n",
-			       __func__, ret);
+		ret = voice_set_dtx(v);
+		if (ret < 0)
 			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
+
 		break;
 	}
 	case VSS_MEDIA_ID_AMR_WB_MODEM: {
 		struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
-		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
 
 		pr_debug("Setting AMR WB rate\n");
 
@@ -851,70 +883,18 @@
 			pr_err("%s: wait_event timeout\n", __func__);
 			goto fail;
 		}
-		/* Disable DTX */
-		pr_debug("Disabling DTX\n");
 
-		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						      APR_HDR_LEN(APR_HDR_SIZE),
-						      APR_PKT_VER);
-		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				       sizeof(cvs_set_dtx) - APR_HDR_SIZE);
-		cvs_set_dtx.hdr.src_port = v->session_id;
-		cvs_set_dtx.hdr.dest_port = cvs_handle;
-		cvs_set_dtx.hdr.token = 0;
-		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
-		cvs_set_dtx.dtx_mode.enable = 0;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_DTX\n",
-			       __func__, ret);
+		ret = voice_set_dtx(v);
+		if (ret < 0)
 			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
+
 		break;
 	}
 	case VSS_MEDIA_ID_G729:
 	case VSS_MEDIA_ID_G711_ALAW:
 	case VSS_MEDIA_ID_G711_MULAW: {
-		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
-		/* Disable DTX */
-		pr_debug("Disabling DTX\n");
+		ret = voice_set_dtx(v);
 
-		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						      APR_HDR_LEN(APR_HDR_SIZE),
-						      APR_PKT_VER);
-		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-					    sizeof(cvs_set_dtx) - APR_HDR_SIZE);
-		cvs_set_dtx.hdr.src_port = v->session_id;
-		cvs_set_dtx.hdr.dest_port = cvs_handle;
-		cvs_set_dtx.hdr.token = 0;
-		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
-		cvs_set_dtx.dtx_mode.enable = 0;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_DTX\n",
-			       __func__, ret);
-			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
 		break;
 	}
 	default:
@@ -1155,6 +1135,7 @@
 	int ret = 0;
 	void *apr_cvs;
 	u16 cvs_handle;
+	uint32_t cal_paddr;
 
 	/* get the cvs cal data */
 	get_all_vocstrm_cal(&cal_block);
@@ -1171,6 +1152,21 @@
 		pr_err("%s: apr_cvs is NULL.\n", __func__);
 		return -EINVAL;
 	}
+
+	if (is_voip_session(v->session_id)) {
+		if (common.cvs_cal.buf) {
+			cal_paddr = common.cvs_cal.phy;
+
+			memcpy(common.cvs_cal.buf,
+				(void *) cal_block.cal_kvaddr,
+				cal_block.cal_size);
+		} else {
+			return -EINVAL;
+		}
+	} else {
+		cal_paddr = cal_block.cal_paddr;
+	}
+
 	cvs_handle = voice_get_cvs_handle(v);
 
 	/* fill in the header */
@@ -1183,7 +1179,7 @@
 	cvs_reg_cal_cmd.hdr.token = 0;
 	cvs_reg_cal_cmd.hdr.opcode = VSS_ISTREAM_CMD_REGISTER_CALIBRATION_DATA;
 
-	cvs_reg_cal_cmd.cvs_cal_data.phys_addr = cal_block.cal_paddr;
+	cvs_reg_cal_cmd.cvs_cal_data.phys_addr = cal_paddr;
 	cvs_reg_cal_cmd.cvs_cal_data.mem_size = cal_block.cal_size;
 
 	v->cvs_state = CMD_STATUS_FAIL;
@@ -1266,6 +1262,7 @@
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
+	uint32_t cal_paddr;
 
 	/* get all cvp cal data */
 	get_all_cvp_cal(&cal_block);
@@ -1282,6 +1279,15 @@
 		pr_err("%s: apr_cvp is NULL.\n", __func__);
 		return -EINVAL;
 	}
+
+	if (is_voip_session(v->session_id)) {
+		if (common.cvp_cal.buf)
+			cal_paddr = common.cvp_cal.phy;
+		else
+			return -EINVAL;
+	} else {
+		cal_paddr = cal_block.cal_paddr;
+	}
 	cvp_handle = voice_get_cvp_handle(v);
 
 	/* fill in the header */
@@ -1294,9 +1300,9 @@
 	cvp_map_mem_cmd.hdr.token = 0;
 	cvp_map_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_MAP_MEMORY;
 
-	pr_debug("%s, phy_addr:%d, mem_size:%d\n", __func__,
-		cal_block.cal_paddr, cal_block.cal_size);
-	cvp_map_mem_cmd.vss_map_mem.phys_addr = cal_block.cal_paddr;
+	pr_debug("%s, phy_addr:0x%x, mem_size:%d\n", __func__,
+		cal_paddr, cal_block.cal_size);
+	cvp_map_mem_cmd.vss_map_mem.phys_addr = cal_paddr;
 	cvp_map_mem_cmd.vss_map_mem.mem_size = cal_block.cal_size;
 	cvp_map_mem_cmd.vss_map_mem.mem_pool_id =
 				VSS_ICOMMON_MAP_MEMORY_SHMEM8_4K_POOL;
@@ -1327,6 +1333,7 @@
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
+	uint32_t cal_paddr;
 
 	get_all_cvp_cal(&cal_block);
 	if (cal_block.cal_size == 0)
@@ -1342,6 +1349,12 @@
 		pr_err("%s: apr_cvp is NULL.\n", __func__);
 		return -EINVAL;
 	}
+
+	if (is_voip_session(v->session_id))
+		cal_paddr = common.cvp_cal.phy;
+	else
+		cal_paddr = cal_block.cal_paddr;
+
 	cvp_handle = voice_get_cvp_handle(v);
 
 	/* fill in the header */
@@ -1354,7 +1367,7 @@
 	cvp_unmap_mem_cmd.hdr.token = 0;
 	cvp_unmap_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_UNMAP_MEMORY;
 
-	cvp_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_block.cal_paddr;
+	cvp_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_paddr;
 
 	v->cvp_state = CMD_STATUS_FAIL;
 	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_unmap_mem_cmd);
@@ -1382,6 +1395,7 @@
 	int ret = 0;
 	void *apr_cvs;
 	u16 cvs_handle;
+	uint32_t cal_paddr;
 
 	/* get all cvs cal data */
 	get_all_vocstrm_cal(&cal_block);
@@ -1398,6 +1412,16 @@
 		pr_err("%s: apr_cvs is NULL.\n", __func__);
 		return -EINVAL;
 	}
+
+	if (is_voip_session(v->session_id)) {
+		if (common.cvs_cal.buf)
+			cal_paddr = common.cvs_cal.phy;
+		else
+			return -EINVAL;
+	} else {
+		cal_paddr = cal_block.cal_paddr;
+	}
+
 	cvs_handle = voice_get_cvs_handle(v);
 
 	/* fill in the header */
@@ -1410,9 +1434,9 @@
 	cvs_map_mem_cmd.hdr.token = 0;
 	cvs_map_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_MAP_MEMORY;
 
-	pr_debug("%s, phys_addr: %d, mem_size: %d\n", __func__,
-		cal_block.cal_paddr, cal_block.cal_size);
-	cvs_map_mem_cmd.vss_map_mem.phys_addr = cal_block.cal_paddr;
+	pr_debug("%s, phys_addr: 0x%x, mem_size: %d\n", __func__,
+		cal_paddr, cal_block.cal_size);
+	cvs_map_mem_cmd.vss_map_mem.phys_addr = cal_paddr;
 	cvs_map_mem_cmd.vss_map_mem.mem_size = cal_block.cal_size;
 	cvs_map_mem_cmd.vss_map_mem.mem_pool_id =
 				VSS_ICOMMON_MAP_MEMORY_SHMEM8_4K_POOL;
@@ -1443,6 +1467,7 @@
 	int ret = 0;
 	void *apr_cvs;
 	u16 cvs_handle;
+	uint32_t cal_paddr;
 
 	get_all_vocstrm_cal(&cal_block);
 	if (cal_block.cal_size == 0)
@@ -1458,6 +1483,12 @@
 		pr_err("%s: apr_cvs is NULL.\n", __func__);
 		return -EINVAL;
 	}
+
+	if (is_voip_session(v->session_id))
+		cal_paddr = common.cvs_cal.phy;
+	else
+		cal_paddr = cal_block.cal_paddr;
+
 	cvs_handle = voice_get_cvs_handle(v);
 
 	/* fill in the header */
@@ -1470,7 +1501,7 @@
 	cvs_unmap_mem_cmd.hdr.token = 0;
 	cvs_unmap_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_UNMAP_MEMORY;
 
-	cvs_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_block.cal_paddr;
+	cvs_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_paddr;
 
 	v->cvs_state = CMD_STATUS_FAIL;
 	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_unmap_mem_cmd);
@@ -1498,6 +1529,7 @@
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
+	uint32_t cal_paddr;
 
       /* get the cvp cal data */
 	get_all_vocproc_cal(&cal_block);
@@ -1514,6 +1546,21 @@
 		pr_err("%s: apr_cvp is NULL.\n", __func__);
 		return -EINVAL;
 	}
+
+	if (is_voip_session(v->session_id)) {
+		if (common.cvp_cal.buf) {
+			cal_paddr = common.cvp_cal.phy;
+
+			memcpy(common.cvp_cal.buf,
+				(void *)cal_block.cal_kvaddr,
+				cal_block.cal_size);
+		} else {
+			return -EINVAL;
+		}
+	} else {
+		cal_paddr = cal_block.cal_paddr;
+	}
+
 	cvp_handle = voice_get_cvp_handle(v);
 
 	/* fill in the header */
@@ -1526,7 +1573,7 @@
 	cvp_reg_cal_cmd.hdr.token = 0;
 	cvp_reg_cal_cmd.hdr.opcode = VSS_IVOCPROC_CMD_REGISTER_CALIBRATION_DATA;
 
-	cvp_reg_cal_cmd.cvp_cal_data.phys_addr = cal_block.cal_paddr;
+	cvp_reg_cal_cmd.cvp_cal_data.phys_addr = cal_paddr;
 	cvp_reg_cal_cmd.cvp_cal_data.mem_size = cal_block.cal_size;
 
 	v->cvp_state = CMD_STATUS_FAIL;
@@ -1605,14 +1652,18 @@
 static int voice_send_cvp_register_vol_cal_table_cmd(struct voice_data *v)
 {
 	struct cvp_register_vol_cal_table_cmd cvp_reg_cal_tbl_cmd;
-	struct acdb_cal_block cal_block;
+	struct acdb_cal_block vol_block;
+	struct acdb_cal_block voc_block;
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
+	uint32_t cal_paddr;
 
 	/* get the cvp vol cal data */
-	get_all_vocvol_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	get_all_vocvol_cal(&vol_block);
+	get_all_vocproc_cal(&voc_block);
+
+	if (vol_block.cal_size == 0)
 		goto fail;
 
 	if (v == NULL) {
@@ -1625,6 +1676,21 @@
 		pr_err("%s: apr_cvp is NULL.\n", __func__);
 		return -EINVAL;
 	}
+
+	if (is_voip_session(v->session_id)) {
+		if (common.cvp_cal.buf) {
+			cal_paddr = common.cvp_cal.phy + voc_block.cal_size;
+
+			memcpy(common.cvp_cal.buf + voc_block.cal_size,
+				(void *) vol_block.cal_kvaddr,
+				vol_block.cal_size);
+		} else {
+			return -EINVAL;
+		}
+	} else {
+		cal_paddr = vol_block.cal_paddr;
+	}
+
 	cvp_handle = voice_get_cvp_handle(v);
 
 	/* fill in the header */
@@ -1638,8 +1704,8 @@
 	cvp_reg_cal_tbl_cmd.hdr.opcode =
 				VSS_IVOCPROC_CMD_REGISTER_VOLUME_CAL_TABLE;
 
-	cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.phys_addr = cal_block.cal_paddr;
-	cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.mem_size = cal_block.cal_size;
+	cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.phys_addr = cal_paddr;
+	cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.mem_size = vol_block.cal_size;
 
 	v->cvp_state = CMD_STATUS_FAIL;
 	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_reg_cal_tbl_cmd);
@@ -2307,6 +2373,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;
@@ -2908,6 +3019,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);
@@ -3236,11 +3390,13 @@
 
 void voc_config_vocoder(uint32_t media_type,
 			  uint32_t rate,
-			  uint32_t network_type)
+			  uint32_t network_type,
+			  uint32_t dtx_mode)
 {
 	common.mvs_info.media_type = media_type;
 	common.mvs_info.rate = rate;
 	common.mvs_info.network_type = network_type;
+	common.mvs_info.dtx_mode = dtx_mode;
 }
 
 static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
@@ -3576,9 +3732,73 @@
 static int __init voice_init(void)
 {
 	int rc = 0, i = 0;
+	int len;
 
 	memset(&common, 0, sizeof(struct common_data));
 
+	/* Allocate memory for VoIP calibration */
+	common.client = msm_ion_client_create(UINT_MAX, "voip_client");
+	if (IS_ERR_OR_NULL((void *)common.client)) {
+		pr_err("%s: ION create client for Voip failed\n", __func__);
+		goto cont;
+	}
+	common.cvp_cal.handle = ion_alloc(common.client, CVP_CAL_SIZE, SZ_4K,
+					  ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL((void *) common.cvp_cal.handle)) {
+		pr_err("%s: ION memory allocation for CVP failed\n",
+			__func__);
+		ion_client_destroy(common.client);
+		goto cont;
+	}
+
+	rc = ion_phys(common.client, common.cvp_cal.handle,
+		  (ion_phys_addr_t *)&common.cvp_cal.phy, (size_t *)&len);
+	if (rc) {
+		pr_err("%s: ION Get Physical for cvp failed, rc = %d\n",
+			__func__, rc);
+		ion_free(common.client, common.cvp_cal.handle);
+		ion_client_destroy(common.client);
+		goto cont;
+	}
+
+	common.cvp_cal.buf = ion_map_kernel(common.client,
+					common.cvp_cal.handle, 0);
+	if (IS_ERR_OR_NULL((void *) common.cvp_cal.buf)) {
+		pr_err("%s: ION memory mapping for cvp failed\n", __func__);
+		common.cvp_cal.buf = NULL;
+		ion_free(common.client, common.cvp_cal.handle);
+		ion_client_destroy(common.client);
+		goto cont;
+	}
+	memset((void *)common.cvp_cal.buf, 0, CVP_CAL_SIZE);
+
+	common.cvs_cal.handle = ion_alloc(common.client, CVS_CAL_SIZE, SZ_4K,
+					 ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL((void *) common.cvs_cal.handle)) {
+		pr_err("%s: ION memory allocation for CVS failed\n",
+			__func__);
+		goto cont;
+	}
+
+	rc = ion_phys(common.client, common.cvs_cal.handle,
+		  (ion_phys_addr_t *)&common.cvs_cal.phy, (size_t *)&len);
+	if (rc) {
+		pr_err("%s: ION Get Physical for cvs failed, rc = %d\n",
+			__func__, rc);
+		ion_free(common.client, common.cvs_cal.handle);
+		goto cont;
+	}
+
+	common.cvs_cal.buf = ion_map_kernel(common.client,
+					common.cvs_cal.handle, 0);
+	if (IS_ERR_OR_NULL((void *) common.cvs_cal.buf)) {
+		pr_err("%s: ION memory mapping for cvs failed\n", __func__);
+		common.cvs_cal.buf = NULL;
+		ion_free(common.client, common.cvs_cal.handle);
+		goto cont;
+	}
+	memset((void *)common.cvs_cal.buf, 0, CVS_CAL_SIZE);
+cont:
 	/* set default value */
 	common.default_mute_val = 1;  /* default is mute */
 	common.default_vol_val = 0;
@@ -3594,6 +3814,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 2dc08d6..0fc7a01 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -13,6 +13,7 @@
 #define __QDSP6VOICE_H__
 
 #include <mach/qdsp6v2/apr.h>
+#include <linux/ion.h>
 
 #define MAX_VOC_PKT_SIZE 642
 #define SESSION_NAME_LEN 20
@@ -637,6 +638,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 +732,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 +789,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,
@@ -785,6 +809,7 @@
 	uint32_t media_type;
 	uint32_t rate;
 	uint32_t network_type;
+	uint32_t dtx_mode;
 	ul_cb_fn ul_cb;
 	dl_cb_fn dl_cb;
 	void *private_data;
@@ -847,6 +872,12 @@
 	struct voice_rec_route_state rec_route_state;
 };
 
+struct cal_mem {
+	struct ion_handle *handle;
+	uint32_t phy;
+	void *buf;
+};
+
 #define MAX_VOC_SESSIONS 2
 #define SESSION_ID_BASE 0xFFF0
 
@@ -863,6 +894,10 @@
 	/* APR to CVP in the Q6 */
 	void *apr_q6_cvp;
 
+	struct ion_client *client;
+	struct cal_mem cvp_cal;
+	struct cal_mem cvs_cal;
+
 	struct mutex common_lock;
 
 	struct mvs_driver_info mvs_info;
@@ -876,7 +911,8 @@
 
 void voc_config_vocoder(uint32_t media_type,
 			uint32_t rate,
-			uint32_t network_type);
+			uint32_t network_type,
+			uint32_t dtx_mode);
 
 enum {
 	DEV_RX = 0,
@@ -902,6 +938,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..04d4ca4 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -30,6 +30,7 @@
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
 #include <linux/platform_device.h>
+#include <linux/ctype.h>
 #include <linux/slab.h>
 #include <sound/ac97_codec.h>
 #include <sound/core.h>
@@ -1144,6 +1145,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 +1403,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
@@ -2131,9 +2142,20 @@
 		 "%s", card->name);
 	snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
 		 "%s", card->long_name ? card->long_name : card->name);
-	if (card->driver_name)
-		strlcpy(card->snd_card->driver, card->driver_name,
-			sizeof(card->snd_card->driver));
+	snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
+		 "%s", card->driver_name ? card->driver_name : card->name);
+	for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) {
+		switch (card->snd_card->driver[i]) {
+		case '_':
+		case '-':
+		case '\0':
+			break;
+		default:
+			if (!isalnum(card->snd_card->driver[i]))
+				card->snd_card->driver[i] = '_';
+			break;
+		}
+	}
 
 	if (card->late_probe) {
 		ret = card->late_probe(card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c03f7ca7..265df9e 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -60,6 +60,7 @@
 	[snd_soc_dapm_pre] = 0,
 	[snd_soc_dapm_supply] = 1,
 	[snd_soc_dapm_micbias] = 2,
+	[snd_soc_dapm_adc] = 3,
 	[snd_soc_dapm_mic] = 4,
 	[snd_soc_dapm_mux] = 5,
 	[snd_soc_dapm_virt_mux] = 5,
@@ -70,7 +71,6 @@
 	[snd_soc_dapm_pga] = 8,
 	[snd_soc_dapm_aif_in] = 8,
 	[snd_soc_dapm_aif_out] = 8,
-	[snd_soc_dapm_adc] = 9,
 	[snd_soc_dapm_out_drv] = 10,
 	[snd_soc_dapm_hp] = 10,
 	[snd_soc_dapm_spk] = 10,
@@ -1318,7 +1318,7 @@
 		/* Do we need to apply any queued changes? */
 		if (sort[w->id] != cur_sort || w->reg != cur_reg ||
 		    w->dapm != cur_dapm || w->subseq != cur_subseq) {
-			if (!list_empty(&pending))
+			if (cur_dapm && !list_empty(&pending))
 				dapm_seq_run_coalesced(cur_dapm, &pending);
 
 			if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1378,7 +1378,7 @@
 				"Failed to apply widget power: %d\n", ret);
 	}
 
-	if (!list_empty(&pending))
+	if (cur_dapm && !list_empty(&pending))
 		dapm_seq_run_coalesced(cur_dapm, &pending);
 
 	if (cur_dapm && cur_dapm->seq_notifier) {
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index fa31d9c..c1590ca 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -113,6 +113,23 @@
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
 
 /**
+ * snd_soc_jack_report_no_dapm - Report the current status for a jack
+ *				 without DAPM sync
+ * @jack:   the jack
+ * @status: a bitmask of enum snd_jack_type values that are currently detected.
+ * @mask:   a bitmask of enum snd_jack_type values that being reported.
+ */
+void snd_soc_jack_report_no_dapm(struct snd_soc_jack *jack, int status,
+				 int mask)
+{
+	jack->status &= ~mask;
+	jack->status |= status & mask;
+
+	snd_jack_report(jack->jack, jack->status);
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_report_no_dapm);
+
+/**
  * snd_soc_jack_add_zones - Associate voltage zones with jack
  *
  * @jack:  ASoC jack
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index ec921ec..cd987de 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -57,7 +57,36 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
 
-static struct snd_soc_platform_driver dummy_platform;
+static const struct snd_pcm_hardware dummy_dma_hardware = {
+	.formats		= 0xffffffff,
+	.channels_min		= 1,
+	.channels_max		= UINT_MAX,
+
+	/* Random values to keep userspace happy when checking constraints */
+	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.buffer_bytes_max	= 128*1024,
+	.period_bytes_min	= PAGE_SIZE,
+	.period_bytes_max	= PAGE_SIZE*2,
+	.periods_min		= 2,
+	.periods_max		= 128,
+};
+
+static int dummy_dma_open(struct snd_pcm_substream *substream)
+{
+	snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
+
+	return 0;
+}
+
+static struct snd_pcm_ops dummy_dma_ops = {
+	.open		= dummy_dma_open,
+	.ioctl		= snd_pcm_lib_ioctl,
+};
+
+static struct snd_soc_platform_driver dummy_platform = {
+	.ops = &dummy_dma_ops,
+};
 
 static __devinit int snd_soc_dummy_probe(struct platform_device *pdev)
 {
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index fb5d68f..96c381e 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -459,7 +459,8 @@
 	unsigned int i;
 
 	for (i = 0; i < stream->queue_length; ++i)
-		usb_kill_urb(&stream->urbs[i]->urb);
+		if (stream->urbs[i])
+			usb_kill_urb(&stream->urbs[i]->urb);
 }
 
 static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index)
@@ -484,6 +485,9 @@
 {
 	struct usb_host_interface *alts;
 
+	if (!ua->intf[intf_index])
+		return;
+
 	alts = ua->intf[intf_index]->cur_altsetting;
 	if (alts->desc.bAlternateSetting != 0) {
 		int err = usb_set_interface(ua->dev,
@@ -1144,27 +1148,37 @@
 {
 	unsigned int i;
 
-	for (i = 0; i < stream->queue_length; ++i)
+	for (i = 0; i < stream->queue_length; ++i) {
 		kfree(stream->urbs[i]);
+		stream->urbs[i] = NULL;
+	}
 }
 
 static void free_usb_related_resources(struct ua101 *ua,
 				       struct usb_interface *interface)
 {
 	unsigned int i;
+	struct usb_interface *intf;
 
+	mutex_lock(&ua->mutex);
 	free_stream_urbs(&ua->capture);
 	free_stream_urbs(&ua->playback);
+	mutex_unlock(&ua->mutex);
 	free_stream_buffers(ua, &ua->capture);
 	free_stream_buffers(ua, &ua->playback);
 
-	for (i = 0; i < ARRAY_SIZE(ua->intf); ++i)
-		if (ua->intf[i]) {
-			usb_set_intfdata(ua->intf[i], NULL);
-			if (ua->intf[i] != interface)
+	for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) {
+		mutex_lock(&ua->mutex);
+		intf = ua->intf[i];
+		ua->intf[i] = NULL;
+		mutex_unlock(&ua->mutex);
+		if (intf) {
+			usb_set_intfdata(intf, NULL);
+			if (intf != interface)
 				usb_driver_release_interface(&ua101_driver,
-							     ua->intf[i]);
+							     intf);
 		}
+	}
 }
 
 static void ua101_card_free(struct snd_card *card)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index cdd19d7..0de7cbd 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -765,10 +765,60 @@
  * interface to ALSA control for feature/mixer units
  */
 
+/* volume control quirks */
+static void volume_control_quirks(struct usb_mixer_elem_info *cval,
+				  struct snd_kcontrol *kctl)
+{
+	switch (cval->mixer->chip->usb_id) {
+	case USB_ID(0x0471, 0x0101):
+	case USB_ID(0x0471, 0x0104):
+	case USB_ID(0x0471, 0x0105):
+	case USB_ID(0x0672, 0x1041):
+	/* quirk for UDA1321/N101.
+	 * note that detection between firmware 2.1.1.7 (N101)
+	 * and later 2.1.1.21 is not very clear from datasheets.
+	 * I hope that the min value is -15360 for newer firmware --jk
+	 */
+		if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
+		    cval->min == -15616) {
+			snd_printk(KERN_INFO
+				 "set volume quirk for UDA1321/N101 chip\n");
+			cval->max = -256;
+		}
+		break;
+
+	case USB_ID(0x046d, 0x09a4):
+		if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+			snd_printk(KERN_INFO
+				"set volume quirk for QuickCam E3500\n");
+			cval->min = 6080;
+			cval->max = 8768;
+			cval->res = 192;
+		}
+		break;
+
+	case USB_ID(0x046d, 0x0808):
+	case USB_ID(0x046d, 0x0809):
+	case USB_ID(0x046d, 0x0991):
+	/* Most audio usb devices lie about volume resolution.
+	 * Most Logitech webcams have res = 384.
+	 * Proboly there is some logitech magic behind this number --fishor
+	 */
+		if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+			snd_printk(KERN_INFO
+				"set resolution quirk: cval->res = 384\n");
+			cval->res = 384;
+		}
+		break;
+
+	}
+}
+
 /*
  * retrieve the minimum and maximum values for the specified control
  */
-static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
+static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
+				   int default_min, struct snd_kcontrol *kctl)
 {
 	/* for failsafe */
 	cval->min = default_min;
@@ -844,6 +894,9 @@
 		cval->initialized = 1;
 	}
 
+	if (kctl)
+		volume_control_quirks(cval, kctl);
+
 	/* USB descriptions contain the dB scale in 1/256 dB unit
 	 * while ALSA TLV contains in 1/100 dB unit
 	 */
@@ -864,6 +917,7 @@
 	return 0;
 }
 
+#define get_min_max(cval, def)	get_min_max_with_quirks(cval, def, NULL)
 
 /* get a feature/mixer unit info */
 static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -881,8 +935,17 @@
 		uinfo->value.integer.min = 0;
 		uinfo->value.integer.max = 1;
 	} else {
-		if (! cval->initialized)
-			get_min_max(cval,  0);
+		if (!cval->initialized) {
+			get_min_max_with_quirks(cval, 0, kcontrol);
+			if (cval->initialized && cval->dBmin >= cval->dBmax) {
+				kcontrol->vd[0].access &=
+					~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+					  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
+				snd_ctl_notify(cval->mixer->chip->card,
+					       SNDRV_CTL_EVENT_MASK_INFO,
+					       &kcontrol->id);
+			}
+		}
 		uinfo->value.integer.min = 0;
 		uinfo->value.integer.max =
 			(cval->max - cval->min + cval->res - 1) / cval->res;
@@ -1036,9 +1099,6 @@
 		cval->ch_readonly = readonly_mask;
 	}
 
-	/* get min/max values */
-	get_min_max(cval, 0);
-
 	/* if all channels in the mask are marked read-only, make the control
 	 * read-only. set_cur_mix_value() will check the mask again and won't
 	 * issue write commands to read-only channels. */
@@ -1060,6 +1120,9 @@
 		len = snd_usb_copy_string_desc(state, nameid,
 				kctl->id.name, sizeof(kctl->id.name));
 
+	/* get min/max values */
+	get_min_max_with_quirks(cval, 0, kctl);
+
 	switch (control) {
 	case UAC_FU_MUTE:
 	case UAC_FU_VOLUME:
@@ -1109,51 +1172,6 @@
 		break;
 	}
 
-	/* volume control quirks */
-	switch (state->chip->usb_id) {
-	case USB_ID(0x0471, 0x0101):
-	case USB_ID(0x0471, 0x0104):
-	case USB_ID(0x0471, 0x0105):
-	case USB_ID(0x0672, 0x1041):
-	/* quirk for UDA1321/N101.
-	 * note that detection between firmware 2.1.1.7 (N101)
-	 * and later 2.1.1.21 is not very clear from datasheets.
-	 * I hope that the min value is -15360 for newer firmware --jk
-	 */
-		if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
-		    cval->min == -15616) {
-			snd_printk(KERN_INFO
-				 "set volume quirk for UDA1321/N101 chip\n");
-			cval->max = -256;
-		}
-		break;
-
-	case USB_ID(0x046d, 0x09a4):
-		if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
-			snd_printk(KERN_INFO
-				"set volume quirk for QuickCam E3500\n");
-			cval->min = 6080;
-			cval->max = 8768;
-			cval->res = 192;
-		}
-		break;
-
-	case USB_ID(0x046d, 0x0808):
-	case USB_ID(0x046d, 0x0809):
-	case USB_ID(0x046d, 0x0991):
-	/* Most audio usb devices lie about volume resolution.
-	 * Most Logitech webcams have res = 384.
-	 * Proboly there is some logitech magic behind this number --fishor
-	 */
-		if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
-			snd_printk(KERN_INFO
-				"set resolution quirk: cval->res = 384\n");
-			cval->res = 384;
-		}
-		break;
-
-	}
-
 	range = (cval->max - cval->min) / cval->res;
 	/* Are there devices with volume range more than 255? I use a bit more
 	 * to be sure. 384 is a resolution magic number found on Logitech
diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c
index c400ade..1e7a47a 100644
--- a/sound/usb/usx2y/usb_stream.c
+++ b/sound/usb/usx2y/usb_stream.c
@@ -674,7 +674,7 @@
 		inurb->transfer_buffer_length =
 			inurb->number_of_packets *
 			inurb->iso_frame_desc[0].length;
-		preempt_disable();
+
 		if (u == 0) {
 			int now;
 			struct usb_device *dev = inurb->dev;
@@ -686,19 +686,17 @@
 		}
 		err = usb_submit_urb(inurb, GFP_ATOMIC);
 		if (err < 0) {
-			preempt_enable();
 			snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])"
 				   " returned %i\n", u, err);
 			return err;
 		}
 		err = usb_submit_urb(outurb, GFP_ATOMIC);
 		if (err < 0) {
-			preempt_enable();
 			snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])"
 				   " returned %i\n", u, err);
 			return err;
 		}
-		preempt_enable();
+
 		if (inurb->start_frame != outurb->start_frame) {
 			snd_printd(KERN_DEBUG
 				   "u[%i] start_frames differ in:%u out:%u\n",
diff --git a/tools/perf/builtin-periodic.c b/tools/perf/builtin-periodic.c
index 70a0e2b..060e909 100644
--- a/tools/perf/builtin-periodic.c
+++ b/tools/perf/builtin-periodic.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -194,6 +194,8 @@
 	if (p == NULL)
 		return PERF_PERIODIC_ERROR;
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
+		if (((1 << cpu) & cpumask) == 0)
+			continue;
 		p->perf_fd[cpu] = sys_perf_event_open(p->attr, target_pid, cpu,
 					-1, 0);
 		if (p->perf_fd[cpu] < 0)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f022316..8c50da8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1869,8 +1869,10 @@
 
 	pr_debug("Writing event: %s\n", buf);
 	ret = write(fd, buf, strlen(buf));
-	if (ret < 0)
+	if (ret < 0) {
+		ret = -errno;
 		goto error;
+	}
 
 	printf("Remove event: %s\n", ent->s);
 	return 0;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 0a7ed5b..bf54c48 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1537,6 +1537,8 @@
 	field = malloc_or_die(sizeof(*field));
 
 	type = process_arg(event, field, &token);
+	while (type == EVENT_OP)
+		type = process_op(event, field, &token);
 	if (test_type_token(type, token, EVENT_DELIM, ","))
 		goto out_free;
 
@@ -1580,6 +1582,8 @@
 	field = malloc_or_die(sizeof(*field));
 
 	type = process_arg(event, field, &token);
+	while (type == EVENT_OP)
+		type = process_op(event, field, &token);
 	if (test_type_token(type, token, EVENT_DELIM, ","))
 		goto out_free;