Merge "arm/dt: 8974: Set otg_capability flag to get external VBUS notifications"
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index 4fedc72..3c4e1d3 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -4,15 +4,20 @@
 VESA EDP display interface specification.
 
 Required properties
-- compatible :		Must be "qcom,mdss-edp".
-- reg :				Offset and length of the register set for the device.
-- reg-names :		Names to refer to register sets related to this device
-- vdda-supply :		Phandle for vdd regulator device node.
-- gpio-panel-en	:	GPIO for supplying power to panel and to backlight driver.
-- status :			A string that has to be set to "okay/ok" to enable
-					the driver. By default this property will be set to
-					"disable". Will be set to "ok/okay" status for specific
-					platforms.
+- compatible :				Must be "qcom,mdss-edp".
+- reg :						Offset and length of the register set for the
+							device.
+- reg-names :				Names to refer to register sets related to this
+							device
+- vdda-supply :				Phandle for vdd regulator device node.
+- gpio-panel-en	:			GPIO for supplying power to panel and backlight
+							driver.
+- qcom,panel-lpg-channel :	LPG channel for backlight.
+- qcom,panel-pwm-period :	PWM period in microseconds.
+- status :					A string that has to be set to "okay/ok" to enable
+							the driver. By default this property will be set to
+							"disable". Will be set to "ok/okay" status for
+							specific platforms.
 
 Example:
 	mdss_edp: qcom,mdss_edp@fd923400 {
@@ -22,6 +27,8 @@
 		reg-names = "edp_base", "mmss_cc_base";
 		vdda-supply = <&pm8941_l12>;
 		gpio-panel-en = <&msmgpio 58 0>;
+		qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
+		qcom,panel-pwm-period = <53>;
 		status = "disable";
 	};
 
diff --git a/Documentation/devicetree/bindings/power/bq28400-battery.txt b/Documentation/devicetree/bindings/power/bq28400-battery.txt
new file mode 100644
index 0000000..3879b4d
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/bq28400-battery.txt
@@ -0,0 +1,18 @@
+TI BQ28400 Battery Gas Gauge
+
+The bq28400 monitors the battery temperature, capacity, voltage, current etc.
+The device interface is I2C, its I2C slave 7-bit address is 0xb.
+The device is usually embedded inside the "smart battery" pack.
+
+node required properties:
+- compatible:	Must be "ti,bq28400-battery".
+- reg:		I2C Address must be 0xb.
+
+Example:
+	i2c@f9967000 {
+		battery@b {
+			compatible = "ti,bq28400-battery";
+			reg = <0xb>;
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/power/smb350.txt b/Documentation/devicetree/bindings/power/smb350.txt
new file mode 100644
index 0000000..6f21236
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/smb350.txt
@@ -0,0 +1,43 @@
+Summit smb350 battery charger
+
+The smb350 charger supports stack-cell battery charging.
+
+The smb350 interface is via I2C bus.
+The i2c slave 7-bit address is programmable at manufacture.
+
+Node required properties:
+- compatible:		Must be "summit,smb350-charger".
+- reg:			The device 7-bit I2C address.
+- summit,stat-gpio		gpio which smb350 STAT pin connects to.
+- summit,chg-en-n-gpio		gpio which control charging enable.
+- summit,chg-susp-n-gpio	gpio which control device shutdown
+- summit,chg-current-ma		charging current in milliamps.
+- summit,term-current-ma	charging termination current in milliamps.
+				valid values are 200/300/400/500/600/700.
+				A value of zero means no termination current.
+
+Example:
+	i2c@f9967000 {
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0Xf9967000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 105 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+		label = "blsp_11";
+
+		smb350-charger@2b {
+			compatible = "summit,smb350-charger";
+			reg = <0x2b>; /* 0x56/0x57 */
+			summit,stat-gpio = <&pm8941_gpios 30 0x00>;
+			summit,chg-en-n-gpio = <&pm8941_gpios 10 0x00>;
+			summit,chg-susp-n-gpio = <&pm8941_gpios 13 0x00>;
+			summit,chg-current-ma = <1600>;
+			summit,term-current-ma = <200>;
+		};
+	};
+
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 252b9f5..470d540 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -228,6 +228,47 @@
 				 <0x1b80009e>, /* LPG_CHAN_8 */
 				 <0x1bc0009f>; /* LPG_PWM */
 	};
+
+	sdcc1: qcom,sdcc@f9824000 {
+		cell-index = <1>; /* SDC1 eMMC slot */
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf9824000 0x800>;
+		reg-names = "core_mem";
+		interrupts = <0 123 0>;
+		interrupt-names = "core_irq";
+
+		qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+		qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+		qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+		qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-bus-width = <8>;
+		qcom,sdcc-nonremovable;
+		qcom,sdcc-bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	};
+
+	sdcc2: qcom,sdcc@f98a4000 {
+		cell-index = <2>; /* SDC2 SD card slot */
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98a4000 0x800>;
+		reg-names = "core_mem";
+		interrupts = <0 125 0>;
+		interrupt-names = "core_irq";
+
+		qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+		qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+		qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+		qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-bus-width = <4>;
+		qcom,sdcc-xpc;
+		qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+		qcom,sdcc-current-limit = <800>;
+	};
 };
 
 /include/ "msm-pm8644.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-liquid.dts
index 2eacb46..d1a6148 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-liquid.dts
@@ -27,6 +27,13 @@
 		status = "ok";
 	};
 
+	i2c@f9967000 {
+		battery@b {
+			compatible = "ti,bq28400-battery";
+			reg = <0xb>;
+		};
+	};
+
 	gpio_keys {
 		compatible = "gpio-keys";
 		input-name = "gpio-keys";
@@ -314,6 +321,13 @@
 	};
 
 	gpio@e300 { /* GPIO 36 */
+		qcom,mode = <1>;  /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+		qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+		qcom,out-strength = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-select = <3>; /* QPNP_PIN_SEL_FUNC_2 */
+		qcom,master-en = <1>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index e791348..a51a38d 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -68,6 +68,9 @@
 		reg-names = "edp_base", "mmss_cc_base";
 		vdda-supply = <&pm8941_l12>;
 		gpio-panel-en = <&msmgpio 58 0>;
+		gpio-panel-pwm = <&pm8941_gpios 36 0>;
+		qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
+		qcom,panel-pwm-period = <53>;
 		status = "disable";
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 11f7c37..00b69ea 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -564,10 +564,12 @@
 		};
 	};
 
-	i2c@f9967000 {
+	i2c@f9967000 { /* BLSP#11 */
 		cell-index = <0>;
 		compatible = "qcom,i2c-qup";
 		reg = <0Xf9967000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
 		reg-names = "qup_phys_addr";
 		interrupts = <0 105 0>;
 		interrupt-names = "qup_err_intr";
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 93e84e9..1dc853b 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -11,7 +11,6 @@
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
-# CONFIG_PERF_EVENTS is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
@@ -84,6 +83,7 @@
 CONFIG_IPV6_MROUTE=y
 CONFIG_IPV6_PIMSM_V2=y
 # CONFIG_NET_ACTIVITY_STATS is not set
+CONFIG_IP_SCTP=y
 CONFIG_RFKILL=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index c45063f..203d3b7 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -12,7 +12,6 @@
 CONFIG_KALLSYMS_ALL=y
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
-# CONFIG_PERF_EVENTS is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
@@ -83,6 +82,7 @@
 CONFIG_IPV6_MROUTE=y
 CONFIG_IPV6_PIMSM_V2=y
 # CONFIG_NET_ACTIVITY_STATS is not set
+CONFIG_IP_SCTP=y
 CONFIG_RFKILL=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index 24e3452..e4dd4fb 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -41,6 +41,7 @@
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_ARM_ARCH_TIMER=y
+CONFIG_HOTPLUG_CPU=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index d8d2eae..c49ad93 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -275,6 +275,7 @@
 # CONFIG_BATTERY_MSM is not set
 CONFIG_QPNP_CHARGER=y
 CONFIG_QPNP_BMS=y
+CONFIG_BATTERY_BQ28400=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 36f417e..e1d4ca0 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -85,6 +85,13 @@
 # CONFIG_NET_VENDOR_CIRRUS is not set
 # CONFIG_NET_VENDOR_FARADAY is not set
 # CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
+CONFIG_ATH_COMMON=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_SDIO=m
+CONFIG_ATH6KL_DEBUG=y
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_MSM_RMNET is not set
@@ -120,6 +127,7 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
 CONFIG_HWMON=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_REGULATOR=y
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 53426c6..12f71a1 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -92,6 +92,7 @@
 static inline void outer_flush_all(void) { }
 static inline void outer_inv_all(void) { }
 static inline void outer_disable(void) { }
+static inline void outer_resume(void) { }
 
 #endif
 
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 3f36017..b258707 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2004,7 +2004,7 @@
 
 config MSM_PIL_TZAPPS
 	tristate "TZApps Boot Support"
-	depends on MSM_PIL
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for booting and shutting down TZApps.
 
@@ -2023,13 +2023,13 @@
 
 config MSM_PIL_VIDC
 	tristate "Video Core Secure Boot Support"
-	depends on MSM_PIL
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for authenticating the video core image.
 
 config MSM_PIL_VENUS
 	tristate "VENUS (Video) Boot Support"
-	depends on MSM_PIL
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for booting and shutting down the VENUS processor (Video).
 	  Venus is the Video subsystem processor used for video codecs.
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index fad7092..f35ae6b 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -281,8 +281,11 @@
 	if (SOCINFO_VERSION_MAJOR(version) == 2) {
 		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 2);
 	} else {
+		/* The bootloader has started returning 1.2 for chips that
+		   are either 1.1 or 1.2. To handle that and default any
+		   future revisions to this path, check for minor version >=1 */
 		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
-				(SOCINFO_VERSION_MINOR(version) == 1))
+				(SOCINFO_VERSION_MINOR(version) >= 1))
 			kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
 		else
 			kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index e64a672..c0e325a 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -512,4 +512,7 @@
 	} else if (machine_is_apq8064_cdp()) {
 		apq8064_pm8921_chg_pdata.has_dc_supply = true;
 	}
+
+	if (!machine_is_apq8064_mtp() && !machine_is_apq8064_liquid())
+		apq8064_pm8921_chg_pdata.battery_less_hardware = 1;
 }
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index bd1762d..3e31f68 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -18,7 +18,6 @@
 #include <linux/of_fdt.h>
 #include <linux/of_irq.h>
 #include <asm/hardware/gic.h>
-#include <asm/arch_timer.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/socinfo.h>
@@ -30,15 +29,9 @@
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 
+#include "board-dt.h"
 #include "clock.h"
 
-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, },
-	{}
-};
-
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
@@ -81,26 +74,7 @@
 	msm_reserve();
 }
 
-void __init mpq8092_init_irq(void)
-{
-	of_irq_init(irq_match);
-}
-
-static void __init mpq8092_dt_timer_init(void)
-{
-	arch_timer_of_register();
-}
-
-static struct sys_timer mpq8092_dt_timer = {
-	.init = mpq8092_dt_timer_init
-};
-
-static void __init mpq8092_dt_init_irq(void)
-{
-	mpq8092_init_irq();
-}
-
-static void __init mpq8092_dt_map_io(void)
+static void __init mpq8092_map_io(void)
 {
 	msm_map_mpq8092_io();
 	if (socinfo_init() < 0)
@@ -113,21 +87,19 @@
 			"msm_serial_hsl.0", NULL),
 	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
 			"spmi-pmic-arb.0", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+			"msm_sdcc.1", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+			"msm_sdcc.2", NULL),
 	{}
 };
 
-static void __init mpq8092_init(struct of_dev_auxdata **adata)
+static void __init mpq8092_init(void)
 {
+	struct of_dev_auxdata *adata = mpq8092_auxdata_lookup;
+
 	mpq8092_init_gpiomux();
-	*adata = mpq8092_auxdata_lookup;
 	msm_clock_init(&mpq8092_clock_init_data);
-}
-
-static void __init mpq8092_dt_init(void)
-{
-	struct of_dev_auxdata *adata = NULL;
-
-	mpq8092_init(&adata);
 	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
 }
 
@@ -136,12 +108,12 @@
 	NULL
 };
 
-DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
-	.map_io = mpq8092_dt_map_io,
-	.init_irq = mpq8092_dt_init_irq,
-	.init_machine = mpq8092_dt_init,
+DT_MACHINE_START(MSM8092_DT, "Qualcomm MSM 8092 (Flattened Device Tree)")
+	.map_io = mpq8092_map_io,
+	.init_irq = msm_dt_init_irq_nompm,
+	.init_machine = mpq8092_init,
 	.handle_irq = gic_handle_irq,
-	.timer = &mpq8092_dt_timer,
+	.timer = &msm_dt_timer,
 	.dt_compat = mpq8092_dt_match,
 	.reserve = mpq8092_dt_reserve,
 	.init_very_early = mpq8092_early_memory,
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 9afc05e..7039879 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -37,6 +37,7 @@
 #include <mach/socinfo.h>
 #include <mach/board.h>
 #include <mach/clk-provider.h>
+#include "board-dt.h"
 #include "clock.h"
 
 static struct clk_lookup msm_clocks_dummy[] = {
@@ -54,26 +55,6 @@
 	.size = ARRAY_SIZE(msm_clocks_dummy),
 };
 
-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, },
-	{},
-};
-
-static void __init msm8910_dt_timer_init(void)
-{
-	arch_timer_of_register();
-}
-
-static struct sys_timer msm8910_dt_timer = {
-	.init = msm8910_dt_timer_init
-};
-
-void __init msm8910_init_irq(void)
-{
-	of_irq_init(irq_match);
-}
-
 void __init msm8910_init(void)
 {
 	msm_clock_init(&msm_dummy_clock_init_data);
@@ -91,9 +72,9 @@
 
 DT_MACHINE_START(MSM8910_DT, "Qualcomm MSM 8910 (Flattened Device Tree)")
 	.map_io = msm_map_msm8910_io,
-	.init_irq = msm8910_init_irq,
+	.init_irq = msm_dt_init_irq_nompm,
 	.init_machine = msm8910_init,
 	.handle_irq = gic_handle_irq,
-	.timer = &msm8910_dt_timer,
+	.timer = &msm_dt_timer,
 	.dt_compat = msm8910_dt_match,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 99a5a34..578c665 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -163,10 +163,18 @@
 {
 	unsigned int version = socinfo_get_version();
 
+	/* Set the turbo speed for the AA and AB respectively */
+
 	if (cpu_is_msm8930aa())
 		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 450000000;
+	else if (cpu_is_msm8930ab())
+		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 500000000;
 
-	if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+	/* Set up the chip ID based on the SoC version */
+
+	if (cpu_is_msm8930ab())
+		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 3);
+	else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
 		(SOCINFO_VERSION_MINOR(version) == 2))
 		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 2);
 	else
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 8687b2a..0c7666b 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -596,4 +596,7 @@
 		else if (machine_is_msm8930_cdp())
 			pm8921_chg_pdata.has_dc_supply = true;
 	}
+
+	if (!machine_is_msm8930_mtp())
+		pm8921_chg_pdata.battery_less_hardware = 1;
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index 16a82b4..727c4c6 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -97,6 +97,8 @@
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar1p1-slim"),
 	REGULATOR_SUPPLY("vddp",		"0-0048"),
 	REGULATOR_SUPPLY("mhl_iovcc18",		"0-0039"),
+	REGULATOR_SUPPLY("vdd-io",		"spi0.0"),
+	REGULATOR_SUPPLY("vdd-phy",		"spi0.0"),
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("8038_l12",		NULL),
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index 8898b50..33e38ab 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -196,6 +196,8 @@
 	REGULATOR_SUPPLY("mhl_iovcc18",		"0-0039"),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("vdd-io",		"spi0.0"),
+	REGULATOR_SUPPLY("vdd-phy",		"spi0.0"),
 };
 VREG_CONSUMERS(S5) = {
 	REGULATOR_SUPPLY("8917_s5",		NULL),
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index d8a260b..9efedb1 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -612,4 +612,8 @@
 
 	if (machine_is_msm8960_fluid())
 		pm8921_bms_pdata.rconn_mohm = 20;
+
+	if (!machine_is_msm8960_fluid() && !machine_is_msm8960_liquid()
+			&& !machine_is_msm8960_fluid())
+		pm8921_chg_pdata.battery_less_hardware = 1;
 }
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 4a78e31..e919d78 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -3216,6 +3216,17 @@
 	msm_tsens_early_init(&msm_tsens_pdata);
 }
 
+static void __init msm8960_reset_spm_avs(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) {
+		struct msm_spm_platform_data *pdata = &msm_spm_data[i];
+		pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0;
+		pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0;
+	}
+}
+
 static void __init msm8960_cdp_init(void)
 {
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
@@ -3269,8 +3280,12 @@
 		msm_isa1200_board_info[0].platform_data = &isa1200_1_pdata;
 	msm8960_i2c_init();
 	msm8960_gfx_init();
+
+	if (cpu_is_msm8960ab())
+		msm8960_reset_spm_avs();
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
+
 	msm8960_init_buses();
 	platform_add_devices(msm8960_footswitch, msm8960_num_footswitch);
 	if (machine_is_msm8960_liquid())
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 7480437..19fb222 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -198,7 +198,7 @@
 		.edge = SMD_APPS_RPM,
 
 		.smd_int.irq_name = "rpm_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.flags = IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
 		.smd_int.irq_id = -1,
 		.smd_int.device_name = "smd_dev",
 		.smd_int.dev_id = 0,
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 49f2561..5c7eebe 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -21,11 +21,8 @@
 #include <linux/of_irq.h>
 #include <linux/memory.h>
 #include <asm/mach/map.h>
-#include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
-#include <asm/arch_timer.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
 #include <mach/socinfo.h>
 #include <mach/board.h>
 #include <mach/restart.h>
@@ -35,19 +32,15 @@
 #include <mach/msm_memtypes.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_smd.h>
-#include <mach/scm.h>
 #include <mach/rpm-smd.h>
 #include <mach/rpm-regulator-smd.h>
-#include <mach/mpm.h>
+#include "board-dt.h"
 #include "clock.h"
 #include "modem_notifier.h"
 #include "lpm_resources.h"
 #include "spm.h"
 
 #define MSM_KERNEL_EBI_SIZE	0x51000
-#define SCM_SVC_L2CC_PL310	16
-#define L2CC_PL310_CTRL_ID	1
-#define L2CC_PL310_ON		1
 
 static struct memtype_reserve msm9625_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
@@ -76,10 +69,6 @@
 	.paddr_to_memtype = msm9625_paddr_to_memtype,
 };
 
-#define L2CC_AUX_CTRL	((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
-			(0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
-			(0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT))
-
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
@@ -103,13 +92,6 @@
 	.size = ARRAY_SIZE(msm_clocks_dummy),
 };
 
-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, },
-	{}
-};
-
 static const char *msm9625_dt_match[] __initconst = {
 	"qcom,msm9625",
 	NULL
@@ -129,34 +111,6 @@
 	{}
 };
 
-static struct of_device_id mpm_match[] __initdata = {
-	{.compatible = "qcom,mpm-v2", },
-	{},
-};
-
-void __init msm9625_init_irq(void)
-{
-	struct device_node *node;
-	scm_call_atomic1(SCM_SVC_L2CC_PL310, L2CC_PL310_CTRL_ID, L2CC_PL310_ON);
-	l2x0_of_init(0, ~0UL);
-	of_irq_init(irq_match);
-	node = of_find_matching_node(NULL, mpm_match);
-
-	WARN_ON(!node);
-
-	if (node)
-		of_mpm_init(node);
-}
-
-static void __init msm_dt_timer_init(void)
-{
-	arch_timer_of_register();
-}
-
-static struct sys_timer msm_dt_timer = {
-	.init = msm_dt_timer_init
-};
-
 static void __init msm9625_early_memory(void)
 {
 	reserve_info = &msm9625_reserve_info;
@@ -331,9 +285,9 @@
 	msm9625_add_drivers();
 }
 
-DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
+DT_MACHINE_START(MSM9625_DT, "Qualcomm MSM 9625 (Flattened Device Tree)")
 	.map_io = msm_map_msm9625_io,
-	.init_irq = msm9625_init_irq,
+	.init_irq = msm_dt_init_irq_l2x0,
 	.init_machine = msm9625_init,
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 3654de8..74b0d0d 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -17,12 +17,18 @@
 #include <linux/mfd/wcd9xxx/core.h>
 #include <asm/arch_timer.h>
 #include <asm/mach/time.h>
+#include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <mach/mpm.h>
 #include <mach/qpnp-int.h>
+#include <mach/scm.h>
 
 #include "board-dt.h"
 
+#define SCM_SVC_L2CC_PL310	16
+#define L2CC_PL310_CTRL_ID	1
+#define L2CC_PL310_ON		1
+
 static void __init msm_dt_timer_init(void)
 {
 	arch_timer_of_register();
@@ -62,3 +68,10 @@
 {
 	of_irq_init(irq_match);
 }
+
+void __init msm_dt_init_irq_l2x0(void)
+{
+	scm_call_atomic1(SCM_SVC_L2CC_PL310, L2CC_PL310_CTRL_ID, L2CC_PL310_ON);
+	l2x0_of_init(0, ~0UL);
+	msm_dt_init_irq();
+}
diff --git a/arch/arm/mach-msm/board-dt.h b/arch/arm/mach-msm/board-dt.h
index 16a6135..cc3e92c 100644
--- a/arch/arm/mach-msm/board-dt.h
+++ b/arch/arm/mach-msm/board-dt.h
@@ -13,3 +13,4 @@
 extern struct sys_timer msm_dt_timer;
 void __init msm_dt_init_irq(void);
 void __init msm_dt_init_irq_nompm(void);
+void __init msm_dt_init_irq_l2x0(void);
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index e42fe65..e1390db 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -160,7 +160,8 @@
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
 	VDD_DIG_NOMINAL,
-	VDD_DIG_HIGH
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
 };
 
 static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
@@ -184,15 +185,21 @@
 	return rc;
 }
 
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 
 #define PCOM_XO_DISABLE	0
 #define PCOM_XO_ENABLE	1
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 934bf88..472cb68 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -376,7 +376,8 @@
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
 	VDD_DIG_NOMINAL,
-	VDD_DIG_HIGH
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
 };
 
 static int set_vdd_dig_8960(struct clk_vdd_class *vdd_class, int level)
@@ -391,7 +392,7 @@
 				    vdd_uv[level], 1150000, 1);
 }
 
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960, VDD_DIG_NUM);
 
 static int rpm_vreg_dig_8930 = RPM_VREG_ID_PM8038_VDD_DIG_CORNER;
 static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
@@ -409,21 +410,31 @@
 }
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2), \
-	.fmax[VDD_DIG_##l3] = (f3)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 
 enum vdd_sr2_hdmi_pll_levels {
 	VDD_SR2_HDMI_PLL_OFF,
-	VDD_SR2_HDMI_PLL_ON
+	VDD_SR2_HDMI_PLL_ON,
+	VDD_SR2_HDMI_PLL_NUM
 };
 
 static int set_vdd_sr2_hdmi_pll_8960(struct clk_vdd_class *vdd_class, int level)
@@ -455,7 +466,8 @@
 	return rc;
 }
 
-static DEFINE_VDD_CLASS(vdd_sr2_hdmi_pll, set_vdd_sr2_hdmi_pll_8960);
+static DEFINE_VDD_CLASS(vdd_sr2_hdmi_pll, set_vdd_sr2_hdmi_pll_8960,
+			VDD_SR2_HDMI_PLL_NUM);
 
 static int sr2_lreg_uv[] = {
 	[VDD_SR2_HDMI_PLL_OFF] = 0,
@@ -530,7 +542,10 @@
 		.rate = 1200000000,
 		.ops = &clk_ops_local_pll,
 		.vdd_class = &vdd_sr2_hdmi_pll,
-		.fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
+		.fmax = (unsigned long[VDD_SR2_HDMI_PLL_NUM]) {
+			[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX
+		},
+		.num_fmax = VDD_SR2_HDMI_PLL_NUM,
 		CLK_INIT(pll3_clk.c),
 	},
 };
@@ -1532,7 +1547,7 @@
 static CLK_SDC(sdc4_clk, 4, 3,  33000000,  67000000);
 static CLK_SDC(sdc5_clk, 5, 2,  33000000,  67000000);
 
-static unsigned long fmax_sdc1_8064v2[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_sdc1_8064v2[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 100000000,
 	[VDD_DIG_NOMINAL] = 200000000,
 };
@@ -1933,7 +1948,7 @@
 	},
 };
 
-static unsigned long fmax_ce3_8064v2[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_ce3_8064v2[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     =  57000000,
 	[VDD_DIG_NOMINAL] = 120000000,
 };
@@ -3580,25 +3595,25 @@
 	F_END
 };
 
-static unsigned long fmax_gfx3d_8064ab[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8064ab[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 325000000,
 	[VDD_DIG_HIGH]    = 450000000
 };
 
-static unsigned long fmax_gfx3d_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8064[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 325000000,
 	[VDD_DIG_HIGH]    = 400000000
 };
 
-static unsigned long fmax_gfx3d_8930[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8930[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 192000000,
 	[VDD_DIG_NOMINAL] = 320000000,
 	[VDD_DIG_HIGH]    = 400000000
 };
 
-static unsigned long fmax_gfx3d_8930aa[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8930aa[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 192000000,
 	[VDD_DIG_NOMINAL] = 320000000,
 	[VDD_DIG_HIGH]    = 450000000
@@ -3750,7 +3765,7 @@
 	F_END
 };
 
-static unsigned long fmax_ijpeg_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_ijpeg_8064[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 266667000,
 	[VDD_DIG_HIGH]    = 320000000
@@ -3877,7 +3892,7 @@
 	F_END
 };
 
-static unsigned long fmax_mdp_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_mdp_8064[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 266667000
 };
@@ -4071,7 +4086,10 @@
 	.dbg_name = "hdmi_pll_clk",
 	.ops = &clk_ops_hdmi_pll,
 	.vdd_class = &vdd_sr2_hdmi_pll,
-	.fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
+	.fmax = (unsigned long [VDD_SR2_HDMI_PLL_NUM]) {
+		[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
+	},
+	.num_fmax = VDD_SR2_HDMI_PLL_NUM,
 	CLK_INIT(hdmi_pll_clk),
 };
 
@@ -4103,7 +4121,7 @@
 	F_END
 };
 
-static unsigned long fmax_tv_src_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_tv_src_8064[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     =  74250000,
 	[VDD_DIG_NOMINAL] = 149000000
 };
@@ -4342,7 +4360,7 @@
 	},
 };
 
-static unsigned long fmax_vcodec_8064v2[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_vcodec_8064v2[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 100000000,
 	[VDD_DIG_NOMINAL] = 200000000,
 	[VDD_DIG_HIGH]    = 266670000,
@@ -4424,7 +4442,7 @@
 	F_END
 };
 
-static unsigned long fmax_vfe_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_vfe_8064[VDD_DIG_NUM] = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 266667000,
 	[VDD_DIG_HIGH]    = 320000000
@@ -6565,37 +6583,25 @@
 	 */
 	if (cpu_is_apq8064()) {
 		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
-
-		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064,
-		       sizeof(gfx3d_clk.c.fmax));
+		gfx3d_clk.c.fmax = fmax_gfx3d_8064;
 	}
 	if (cpu_is_apq8064ab()) {
 		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
-
-		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064ab,
-		       sizeof(gfx3d_clk.c.fmax));
+		gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
 	}
 	if ((cpu_is_apq8064() &&
 		SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
 		cpu_is_apq8064ab()) {
 
-		memcpy(vcodec_clk.c.fmax, fmax_vcodec_8064v2,
-			sizeof(vcodec_clk.c.fmax));
-		memcpy(ce3_src_clk.c.fmax, fmax_ce3_8064v2,
-			sizeof(ce3_src_clk.c.fmax));
-		memcpy(sdc1_clk.c.fmax, fmax_sdc1_8064v2,
-			sizeof(sdc1_clk.c.fmax));
+		vcodec_clk.c.fmax = fmax_vcodec_8064v2;
+		ce3_src_clk.c.fmax = fmax_ce3_8064v2;
+		sdc1_clk.c.fmax = fmax_sdc1_8064v2;
 	}
 	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
-		memcpy(ijpeg_clk.c.fmax, fmax_ijpeg_8064,
-		       sizeof(ijpeg_clk.c.fmax));
-		memcpy(mdp_clk.c.fmax, fmax_mdp_8064,
-		       sizeof(ijpeg_clk.c.fmax));
-		memcpy(tv_src_clk.c.fmax, fmax_tv_src_8064,
-		       sizeof(tv_src_clk.c.fmax));
-		memcpy(vfe_clk.c.fmax, fmax_vfe_8064,
-		       sizeof(vfe_clk.c.fmax));
-
+		ijpeg_clk.c.fmax = fmax_ijpeg_8064;
+		mdp_clk.c.fmax = fmax_mdp_8064;
+		tv_src_clk.c.fmax = fmax_tv_src_8064;
+		vfe_clk.c.fmax = fmax_vfe_8064;
 		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
 	}
 
@@ -6604,11 +6610,9 @@
 	 * clocks which differ between 8960 and 8930.
 	 */
 	if (cpu_is_msm8930() || cpu_is_msm8627()) {
-		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
-		       sizeof(gfx3d_clk.c.fmax));
+		gfx3d_clk.c.fmax = fmax_gfx3d_8930;
 	} else if (cpu_is_msm8930aa()) {
-		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930aa,
-		       sizeof(gfx3d_clk.c.fmax));
+		gfx3d_clk.c.fmax = fmax_gfx3d_8930aa;
 	}
 	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
 		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 246ceaf..76b8abf 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -588,23 +588,33 @@
 	}
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2), \
-	.fmax[VDD_DIG_##l3] = (f3)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 
 enum vdd_dig_levels {
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
 	VDD_DIG_NOMINAL,
-	VDD_DIG_HIGH
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
 };
 
 static const int vdd_corner[] = {
@@ -622,7 +632,7 @@
 					RPM_REGULATOR_CORNER_SUPER_TURBO);
 }
 
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
 
 #define RPM_MISC_CLK_TYPE	0x306b6c63
 #define RPM_BUS_CLK_TYPE	0x316b6c63
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index bc4bb2e..3816b54 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -268,7 +268,8 @@
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
 	VDD_DIG_NOMINAL,
-	VDD_DIG_HIGH
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
 };
 
 static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
@@ -284,20 +285,29 @@
 				    vdd_uv[level], 1200000, 1);
 }
 
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2), \
-	.fmax[VDD_DIG_##l3] = (f3)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 
 DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
 DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 035ef5c..338361b 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -182,7 +182,8 @@
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
 	VDD_DIG_NOMINAL,
-	VDD_DIG_HIGH
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
 };
 
 static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
@@ -198,15 +199,21 @@
 		RPM_VREG_VOTER3, vdd_corner[level], RPM_VREG_CORNER_HIGH, 1);
 }
 
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 
 /*
  * Clock Descriptions
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index fb4f32a..b9362cf 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -291,23 +291,33 @@
 	}
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 #define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
-	.vdd_class = &vdd_dig, \
-	.fmax[VDD_DIG_##l1] = (f1), \
-	.fmax[VDD_DIG_##l2] = (f2), \
-	.fmax[VDD_DIG_##l3] = (f3)
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
 
 enum vdd_dig_levels {
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
 	VDD_DIG_NOMINAL,
-	VDD_DIG_HIGH
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
 };
 
 static const int vdd_corner[] = {
@@ -325,7 +335,7 @@
 					RPM_REGULATOR_CORNER_SUPER_TURBO);
 }
 
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
 
 /* TODO: Needs to confirm the below values */
 #define RPM_MISC_CLK_TYPE	0x306b6c63
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 8bd4433..489d623 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -157,7 +157,7 @@
 			   clock->dbg_name, clock->rate);
 		return 0;
 	}
-	for (level = 0; level < ARRAY_SIZE(clock->fmax); level++) {
+	for (level = 0; level < clock->num_fmax; level++) {
 		if (vdd_level == level)
 			seq_printf(m, "[%lu] ", clock->fmax[level]);
 		else
@@ -189,7 +189,7 @@
 	if (!clock->vdd_class) {
 		fmax = INT_MAX;
 	} else {
-		for (level = 0; level < ARRAY_SIZE(clock->fmax); level++)
+		for (level = 0; level < clock->num_fmax; level++)
 			if (clock->fmax[level])
 				fmax = clock->fmax[level];
 	}
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 5100980..e9dd974 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -37,11 +37,11 @@
 {
 	int level;
 
-	for (level = 0; level < ARRAY_SIZE(clk->fmax); level++)
+	for (level = 0; level < clk->num_fmax; level++)
 		if (rate <= clk->fmax[level])
 			break;
 
-	if (level == ARRAY_SIZE(clk->fmax)) {
+	if (level == clk->num_fmax) {
 		pr_err("Rate %lu for %s is greater than highest Fmax\n", rate,
 			clk->dbg_name);
 		return -EINVAL;
@@ -55,7 +55,7 @@
 {
 	int level, rc;
 
-	for (level = ARRAY_SIZE(vdd_class->level_votes)-1; level > 0; level--)
+	for (level = vdd_class->num_levels-1; level > 0; level--)
 		if (vdd_class->level_votes[level])
 			break;
 
@@ -74,6 +74,9 @@
 {
 	int rc;
 
+	if (level >= vdd_class->num_levels)
+		return -EINVAL;
+
 	mutex_lock(&vdd_class->lock);
 	vdd_class->level_votes[level]++;
 	rc = update_vdd(vdd_class);
@@ -89,6 +92,9 @@
 {
 	int rc = 0;
 
+	if (level >= vdd_class->num_levels)
+		return -EINVAL;
+
 	mutex_lock(&vdd_class->lock);
 	if (WARN(!vdd_class->level_votes[level],
 			"Reference counts are incorrect for %s level %d\n",
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 770713d..d47e88e 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -39,8 +39,6 @@
 #define ENABLE_VOTED	4	/* Bit pol: 1 = running; delay on disable */
 #define DELAY		5	/* No bit to check, just delay */
 
-#define MAX_VDD_LEVELS			4
-
 /**
  * struct clk_vdd_class - Voltage scaling class
  * @class_name: name of the class
@@ -52,16 +50,19 @@
 struct clk_vdd_class {
 	const char *class_name;
 	int (*set_vdd)(struct clk_vdd_class *v_class, int level);
-	int level_votes[MAX_VDD_LEVELS];
+	int *level_votes;
+	int num_levels;
 	unsigned long cur_level;
 	struct mutex lock;
 };
 
-#define DEFINE_VDD_CLASS(_name, _set_vdd) \
+#define DEFINE_VDD_CLASS(_name, _set_vdd, _num_levels) \
 	struct clk_vdd_class _name = { \
 		.class_name = #_name, \
 		.set_vdd = _set_vdd, \
-		.cur_level = ARRAY_SIZE(_name.level_votes), \
+		.level_votes = (int [_num_levels]) {}, \
+		.num_levels = _num_levels, \
+		.cur_level = _num_levels, \
 		.lock = __MUTEX_INITIALIZER(_name.lock) \
 	}
 
@@ -109,7 +110,8 @@
 	const char *dbg_name;
 	struct clk *depends;
 	struct clk_vdd_class *vdd_class;
-	unsigned long fmax[MAX_VDD_LEVELS];
+	unsigned long *fmax;
+	int num_fmax;
 	unsigned long rate;
 
 	struct list_head children;
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 38813e1..e5892c3 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1153,6 +1153,37 @@
 	return 0;
 }
 
+static void sched_dequeue(struct ocmem_req *victim_req)
+{
+	struct ocmem_req *req = NULL;
+	struct ocmem_req *next = NULL;
+	int id;
+
+	if (!victim_req)
+		return;
+
+	id = victim_req->owner;
+
+	mutex_lock(&sched_queue_mutex);
+
+	if (list_empty(&sched_queue[id]))
+		goto dequeue_done;
+
+	list_for_each_entry_safe(req, next, &sched_queue[id], sched_list)
+	{
+		if (req == victim_req) {
+			pr_debug("ocmem: Cancelling pending request %p\n",
+							req);
+			list_del(&req->sched_list);
+			goto dequeue_done;
+		}
+	}
+
+dequeue_done:
+	mutex_unlock(&sched_queue_mutex);
+	return;
+}
+
 static struct ocmem_req *ocmem_fetch_req(void)
 {
 	int i;
@@ -1379,6 +1410,10 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&sched_mutex);
+	sched_dequeue(req);
+	mutex_unlock(&sched_mutex);
+
 	if (!TEST_STATE(req, R_FREE)) {
 
 		rc = process_unmap(req, req->req_start, req->req_end);
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
index 2345453..be78fab 100644
--- a/arch/arm/mach-msm/pil-tzapps.c
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -16,9 +16,18 @@
 #include <linux/elf.h>
 #include <linux/err.h>
 
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
+struct tzapps_data {
+	struct pil_device *pil;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+};
+
 static int pil_tzapps_init_image(struct pil_desc *pil, const u8 *metadata,
 		size_t size)
 {
@@ -41,10 +50,28 @@
 	.shutdown = pil_tzapps_shutdown,
 };
 
+#define subsys_to_drv(d) container_of(d, struct tzapps_data, subsys_desc)
+
+static int tzapps_start(const struct subsys_desc *desc)
+{
+	void *ret;
+
+	ret = pil_get("tzapps");
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+	return 0;
+}
+
+static void tzapps_stop(const struct subsys_desc *desc)
+{
+	struct tzapps_data *drv = subsys_to_drv(desc);
+	pil_put(drv->pil);
+}
+
 static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
 {
 	struct pil_desc *desc;
-	struct pil_device *pil;
+	struct tzapps_data *drv;
 
 	if (pas_supported(PAS_TZAPPS) < 0)
 		return -ENOSYS;
@@ -53,21 +80,38 @@
 	if (!desc)
 		return -ENOMEM;
 
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
 	desc->name = "tzapps";
 	desc->dev = &pdev->dev;
 	desc->ops = &pil_tzapps_ops;
 	desc->owner = THIS_MODULE;
-	pil = msm_pil_register(desc);
-	if (IS_ERR(pil))
-		return PTR_ERR(pil);
-	platform_set_drvdata(pdev, pil);
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil))
+		return PTR_ERR(drv->pil);
+
+	drv->subsys_desc.name = "tzapps";
+	drv->subsys_desc.dev = &pdev->dev;
+	drv->subsys_desc.owner = THIS_MODULE;
+	drv->subsys_desc.start = tzapps_start;
+	drv->subsys_desc.stop = tzapps_stop;
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		msm_pil_unregister(drv->pil);
+		return PTR_ERR(drv->subsys);
+	}
 	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);
+	struct tzapps_data *drv = platform_get_drvdata(pdev);
+	subsys_unregister(drv->subsys);
+	msm_pil_unregister(drv->pil);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index e331296..e3125cf 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -28,6 +28,8 @@
 
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -66,6 +68,8 @@
 	void __iomem *venus_wrapper_base;
 	void __iomem *venus_vbif_base;
 	struct pil_device *pil;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
 	struct regulator *gdsc;
 	phys_addr_t start_addr;
 	struct clk *clks[ARRAY_SIZE(clk_names)];
@@ -78,6 +82,8 @@
 	u32 fw_max_paddr;
 };
 
+#define subsys_to_drv(d) container_of(d, struct venus_data, subsys_desc)
+
 static int venus_register_domain(u32 fw_max_sz)
 {
 	struct msm_iova_partition venus_fw_partition = {
@@ -381,6 +387,23 @@
 	.proxy_unvote = pil_venus_remove_proxy_vote,
 };
 
+static int venus_start(const struct subsys_desc *desc)
+{
+	void *ret;
+	struct venus_data *drv = subsys_to_drv(desc);
+
+	ret = pil_get(drv->subsys_desc.name);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+	return 0;
+}
+
+static void venus_stop(const struct subsys_desc *desc)
+{
+	struct venus_data *drv = subsys_to_drv(desc);
+	pil_put(drv->pil);
+}
+
 static int __devinit pil_venus_probe(struct platform_device *pdev)
 {
 	struct venus_data *drv;
@@ -488,12 +511,25 @@
 	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
 
+	drv->subsys_desc.name = desc->name;
+	drv->subsys_desc.owner = THIS_MODULE;
+	drv->subsys_desc.dev = &pdev->dev;
+	drv->subsys_desc.start = venus_start;
+	drv->subsys_desc.stop = venus_stop;
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		msm_pil_unregister(drv->pil);
+		return PTR_ERR(drv->subsys);
+	}
+
 	return 0;
 }
 
 static int __devexit pil_venus_remove(struct platform_device *pdev)
 {
 	struct venus_data *drv = platform_get_drvdata(pdev);
+	subsys_unregister(drv->subsys);
 	msm_pil_unregister(drv->pil);
 
 	return 0;
diff --git a/arch/arm/mach-msm/pil-vidc.c b/arch/arm/mach-msm/pil-vidc.c
index e4c6a2d..b2609b1 100644
--- a/arch/arm/mach-msm/pil-vidc.c
+++ b/arch/arm/mach-msm/pil-vidc.c
@@ -17,6 +17,9 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
@@ -24,6 +27,8 @@
 	struct clk *smmu_iface;
 	struct clk *core;
 	struct pil_device *pil;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
 };
 
 static int pil_vidc_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -63,6 +68,24 @@
 	.shutdown = pil_vidc_shutdown,
 };
 
+#define subsys_to_drv(d) container_of(d, struct vidc_data, subsys_desc)
+
+static int vidc_start(const struct subsys_desc *desc)
+{
+	void *ret;
+
+	ret = pil_get("vidc");
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+	return 0;
+}
+
+static void vidc_stop(const struct subsys_desc *desc)
+{
+	struct vidc_data *drv = subsys_to_drv(desc);
+	pil_put(drv->pil);
+}
+
 static int __devinit pil_vidc_driver_probe(struct platform_device *pdev)
 {
 	struct pil_desc *desc;
@@ -95,12 +118,25 @@
 	drv->pil = msm_pil_register(desc);
 	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
+
+	drv->subsys_desc.name = "vidc";
+	drv->subsys_desc.dev = &pdev->dev;
+	drv->subsys_desc.owner = THIS_MODULE;
+	drv->subsys_desc.start = vidc_start;
+	drv->subsys_desc.stop = vidc_stop;
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		msm_pil_unregister(drv->pil);
+		return PTR_ERR(drv->subsys);
+	}
 	return 0;
 }
 
 static int __devexit pil_vidc_driver_exit(struct platform_device *pdev)
 {
 	struct vidc_data *drv = platform_get_drvdata(pdev);
+	subsys_unregister(drv->subsys);
 	msm_pil_unregister(drv->pil);
 	return 0;
 }
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index cb9fc76..bb4da0f 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -38,6 +38,8 @@
 static unsigned int l2x0_ways;
 static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
 static void pl310_save(void);
+static void pl310_resume(void);
+static void l2x0_resume(void);
 
 static inline bool is_pl310_rev(int rev)
 {
@@ -378,15 +380,18 @@
 		sync_reg_offset = L2X0_DUMMY_REG;
 #endif
 		outer_cache.set_debug = pl310_set_debug;
+		outer_cache.resume = pl310_resume;
 		break;
 	case L2X0_CACHE_ID_PART_L210:
 		l2x0_ways = (aux >> 13) & 0xf;
 		type = "L210";
+		outer_cache.resume = l2x0_resume;
 		break;
 	default:
 		/* Assume unknown chips have 8 ways */
 		l2x0_ways = 8;
 		type = "L2x0 series";
+		outer_cache.resume = l2x0_resume;
 		break;
 	}
 
diff --git a/block/test-iosched.c b/block/test-iosched.c
index 0a033dc..52070ac 100644
--- a/block/test-iosched.c
+++ b/block/test-iosched.c
@@ -95,6 +95,9 @@
 			return;
 	}
 
+	ptd->test_info.test_duration = jiffies -
+				ptd->test_info.test_duration;
+
 	test_pr_info("%s: Test is completed", __func__);
 
 	test_iosched_mark_test_completion();
@@ -124,7 +127,7 @@
 	test_rq = (struct test_request *)rq->elv.priv[0];
 	BUG_ON(!test_rq);
 
-	test_pr_info("%s: request %d completed, err=%d",
+	test_pr_debug("%s: request %d completed, err=%d",
 	       __func__, test_rq->req_id, err);
 
 	test_rq->req_completed = true;
@@ -669,6 +672,7 @@
 			goto error;
 		}
 
+		ptd->test_info.test_duration = jiffies;
 		ret = run_test(ptd);
 		if (ret) {
 			test_pr_err("%s: failed to run the test\n", __func__);
@@ -678,6 +682,7 @@
 		test_pr_info("%s: Waiting for the test completion", __func__);
 
 		wait_event(ptd->wait_q, ptd->test_state == TEST_COMPLETED);
+		t_info->test_duration = ptd->test_info.test_duration;
 		del_timer_sync(&ptd->timeout_timer);
 
 		ret = check_test_result(ptd);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index a37260b..28d0565 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -257,6 +257,7 @@
 	int mask_check;
 	int logging_process_id;
 	struct task_struct *socket_process;
+	struct task_struct *callback_process;
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	unsigned char *buf_in_sdio;
 	unsigned char *usb_buf_mdm_out;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index c29a1d3f..8a7ae9f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -262,6 +262,10 @@
 		(driver->socket_process->tgid == current->tgid)) {
 		driver->socket_process = NULL;
 	}
+	if (driver->callback_process &&
+		(driver->callback_process->tgid == current->tgid)) {
+		driver->callback_process = NULL;
+	}
 
 #ifdef CONFIG_DIAG_OVER_USB
 	/* If the SD logging process exits, change logging to USB mode */
@@ -522,6 +526,11 @@
 		mutex_lock(&driver->diagchar_mutex);
 		temp = driver->logging_mode;
 		driver->logging_mode = (int)ioarg;
+		if (temp == driver->logging_mode) {
+			mutex_unlock(&driver->diagchar_mutex);
+			pr_alert("diag: forbidden logging change requested\n");
+			return 0;
+		}
 		if (driver->logging_mode == MEMORY_DEVICE_MODE) {
 			diag_clear_hsic_tbl();
 			driver->mask_check = 1;
@@ -540,17 +549,17 @@
 				}
 			}
 		}
-		if (driver->logging_mode == UART_MODE) {
+		if (driver->logging_mode == UART_MODE ||
+			driver->logging_mode == SOCKET_MODE ||
+			driver->logging_mode == CALLBACK_MODE) {
 			diag_clear_hsic_tbl();
 			driver->mask_check = 0;
 			driver->logging_mode = MEMORY_DEVICE_MODE;
 		}
-		if (driver->logging_mode == SOCKET_MODE) {
-			diag_clear_hsic_tbl();
+		if (driver->logging_mode == SOCKET_MODE)
 			driver->socket_process = current;
-			driver->mask_check = 0;
-			driver->logging_mode = MEMORY_DEVICE_MODE;
-		}
+		if (driver->logging_mode == CALLBACK_MODE)
+			driver->callback_process = current;
 		driver->logging_process_id = current->tgid;
 		mutex_unlock(&driver->diagchar_mutex);
 		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
@@ -680,7 +689,7 @@
 				  driver->data_ready[index]);
 	mutex_lock(&driver->diagchar_mutex);
 
-	if ((driver->data_ready[index] & USER_SPACE_LOG_TYPE) && (driver->
+	if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
 					logging_mode == MEMORY_DEVICE_MODE)) {
 #ifdef CONFIG_DIAG_BRIDGE_CODE
 		unsigned long spin_lock_flags;
@@ -689,7 +698,7 @@
 
 		pr_debug("diag: process woken up\n");
 		/*Copy the type of data being passed*/
-		data_type = driver->data_ready[index] & USER_SPACE_LOG_TYPE;
+		data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
 		COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
 		/* place holder for number of data field */
 		ret += 4;
@@ -892,7 +901,7 @@
 		/* copy number of data fields */
 		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
 		ret -= 4;
-		driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
+		driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
 		if (driver->ch)
 			queue_work(driver->diag_wq,
 					 &(driver->diag_read_smd_work));
@@ -909,10 +918,10 @@
 #endif
 		APPEND_DEBUG('n');
 		goto exit;
-	} else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
+	} else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) {
 		/* In case, the thread wakes up and the logging mode is
 		not memory device any more, the condition needs to be cleared */
-		driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
+		driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
 	}
 
 	if (driver->data_ready[index] & DEINIT_TYPE) {
@@ -1026,7 +1035,7 @@
 							payload_size);
 		return err;
 	}
-	if (pkt_type == USER_SPACE_LOG_TYPE) {
+	if (pkt_type == USER_SPACE_DATA_TYPE) {
 		err = copy_from_user(driver->user_space_data, buf + 4,
 							 payload_size);
 		/* Check masks for On-Device logging */
@@ -1409,6 +1418,7 @@
 		driver->num_clients = max_clients;
 		driver->logging_mode = USB_MODE;
 		driver->socket_process = NULL;
+		driver->callback_process = NULL;
 		driver->mask_check = 0;
 		mutex_init(&driver->diagchar_mutex);
 		init_waitqueue_head(&driver->wait_q);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index d27ebcf..978b63b 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -212,8 +212,8 @@
 		 * have their data read/logged.  Detect and remedy this
 		 * situation.
 		 */
-		if ((driver->data_ready[i] & USER_SPACE_LOG_TYPE) == 0) {
-			driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
+		if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
+			driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
 			pr_debug("diag: Force wakeup of logging process\n");
 			wake_up_interruptible(&driver->wait_q);
 		}
@@ -357,7 +357,7 @@
 						 driver->logging_process_id)
 				break;
 		if (i < driver->num_clients) {
-			driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
+			driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
 			pr_debug("diag: wake up logging process\n");
 			wake_up_interruptible(&driver->wait_q);
 		} else
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 8a9567b..1312448 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -382,7 +382,7 @@
 			break;
 
 		case QCE_MODE_XTS:
-			if (creq->encklen ==  AES128_KEY_SIZE)
+			if (creq->encklen/2 ==  AES128_KEY_SIZE)
 				*cmdlistinfo = &cmdlistptr->cipher_aes_128_xts;
 			else
 				*cmdlistinfo = &cmdlistptr->cipher_aes_256_xts;
@@ -767,15 +767,30 @@
 			if ((pce_dev->mode == QCE_MODE_CTR) ||
 				(pce_dev->mode == QCE_MODE_XTS)) {
 				uint32_t num_blk = 0;
-				uint32_t cntr_iv = 0;
+				uint32_t cntr_iv3 = 0;
+				unsigned long long cntr_iv64 = 0;
+				unsigned char *b = (unsigned char *)(&cntr_iv3);
 
 				memcpy(iv, areq->info, sizeof(iv));
-				if (pce_dev->mode == QCE_MODE_CTR)
+				if (pce_dev->mode != QCE_MODE_XTS)
 					num_blk = areq->nbytes/16;
-				cntr_iv = (u32)(((u32)(*(iv + 14))) << 8) |
-							(u32)(*(iv + 15));
-				*(iv + 14) = (char)((cntr_iv + num_blk) >> 8);
-				*(iv + 15) = (char)((cntr_iv + num_blk) & 0xFF);
+				else
+					num_blk = 1;
+				cntr_iv3 =  ((*(iv + 12) << 24) & 0xff000000) |
+					(((*(iv + 13)) << 16) & 0xff0000) |
+					(((*(iv + 14)) << 8) & 0xff00) |
+					(*(iv + 15) & 0xff);
+				cntr_iv64 =
+					(((unsigned long long)cntr_iv3 &
+					(unsigned long long)0xFFFFFFFFULL) +
+					(unsigned long long)num_blk) %
+					(unsigned long long)(0x100000000ULL);
+
+				cntr_iv3 = (u32)(cntr_iv64 & 0xFFFFFFFF);
+				*(iv + 15) = (char)(*b);
+				*(iv + 14) = (char)(*(b + 1));
+				*(iv + 13) = (char)(*(b + 2));
+				*(iv + 12) = (char)(*(b + 3));
 			}
 		} else {
 			memcpy(iv,
@@ -1456,10 +1471,11 @@
 					0, &pcl_info->encr_xts_key);
 		for (i = 1; i < xts_key_reg; i++)
 			qce_add_cmd_element(pdev, &ce_vaddr,
-				(CRYPTO_ENCR_KEY0_REG + i * sizeof(uint32_t)),
-				0, NULL);
+				(CRYPTO_ENCR_XTS_KEY0_REG +
+						i * sizeof(uint32_t)), 0, NULL);
 		qce_add_cmd_element(pdev, &ce_vaddr,
-				CRYPTO_ENCR_XTS_DU_SIZE_REG, 0, NULL);
+				CRYPTO_ENCR_XTS_DU_SIZE_REG, 0,
+					&pcl_info->encr_xts_du_size);
 	}
 	if (iv_reg) {
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR0_IV0_REG, 0,
@@ -1624,13 +1640,6 @@
 						0, &pcl_info->auth_seg_size);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
 						0, &pcl_info->auth_seg_size);
-	} else {
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
-						0, &pcl_info->auth_seg_size);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-						0, &pcl_info->auth_seg_size);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
-						0, &pcl_info->auth_seg_size);
 	}
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 1c904ed..d77311d 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -144,7 +144,7 @@
 #define CRYPTO_ENCR_CCM_INT_CNTR2_REG		0x1A228
 #define CRYPTO_ENCR_CCM_INT_CNTR3_REG		0x1A22C
 
-#define CRYPTO_ENCR_XTS_DU_SIZE_REG		0xA1230
+#define CRYPTO_ENCR_XTS_DU_SIZE_REG		0x1A230
 
 #define CRYPTO_AUTH_SEG_CFG_REG			0x1A300
 #define CRYPTO_AUTH_SEG_SIZE_REG		0x1A304
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 18784ac..67cb34a 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1840,7 +1840,7 @@
 		goto err;
 
 	/* now, wait for the GPU to finish its operations */
-	wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+	wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 	wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
 
 	while (time_before(jiffies, wait_time)) {
@@ -1869,18 +1869,46 @@
 	KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
 	if (KGSL_STATE_DUMP_AND_RECOVER != device->state &&
 		!adreno_dump_and_recover(device)) {
-		wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+		wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 		goto retry;
 	}
 	return -ETIMEDOUT;
 }
 
+/**
+ * is_adreno_rbbm_status_idle - Check if GPU core is idle by probing
+ * rbbm_status register
+ * @device - Pointer to the GPU device whose idle status is to be
+ * checked
+ * @returns - Returns whether the core is idle (based on rbbm_status)
+ * false if the core is active, true if the core is idle
+ */
+static bool is_adreno_rbbm_status_idle(struct kgsl_device *device)
+{
+	unsigned int reg_rbbm_status;
+	bool status = false;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	/* Is the core idle? */
+	adreno_regread(device,
+		adreno_dev->gpudev->reg_rbbm_status,
+		&reg_rbbm_status);
+
+	if (adreno_is_a2xx(adreno_dev)) {
+		if (reg_rbbm_status == 0x110)
+			status = true;
+	} else {
+		if (!(reg_rbbm_status & 0x80000000))
+			status = true;
+	}
+	return status;
+}
+
 static unsigned int adreno_isidle(struct kgsl_device *device)
 {
 	int status = false;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
-	unsigned int rbbm_status;
 
 	WARN_ON(device->state == KGSL_STATE_INIT);
 	/* If the device isn't active, don't force it on. */
@@ -1889,17 +1917,7 @@
 		GSL_RB_GET_READPTR(rb, &rb->rptr);
 		if (!device->active_cnt && (rb->rptr == rb->wptr)) {
 			/* Is the core idle? */
-			adreno_regread(device,
-				adreno_dev->gpudev->reg_rbbm_status,
-				&rbbm_status);
-
-			if (adreno_is_a2xx(adreno_dev)) {
-				if (rbbm_status == 0x110)
-					status = true;
-			} else {
-				if (!(rbbm_status & 0x80000000))
-					status = true;
-			}
+			status = is_adreno_rbbm_status_idle(device);
 		}
 	} else {
 		status = true;
@@ -2142,7 +2160,7 @@
 	if (!adreno_dev->fast_hang_detect)
 		return 0;
 
-	if (device->ftbl->isidle(device))
+	if (is_adreno_rbbm_status_idle(device))
 		return 0;
 
 	for (i = 0; i < hang_detect_regs_count; i++) {
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
index 282440c..ce74c1b 100644
--- a/drivers/gpu/msm/adreno_a2xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -224,6 +224,31 @@
 	return DEBUG_SECTION_SZ(MIUDEBUG_COUNT);
 }
 
+/* Snapshot the istore memory */
+static int a2xx_snapshot_istore(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_istore *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int count, i;
+
+	count = adreno_dev->istore_size * adreno_dev->instruction_size;
+
+	if (remain < (count * 4) + sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the istore section");
+		return 0;
+	}
+
+	header->count = adreno_dev->istore_size;
+
+	for (i = 0; i < count; i++)
+		kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);
+
+	return (count * 4) + sizeof(*header);
+}
+
 /* A2XX GPU snapshot function - this is where all of the A2XX specific
  * bits and pieces are grabbed into the snapshot memory
  */
@@ -338,6 +363,18 @@
 		}
 	}
 
+	/*
+	 * Only dump the istore on a hang - reading it on a running system
+	 * has a non zero chance of hanging the GPU.
+	 */
+
+	if (adreno_is_a2xx(adreno_dev) && hang) {
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
+			a2xx_snapshot_istore, NULL);
+	}
+
+
 	/* Reset the clock gating */
 	adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride);
 
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index a410445..e4f5733 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -220,30 +220,46 @@
 	return DEBUG_SECTION_SZ(size);
 }
 
-#define DEBUGFS_BLOCK_SIZE 0x40
+struct debugbus_block {
+	unsigned int block_id;
+	unsigned int dwords;
+};
 
 static int a3xx_snapshot_debugbus_block(struct kgsl_device *device,
 	void *snapshot, int remain, void *priv)
 {
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
 	struct kgsl_snapshot_debugbus *header = snapshot;
-	unsigned int id = (unsigned int) priv;
+	struct debugbus_block *block = priv;
 	unsigned int val;
 	int i;
 	unsigned int *data = snapshot + sizeof(*header);
-	int size =
-		(DEBUGFS_BLOCK_SIZE * sizeof(unsigned int)) + sizeof(*header);
+	unsigned int dwords;
+	int size;
+
+	/*
+	 * For A305 and A320 all debug bus regions are the same size (0x40). For
+	 * A330, they can be different sizes - most are still 0x40, but some
+	 * like CP are larger
+	 */
+
+	dwords = adreno_is_a330(adreno_dev) ?
+		block->dwords : 0x40;
+
+	size = (dwords * sizeof(unsigned int)) + sizeof(*header);
 
 	if (remain < size) {
 		SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS");
 		return 0;
 	}
 
-	val = (id << 8) | (1 << 16);
+	val = (block->block_id << 8) | (1 << 16);
 
-	header->id = id;
-	header->count = DEBUGFS_BLOCK_SIZE;
+	header->id = block->block_id;
+	header->count = dwords;
 
-	for (i = 0; i < DEBUGFS_BLOCK_SIZE; i++) {
+	for (i = 0; i < dwords; i++) {
 		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, val | i);
 		adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS,
 			&data[i]);
@@ -252,34 +268,34 @@
 	return size;
 }
 
-static unsigned int debugbus_blocks[] = {
-	RBBM_BLOCK_ID_CP,
-	RBBM_BLOCK_ID_RBBM,
-	RBBM_BLOCK_ID_VBIF,
-	RBBM_BLOCK_ID_HLSQ,
-	RBBM_BLOCK_ID_UCHE,
-	RBBM_BLOCK_ID_PC,
-	RBBM_BLOCK_ID_VFD,
-	RBBM_BLOCK_ID_VPC,
-	RBBM_BLOCK_ID_TSE,
-	RBBM_BLOCK_ID_RAS,
-	RBBM_BLOCK_ID_VSC,
-	RBBM_BLOCK_ID_SP_0,
-	RBBM_BLOCK_ID_SP_1,
-	RBBM_BLOCK_ID_SP_2,
-	RBBM_BLOCK_ID_SP_3,
-	RBBM_BLOCK_ID_TPL1_0,
-	RBBM_BLOCK_ID_TPL1_1,
-	RBBM_BLOCK_ID_TPL1_2,
-	RBBM_BLOCK_ID_TPL1_3,
-	RBBM_BLOCK_ID_RB_0,
-	RBBM_BLOCK_ID_RB_1,
-	RBBM_BLOCK_ID_RB_2,
-	RBBM_BLOCK_ID_RB_3,
-	RBBM_BLOCK_ID_MARB_0,
-	RBBM_BLOCK_ID_MARB_1,
-	RBBM_BLOCK_ID_MARB_2,
-	RBBM_BLOCK_ID_MARB_3,
+static struct debugbus_block debugbus_blocks[] = {
+	{ RBBM_BLOCK_ID_CP, 0x52, },
+	{ RBBM_BLOCK_ID_RBBM, 0x40, },
+	{ RBBM_BLOCK_ID_VBIF, 0x40, },
+	{ RBBM_BLOCK_ID_HLSQ, 0x40, },
+	{ RBBM_BLOCK_ID_UCHE, 0x40, },
+	{ RBBM_BLOCK_ID_PC, 0x40, },
+	{ RBBM_BLOCK_ID_VFD, 0x40, },
+	{ RBBM_BLOCK_ID_VPC, 0x40, },
+	{ RBBM_BLOCK_ID_TSE, 0x40, },
+	{ RBBM_BLOCK_ID_RAS, 0x40, },
+	{ RBBM_BLOCK_ID_VSC, 0x40, },
+	{ RBBM_BLOCK_ID_SP_0, 0x40, },
+	{ RBBM_BLOCK_ID_SP_1, 0x40, },
+	{ RBBM_BLOCK_ID_SP_2, 0x40, },
+	{ RBBM_BLOCK_ID_SP_3, 0x40, },
+	{ RBBM_BLOCK_ID_TPL1_0, 0x40, },
+	{ RBBM_BLOCK_ID_TPL1_1, 0x40, },
+	{ RBBM_BLOCK_ID_TPL1_2, 0x40, },
+	{ RBBM_BLOCK_ID_TPL1_3, 0x40, },
+	{ RBBM_BLOCK_ID_RB_0, 0x40, },
+	{ RBBM_BLOCK_ID_RB_1, 0x40, },
+	{ RBBM_BLOCK_ID_RB_2, 0x40, },
+	{ RBBM_BLOCK_ID_RB_3, 0x40, },
+	{ RBBM_BLOCK_ID_MARB_0, 0x40, },
+	{ RBBM_BLOCK_ID_MARB_1, 0x40, },
+	{ RBBM_BLOCK_ID_MARB_2, 0x40, },
+	{ RBBM_BLOCK_ID_MARB_3, 0x40, },
 };
 
 static void *a3xx_snapshot_debugbus(struct kgsl_device *device,
@@ -291,7 +307,7 @@
 		snapshot = kgsl_snapshot_add_section(device,
 			KGSL_SNAPSHOT_SECTION_DEBUGBUS, snapshot, remain,
 			a3xx_snapshot_debugbus_block,
-			(void *) debugbus_blocks[i]);
+			(void *) &debugbus_blocks[i]);
 	}
 
 	return snapshot;
@@ -307,6 +323,7 @@
 	struct kgsl_device *device = &adreno_dev->dev;
 	struct kgsl_snapshot_registers_list list;
 	struct kgsl_snapshot_registers regs[2];
+	int size;
 
 	regs[0].regs = (unsigned int *) a3xx_registers;
 	regs[0].count = a3xx_registers_count;
@@ -326,10 +343,14 @@
 		KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
 		kgsl_snapshot_dump_regs, &list);
 
-	/* CP_STATE_DEBUG indexed registers */
+	/*
+	 * CP_STATE_DEBUG indexed registers - 20 on 305 and 320 and 46 on A330
+	 */
+	size = adreno_is_a330(adreno_dev) ? 0x2E : 0x14;
+
 	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, REG_CP_STATE_DEBUG_INDEX,
-			REG_CP_STATE_DEBUG_DATA, 0x0, 0x14);
+			REG_CP_STATE_DEBUG_DATA, 0x0, size);
 
 	/* CP_ME indexed registers */
 	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 93be980..696073f 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -510,10 +510,28 @@
 			break;
 
 		if (pkt_is_type3(src[i])) {
-			if (adreno_cmd_is_ib(src[i]))
-				ib_add_gpu_object(device, ptbase,
-					src[i + 1], src[i + 2]);
-			else
+			if (adreno_cmd_is_ib(src[i])) {
+				unsigned int gpuaddr = src[i + 1];
+				unsigned int size = src[i + 2];
+				unsigned int ibbase;
+
+				/* Address of the last processed IB2 */
+				kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
+
+				/*
+				 * If this is the last IB2 that was executed,
+				 * then push it to make sure it goes into the
+				 * static space
+				 */
+
+				if (ibbase == gpuaddr)
+					push_object(device,
+						SNAPSHOT_OBJ_TYPE_IB, ptbase,
+						gpuaddr, size);
+				else
+					ib_add_gpu_object(device, ptbase,
+						gpuaddr, size);
+			} else
 				ib_parse_type3(device, &src[i], ptbase);
 		} else if (pkt_is_type0(src[i])) {
 			ib_parse_type0(device, &src[i], ptbase);
@@ -529,31 +547,6 @@
 	snapshot_frozen_objsize += ret;
 }
 
-/* Snapshot the istore memory */
-static int snapshot_istore(struct kgsl_device *device, void *snapshot,
-	int remain, void *priv)
-{
-	struct kgsl_snapshot_istore *header = snapshot;
-	unsigned int *data = snapshot + sizeof(*header);
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	int count, i;
-
-	count = adreno_dev->istore_size * adreno_dev->instruction_size;
-
-	if (remain < (count * 4) + sizeof(*header)) {
-		KGSL_DRV_ERR(device,
-			"snapshot: Not enough memory for the istore section");
-		return 0;
-	}
-
-	header->count = adreno_dev->istore_size;
-
-	for (i = 0; i < count; i++)
-		kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);
-
-	return (count * 4) + sizeof(*header);
-}
-
 /* Snapshot the ringbuffer memory */
 static int snapshot_rb(struct kgsl_device *device, void *snapshot,
 	int remain, void *priv)
@@ -870,17 +863,6 @@
 	for (i = 0; i < objbufptr; i++)
 		snapshot = dump_object(device, i, snapshot, remain);
 
-	/*
-	 * Only dump the istore on a hang - reading it on a running system
-	 * has a non 0 chance of hanging the GPU
-	 */
-
-	if (hang) {
-		snapshot = kgsl_snapshot_add_section(device,
-			KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
-			snapshot_istore, NULL);
-	}
-
 	/* Add GPU specific sections - registers mainly, but other stuff too */
 	if (adreno_dev->gpudev->snapshot)
 		snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7194e47..1b1f0ac 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1710,6 +1710,8 @@
 	else
 		memtype = param->memtype;
 
+	entry->memdesc.flags = param->flags;
+
 	switch (memtype) {
 	case KGSL_USER_MEM_TYPE_PMEM:
 		if (param->fd == 0 || param->len == 0)
@@ -1768,12 +1770,10 @@
 	if (result)
 		goto error;
 
-	entry->memdesc.priv |= param->flags & KGSL_MEMTYPE_MASK;
-
 	if (entry->memdesc.size >= SZ_1M)
-		entry->memdesc.priv |= ilog2(SZ_1M) << KGSL_MEMALIGN_SHIFT;
+		kgsl_memdesc_set_align(&entry->memdesc, ilog2(SZ_1M));
 	else if (entry->memdesc.size >= SZ_64K)
-		entry->memdesc.priv |= ilog2(SZ_64K) << KGSL_MEMALIGN_SHIFT;
+		kgsl_memdesc_set_align(&entry->memdesc, ilog2(SZ_64));
 
 	result = kgsl_mmu_map(private->pagetable,
 			      &entry->memdesc,
@@ -2538,6 +2538,9 @@
 	KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
 		pwr->interval_timeout);
 
+	KGSL_LOG_DUMP(device, "POWER: NAP ALLOWED = %d | START_STOP_SLEEP_WAKE = %d\n",
+		pwr->nap_allowed, pwr->strtstp_sleepwake);
+
 	KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
 				  kgsl_get_clkrate(pwr->grp_clks[0]));
 
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 56950a6..17a5b67 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -124,7 +124,10 @@
 	int (*map_kernel_mem)(struct kgsl_memdesc *);
 };
 
+/* Internal definitions for memdesc->priv */
 #define KGSL_MEMDESC_GUARD_PAGE BIT(0)
+/* Set if the memdesc is mapped into all pagetables */
+#define KGSL_MEMDESC_GLOBAL BIT(1)
 
 /* shared memory allocation */
 struct kgsl_memdesc {
@@ -134,12 +137,12 @@
 	unsigned int gpuaddr;
 	unsigned int physaddr;
 	unsigned int size;
-	unsigned int priv;
+	unsigned int priv; /* Internal flags and settings */
 	struct scatterlist *sg;
 	unsigned int sglen; /* Active entries in the sglist */
 	unsigned int sglen_alloc;  /* Allocated entries in the sglist */
 	struct kgsl_memdesc_ops *ops;
-	int flags;
+	unsigned int flags; /* Flags set from userspace */
 };
 
 /* List of different memory entry types */
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index b49c260..52097dc 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -163,6 +163,16 @@
 	return "unknown";
 }
 
+static char get_alignflag(const struct kgsl_memdesc *m)
+{
+	int align = kgsl_memdesc_get_align(m);
+	if (align >= ilog2(SZ_1M))
+		return 'L';
+	else if (align >= ilog2(SZ_64K))
+		return 'l';
+	return '-';
+}
+
 static int process_mem_print(struct seq_file *s, void *unused)
 {
 	struct kgsl_mem_entry *entry;
@@ -170,7 +180,6 @@
 	struct kgsl_process_private *private = s->private;
 	char flags[4];
 	char usage[16];
-	unsigned int align;
 
 	spin_lock(&private->mem_lock);
 	seq_printf(s, "%8s %8s %5s %10s %16s %5s\n",
@@ -181,20 +190,12 @@
 		entry = rb_entry(node, struct kgsl_mem_entry, node);
 		m = &entry->memdesc;
 
-		flags[0] = m->priv & KGSL_MEMFLAGS_GLOBAL ?  'g' : '-';
-		flags[1] = m->priv & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
-
-		align = (m->priv & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
-		if (align >= ilog2(SZ_1M))
-			flags[2] = 'L';
-		else if (align >= ilog2(SZ_64K))
-			flags[2] = 'l';
-		else
-			flags[2] = '-';
-
+		flags[0] = m->priv & KGSL_MEMDESC_GLOBAL ?  'g' : '-';
+		flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
+		flags[2] = get_alignflag(m);
 		flags[3] = '\0';
 
-		kgsl_get_memory_usage(usage, sizeof(usage), m->priv);
+		kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
 
 		seq_printf(s, "%08x %8d %5s %10s %16s %5d\n",
 			   m->gpuaddr, m->size, flags,
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 870a7d7..2003098 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -237,14 +237,16 @@
 		}
 	}
 
+	/* Set the flags for the memdesc (probably 0, unless it is cached) */
+	priv->memdesc.priv = 0;
+
 	if (TYPE_IS_PMEM(priv->type)) {
 		if (priv->type == DRM_KGSL_GEM_TYPE_EBI ||
 		    priv->type & DRM_KGSL_GEM_PMEM_EBI) {
 				result = kgsl_sharedmem_ebimem_user(
 						&priv->memdesc,
 						priv->pagetable,
-						obj->size * priv->bufcount,
-						0);
+						obj->size * priv->bufcount);
 				if (result) {
 					DRM_ERROR(
 					"Unable to allocate PMEM memory\n");
@@ -262,7 +264,7 @@
 
 		result = kgsl_sharedmem_page_alloc_user(&priv->memdesc,
 					priv->pagetable,
-					obj->size * priv->bufcount, 0);
+					obj->size * priv->bufcount);
 
 		if (result != 0) {
 				DRM_ERROR(
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 62108f2..07ea48e 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -792,13 +792,13 @@
 	if (msm_soc_version_supports_iommu_v1()) {
 		for (i = 0; i < iommu->unit_count; i++) {
 			iommu->iommu_units[i].reg_map.priv |=
-						KGSL_MEMFLAGS_GLOBAL;
+						KGSL_MEMDESC_GLOBAL;
 			status = kgsl_mmu_map(pagetable,
 				&(iommu->iommu_units[i].reg_map),
 				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
 			if (status) {
 				iommu->iommu_units[i].reg_map.priv &=
-							~KGSL_MEMFLAGS_GLOBAL;
+							~KGSL_MEMDESC_GLOBAL;
 				goto err;
 			}
 		}
@@ -808,7 +808,7 @@
 	for (i--; i >= 0; i--) {
 		kgsl_mmu_unmap(pagetable,
 				&(iommu->iommu_units[i].reg_map));
-		iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
+		iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
 	}
 	if (mmu->priv_bank_table) {
 		kgsl_mmu_putpagetable(mmu->priv_bank_table);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index dbb88ee..68cd167 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -593,7 +593,7 @@
 _get_pool(struct kgsl_pagetable *pagetable, unsigned int flags)
 {
 	if (pagetable->kgsl_pool &&
-		(KGSL_MEMFLAGS_GLOBAL & flags))
+		(KGSL_MEMDESC_GLOBAL & flags))
 		return pagetable->kgsl_pool;
 	return pagetable->pool;
 }
@@ -637,10 +637,9 @@
 	 * the address space is so small.
 	 */
 	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype() &&
-	    (memdesc->priv & KGSL_MEMALIGN_MASK)) {
-		page_align = (memdesc->priv & KGSL_MEMALIGN_MASK)
-				>> KGSL_MEMALIGN_SHIFT;
-	}
+	    kgsl_memdesc_get_align(memdesc) > 0)
+		page_align = kgsl_memdesc_get_align(memdesc);
+
 	memdesc->gpuaddr = gen_pool_alloc_aligned(pool, size, page_align);
 	if (memdesc->gpuaddr == 0) {
 		KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
@@ -719,7 +718,7 @@
 	 * Don't clear the gpuaddr on global mappings because they
 	 * may be in use by other pagetables
 	 */
-	if (!(memdesc->priv & KGSL_MEMFLAGS_GLOBAL))
+	if (!(memdesc->priv & KGSL_MEMDESC_GLOBAL))
 		memdesc->gpuaddr = 0;
 	return 0;
 }
@@ -740,8 +739,7 @@
 		return 0;
 
 	gpuaddr = memdesc->gpuaddr;
-	memdesc->priv |= KGSL_MEMFLAGS_GLOBAL
-			| (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
+	memdesc->priv |= KGSL_MEMDESC_GLOBAL;
 
 	result = kgsl_mmu_map(pagetable, memdesc, protflags);
 	if (result)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 739dcb5..422bd55 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -23,6 +23,7 @@
 #include "kgsl_pwrscale.h"
 #include "kgsl_device.h"
 #include "kgsl_trace.h"
+#include "kgsl_sharedmem.h"
 
 #define KGSL_PWRFLAGS_POWER_ON 0
 #define KGSL_PWRFLAGS_CLK_ON   1
@@ -951,6 +952,11 @@
 void kgsl_pwrctrl_wake(struct kgsl_device *device)
 {
 	int status;
+	unsigned int context_id;
+	unsigned int state = device->state;
+	unsigned int ts_processed = 0xdeaddead;
+	struct kgsl_context *context;
+
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
 	switch (device->state) {
 	case KGSL_STATE_SLUMBER:
@@ -964,6 +970,17 @@
 	case KGSL_STATE_SLEEP:
 		kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
 		kgsl_pwrscale_wake(device);
+		kgsl_sharedmem_readl(&device->memstore,
+			(unsigned int *) &context_id,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+				current_context));
+		context = idr_find(&device->context_idr, context_id);
+		if (context)
+			ts_processed = kgsl_readtimestamp(device, context,
+				KGSL_TIMESTAMP_RETIRED);
+		KGSL_PWR_INFO(device, "Wake from %s state. CTXT: %d RTRD TS: %08X\n",
+			kgsl_pwrstate_to_str(state),
+			context ? context->id : -1, ts_processed);
 		/* fall through */
 	case KGSL_STATE_NAP:
 		/* Turn on the core clocks */
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 53dc468..a70647a 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -367,7 +367,7 @@
 	int sglen = memdesc->sglen;
 
 	/* Don't free the guard page if it was used */
-	if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+	if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
 		sglen--;
 
 	kgsl_driver.stats.page_alloc -= memdesc->size;
@@ -405,7 +405,7 @@
 		int i, count = 0;
 
 		/* Don't map the guard page if it exists */
-		if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+		if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
 			sglen--;
 
 		/* create a list of pages to call vmap */
@@ -534,7 +534,7 @@
 static int
 _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
 			struct kgsl_pagetable *pagetable,
-			size_t size, unsigned int flags, unsigned int protflags)
+			size_t size, unsigned int protflags)
 {
 	int pcount = 0, order, ret = 0;
 	int j, len, page_size, sglen_alloc, sglen = 0;
@@ -562,10 +562,12 @@
 	if (size >= ((si.freeram << PAGE_SHIFT) - SZ_32M))
 		return -ENOMEM;
 
-	align = (flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+	align = (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
 
 	page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K)
 			? SZ_64K : PAGE_SIZE;
+	/* update align flags for what we actually use */
+	kgsl_memdesc_set_align(memdesc, ilog2(page_size));
 
 	/*
 	 * There needs to be enough room in the sg structure to be able to
@@ -584,7 +586,6 @@
 
 	memdesc->size = size;
 	memdesc->pagetable = pagetable;
-	memdesc->priv |= (flags & KGSL_MEMALIGN_MASK);
 	memdesc->ops = &kgsl_page_alloc_ops;
 
 	memdesc->sg = kgsl_sg_alloc(sglen_alloc);
@@ -664,7 +665,7 @@
 		if (kgsl_guard_page != NULL) {
 			sg_set_page(&memdesc->sg[sglen++], kgsl_guard_page,
 				PAGE_SIZE, 0);
-			memdesc->flags |= KGSL_MEMDESC_GUARD_PAGE;
+			memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE;
 		}
 	}
 
@@ -741,7 +742,7 @@
 	size = ALIGN(size, PAGE_SIZE * 2);
 
 	ret =  _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
-		0, GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+		GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
 	if (!ret)
 		ret = kgsl_page_alloc_map_kernel(memdesc);
 	if (ret)
@@ -753,7 +754,7 @@
 int
 kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc,
 			    struct kgsl_pagetable *pagetable,
-			    size_t size, int flags)
+			    size_t size)
 {
 	unsigned int protflags;
 
@@ -761,11 +762,11 @@
 		return -EINVAL;
 
 	protflags = GSL_PT_PAGE_RV;
-	if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
+	if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
 		protflags |= GSL_PT_PAGE_WV;
 
 	return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
-		flags, protflags);
+		protflags);
 }
 EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user);
 
@@ -862,7 +863,7 @@
 int
 kgsl_sharedmem_ebimem_user(struct kgsl_memdesc *memdesc,
 			struct kgsl_pagetable *pagetable,
-			size_t size, int flags)
+			size_t size)
 {
 	size = ALIGN(size, PAGE_SIZE);
 	return _kgsl_sharedmem_ebimem(memdesc, pagetable, size);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 5a6c4c2..92a6f27 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -20,6 +20,8 @@
 #include <linux/slab.h>
 #include <linux/kmemleak.h>
 
+#include "kgsl_log.h"
+
 struct kgsl_device;
 struct kgsl_process_private;
 
@@ -27,9 +29,6 @@
 #define KGSL_CACHE_OP_FLUSH     0x02
 #define KGSL_CACHE_OP_CLEAN     0x03
 
-/** Set if the memdesc is mapped into all pagetables */
-#define KGSL_MEMFLAGS_GLOBAL    0x00000002
-
 extern struct kgsl_memdesc_ops kgsl_page_alloc_ops;
 
 int kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
@@ -37,13 +36,13 @@
 
 int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc,
 				struct kgsl_pagetable *pagetable,
-				size_t size, int flags);
+				size_t size);
 
 int kgsl_sharedmem_alloc_coherent(struct kgsl_memdesc *memdesc, size_t size);
 
 int kgsl_sharedmem_ebimem_user(struct kgsl_memdesc *memdesc,
 			     struct kgsl_pagetable *pagetable,
-			     size_t size, int flags);
+			     size_t size);
 
 int kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc,
 			struct kgsl_pagetable *pagetable,
@@ -71,6 +70,36 @@
 int kgsl_sharedmem_init_sysfs(void);
 void kgsl_sharedmem_uninit_sysfs(void);
 
+/*
+ * kgsl_memdesc_get_align - Get alignment flags from a memdesc
+ * @memdesc - the memdesc
+ *
+ * Returns the alignment requested, as power of 2 exponent.
+ */
+static inline int
+kgsl_memdesc_get_align(const struct kgsl_memdesc *memdesc)
+{
+	return (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+}
+
+/*
+ * kgsl_memdesc_set_align - Set alignment flags of a memdesc
+ * @memdesc - the memdesc
+ * @align - alignment requested, as a power of 2 exponent.
+ */
+static inline int
+kgsl_memdesc_set_align(struct kgsl_memdesc *memdesc, unsigned int align)
+{
+	if (align > 32) {
+		KGSL_CORE_ERR("Alignment too big, restricting to 2^32\n");
+		align = 32;
+	}
+
+	memdesc->flags &= ~KGSL_MEMALIGN_MASK;
+	memdesc->flags |= (align << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
+	return 0;
+}
+
 static inline unsigned int kgsl_get_sg_pa(struct scatterlist *sg)
 {
 	/*
@@ -134,7 +163,7 @@
 {
 	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
 		return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
-	memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
+	memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
 	return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
 }
 
@@ -144,15 +173,14 @@
 		size_t size, unsigned int flags)
 {
 	int ret;
-	unsigned int mask = (KGSL_MEMTYPE_MASK | KGSL_MEMFLAGS_GPUREADONLY);
+
+	memdesc->flags = flags;
+
 	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
-		ret = kgsl_sharedmem_ebimem_user(memdesc, pagetable, size,
-						  flags);
+		ret = kgsl_sharedmem_ebimem_user(memdesc, pagetable, size);
 	else
-		ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size,
-							flags);
-	if (ret == 0)
-		memdesc->priv |= flags & mask;
+		ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size);
+
 	return ret;
 }
 
@@ -162,6 +190,8 @@
 	int ret  = kgsl_sharedmem_alloc_coherent(memdesc, size);
 	if (!ret && (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE))
 		memdesc->gpuaddr = memdesc->physaddr;
+
+	memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
 	return ret;
 }
 
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 81cb34f..0b247e5 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -324,7 +324,7 @@
 		__entry->size = mem_entry->memdesc.size;
 		__entry->tgid = mem_entry->priv->pid;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
-				     mem_entry->memdesc.priv);
+				     mem_entry->memdesc.flags);
 	),
 
 	TP_printk(
@@ -356,7 +356,7 @@
 		__entry->type = mem_entry->memtype;
 		__entry->tgid = mem_entry->priv->pid;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
-				     mem_entry->memdesc.priv);
+				     mem_entry->memdesc.flags);
 	),
 
 	TP_printk(
@@ -388,7 +388,7 @@
 		__entry->type = mem_entry->memtype;
 		__entry->tgid = mem_entry->priv->pid;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
-				     mem_entry->memdesc.priv);
+				     mem_entry->memdesc.flags);
 	),
 
 	TP_printk(
@@ -421,7 +421,7 @@
 		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
 		__entry->size = mem_entry->memdesc.size;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
-				     mem_entry->memdesc.priv);
+				     mem_entry->memdesc.flags);
 		__entry->drawctxt_id = id;
 		__entry->type = mem_entry->memtype;
 		__entry->curr_ts = curr_ts;
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 886113f..7ceb017 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -403,6 +403,8 @@
 		goto err_invalid_core;
 	}
 
+	pr_info(VIDC_DBG_TAG "Opening video instance: %p, %d\n",
+		VIDC_INFO, inst, session_type);
 	mutex_init(&inst->sync_lock);
 	mutex_init(&inst->bufq[CAPTURE_PORT].lock);
 	mutex_init(&inst->bufq[OUTPUT_PORT].lock);
@@ -545,7 +547,7 @@
 		dprintk(VIDC_ERR,
 			"Failed to move video instance to uninit state\n");
 	cleanup_instance(inst);
+	pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
 	kfree(inst);
-	dprintk(VIDC_DBG, "Closed the instance\n");
 	return 0;
 }
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index c7637b6..f3c9362 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -439,11 +439,10 @@
 			vc_format->mode << 10,
 			VCAP_VC_CTRL);
 
-	writel_relaxed(vc_format->h_polar << 4 |
+	writel_relaxed(vc_format->d_polar << 8 |
+			vc_format->h_polar << 4 |
 			vc_format->v_polar << 0, VCAP_VC_POLARITY);
 
-	writel_relaxed(vc_format->h_polar << 4 |
-			vc_format->v_polar << 0, VCAP_VC_POLARITY);
 	writel_relaxed(((vc_format->htotal << 16) | vc_format->vtotal),
 			VCAP_VC_V_H_TOTAL);
 	writel_relaxed(((vc_format->hactive_end << 16) |
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 7d3ac83..2307d7a 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -20,6 +20,7 @@
 #include <linux/mmc/host.h>
 #include <linux/delay.h>
 #include <linux/test-iosched.h>
+#include <linux/jiffies.h>
 #include "queue.h"
 #include <linux/mmc/mmc.h>
 
@@ -36,6 +37,28 @@
 #define SECTOR_SIZE 512
 #define NUM_OF_SECTORS_PER_BIO		((BIO_U32_SIZE * 4) / SECTOR_SIZE)
 #define BIO_TO_SECTOR(x)		(x * NUM_OF_SECTORS_PER_BIO)
+/* the desired long test size to be written or read */
+#define LONG_TEST_MAX_NUM_BYTES (50*1024*1024) /* 50MB */
+/* request queue limitation is 128 requests, and we leave 10 spare requests */
+#define TEST_MAX_REQUESTS 118
+#define LONG_TEST_MAX_NUM_REQS	(LONG_TEST_MAX_NUM_BYTES / \
+		(TEST_MAX_BIOS_PER_REQ * sizeof(int) * BIO_U32_SIZE))
+/* this doesn't allow the test requests num to be greater than the maximum */
+#define LONG_TEST_ACTUAL_NUM_REQS  \
+			((TEST_MAX_REQUESTS < LONG_TEST_MAX_NUM_REQS) ? \
+				TEST_MAX_REQUESTS : LONG_TEST_MAX_NUM_REQS)
+#define MB_MSEC_RATIO_APPROXIMATION ((1024 * 1024) / 1000)
+/* actual number of bytes in test */
+#define LONG_TEST_ACTUAL_BYTE_NUM  (LONG_TEST_ACTUAL_NUM_REQS *  \
+			(TEST_MAX_BIOS_PER_REQ * sizeof(int) * BIO_U32_SIZE))
+/* actual number of MiB in test multiplied by 10, for single digit precision*/
+#define LONG_TEST_ACTUAL_MB_NUM_X_10 ((LONG_TEST_ACTUAL_BYTE_NUM * 10) / \
+					(1024 * 1024))
+/* extract integer value */
+#define LONG_TEST_SIZE_INTEGER (LONG_TEST_ACTUAL_MB_NUM_X_10 / 10)
+/* and calculate the MiB value fraction */
+#define LONG_TEST_SIZE_FRACTION (LONG_TEST_ACTUAL_MB_NUM_X_10 - \
+		(LONG_TEST_SIZE_INTEGER * 10))
 
 #define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
 #define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
@@ -127,6 +150,9 @@
 	BKOPS_URGENT_LEVEL_2_TWO_REQS,
 	BKOPS_URGENT_LEVEL_3,
 	BKOPS_MAX_TESTCASE = BKOPS_URGENT_LEVEL_3,
+
+	TEST_LONG_SEQUENTIAL_READ,
+	TEST_LONG_SEQUENTIAL_WRITE,
 };
 
 enum mmc_block_test_group {
@@ -154,6 +180,8 @@
 	struct dentry *packing_control_test;
 	struct dentry *discard_sanitize_test;
 	struct dentry *bkops_test;
+	struct dentry *long_sequential_read_test;
+	struct dentry *long_sequential_write_test;
 };
 
 struct mmc_block_test_data {
@@ -562,6 +590,10 @@
 		return "\nTest urgent BKOPS level 2, followed by a request";
 	case BKOPS_URGENT_LEVEL_3:
 		return "\nTest urgent BKOPS level 3";
+	case TEST_LONG_SEQUENTIAL_READ:
+		return "Test long sequential read";
+	case TEST_LONG_SEQUENTIAL_WRITE:
+		return "Test long sequential write";
 	default:
 		 return "Unknown testcase";
 	}
@@ -818,8 +850,10 @@
 	test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
 		     num_requests, td->wr_rd_next_req_id);
 
-	for (i = 1; i <= num_requests; i++) {
-		start_sec = td->start_sector + 4096 * td->num_of_write_bios;
+	for (i = 1 ; i <= num_requests ; i++) {
+		start_sec =
+			td->start_sector + sizeof(int) *
+			BIO_U32_SIZE * td->num_of_write_bios;
 		if (is_random)
 			pseudo_rnd_num_of_bios(bio_seed, &num_bios);
 		else
@@ -1139,7 +1173,8 @@
 		if (i > (num_requests / 2))
 			is_err_expected = 1;
 
-		start_address = td->start_sector + 4096 * td->num_of_write_bios;
+		start_address = td->start_sector +
+			sizeof(int) * BIO_U32_SIZE * td->num_of_write_bios;
 		ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
 				start_address, (i % 5) + 1, TEST_PATTERN_5A,
 				NULL);
@@ -1243,6 +1278,48 @@
 	return num_requests;
 }
 
+static int prepare_long_test_requests(struct test_data *td)
+{
+
+	int ret;
+	int start_sec;
+	int j;
+	int test_direction;
+
+	if (td)
+		start_sec = td->start_sector;
+	else {
+		test_pr_err("%s: NULL td\n", __func__);
+		return -EINVAL;
+	}
+
+	if (td->test_info.testcase == TEST_LONG_SEQUENTIAL_WRITE)
+		test_direction = WRITE;
+	else
+		test_direction = READ;
+
+	test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
+		     LONG_TEST_ACTUAL_NUM_REQS, td->wr_rd_next_req_id);
+
+	for (j = 0; j < LONG_TEST_ACTUAL_NUM_REQS; j++) {
+
+		ret = test_iosched_add_wr_rd_test_req(0, test_direction,
+						start_sec,
+						TEST_MAX_BIOS_PER_REQ,
+						TEST_NO_PATTERN, NULL);
+		if (ret) {
+			test_pr_err("%s: failed to add a bio request",
+				     __func__);
+			return ret;
+		}
+
+		start_sec +=
+			(TEST_MAX_BIOS_PER_REQ * sizeof(int) * BIO_U32_SIZE);
+	}
+
+	return 0;
+}
+
 /*
  * An implementation for the prepare_test_fn pointer in the test_info
  * data structure. According to the testcase we add the right number of requests
@@ -1351,9 +1428,15 @@
 		ret = prepare_packed_control_tests_requests(td, 0,
 			test_packed_trigger, is_random);
 		break;
+	case TEST_LONG_SEQUENTIAL_WRITE:
+		ret = prepare_long_test_requests(td);
+		break;
+	case TEST_LONG_SEQUENTIAL_READ:
+		ret = prepare_long_test_requests(td);
+		break;
 	default:
 		test_pr_info("%s: Invalid test case...", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
 	}
 
 	return ret;
@@ -2430,6 +2513,185 @@
 	.read = bkops_test_read,
 };
 
+static ssize_t long_sequential_read_test_write(struct file *file,
+				const char __user *buf,
+				size_t count,
+				loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+	unsigned int mtime, integer, fraction;
+
+	test_pr_info("%s: -- Long Sequential Read TEST --", __func__);
+
+	sscanf(buf, "%d", &number);
+
+	if (number <= 0)
+		number = 1;
+
+	memset(&mbtd->test_info, 0, sizeof(struct test_info));
+	mbtd->test_group = TEST_GENERAL_GROUP;
+
+	mbtd->test_info.data = mbtd;
+	mbtd->test_info.prepare_test_fn = prepare_test;
+	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
+
+	for (i = 0 ; i < number ; ++i) {
+		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
+		test_pr_info("%s: ====================", __func__);
+
+		mbtd->test_info.testcase = TEST_LONG_SEQUENTIAL_READ;
+		mbtd->is_random = NON_RANDOM_TEST;
+		ret = test_iosched_start_test(&mbtd->test_info);
+		if (ret)
+			break;
+
+		mtime = jiffies_to_msecs(mbtd->test_info.test_duration);
+
+		test_pr_info("%s: time is %u msec, size is %u.%u MiB",
+			__func__, mtime, LONG_TEST_SIZE_INTEGER,
+			      LONG_TEST_SIZE_FRACTION);
+
+		/* we first multiply in order not to lose precision */
+		mtime *= MB_MSEC_RATIO_APPROXIMATION;
+		/* divide values to get a MiB/sec integer value with one
+		   digit of precision. Multiply by 10 for one digit precision
+		 */
+		fraction = integer = (LONG_TEST_ACTUAL_BYTE_NUM * 10) / mtime;
+		integer /= 10;
+		/* and calculate the MiB value fraction */
+		fraction -= integer * 10;
+
+		test_pr_info("%s: Throughput: %u.%u MiB/sec\n"
+			, __func__, integer, fraction);
+
+		/* Allow FS requests to be dispatched */
+		msleep(1000);
+	}
+
+	return count;
+}
+
+static ssize_t long_sequential_read_test_read(struct file *file,
+			       char __user *buffer,
+			       size_t count,
+			       loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nlong_sequential_read_test\n"
+		 "=========\n"
+		 "Description:\n"
+		 "This test runs the following scenarios\n"
+		 "- Long Sequential Read Test: this test measures read "
+		 "throughput at the driver level by sequentially reading many "
+		 "large requests.\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else
+		return 0;
+}
+
+const struct file_operations long_sequential_read_test_ops = {
+	.open = test_open,
+	.write = long_sequential_read_test_write,
+	.read = long_sequential_read_test_read,
+};
+
+static ssize_t long_sequential_write_test_write(struct file *file,
+				const char __user *buf,
+				size_t count,
+				loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+	unsigned int mtime, integer, fraction;
+
+	test_pr_info("%s: -- Long Sequential Write TEST --", __func__);
+
+	sscanf(buf, "%d", &number);
+
+	if (number <= 0)
+		number = 1;
+
+	memset(&mbtd->test_info, 0, sizeof(struct test_info));
+	mbtd->test_group = TEST_GENERAL_GROUP;
+
+	mbtd->test_info.data = mbtd;
+	mbtd->test_info.prepare_test_fn = prepare_test;
+	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
+
+	for (i = 0 ; i < number ; ++i) {
+		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
+		test_pr_info("%s: ====================", __func__);
+
+		mbtd->test_info.testcase = TEST_LONG_SEQUENTIAL_WRITE;
+		mbtd->is_random = NON_RANDOM_TEST;
+		ret = test_iosched_start_test(&mbtd->test_info);
+		if (ret)
+			break;
+
+		mtime = jiffies_to_msecs(mbtd->test_info.test_duration);
+
+		test_pr_info("%s: time is %u msec, size is %u.%u MiB",
+			__func__, mtime, LONG_TEST_SIZE_INTEGER,
+			      LONG_TEST_SIZE_FRACTION);
+
+		/* we first multiply in order not to lose precision */
+		mtime *= MB_MSEC_RATIO_APPROXIMATION;
+		/* divide values to get a MiB/sec integer value with one
+		   digit of precision
+		 */
+		fraction = integer = (LONG_TEST_ACTUAL_BYTE_NUM * 10) / mtime;
+		integer /= 10;
+		/* and calculate the MiB value fraction */
+		fraction -= integer * 10;
+
+		test_pr_info("%s: Throughput: %u.%u MiB/sec\n",
+			__func__, integer, fraction);
+
+		/* Allow FS requests to be dispatched */
+		msleep(1000);
+	}
+
+	return count;
+}
+
+static ssize_t long_sequential_write_test_read(struct file *file,
+			       char __user *buffer,
+			       size_t count,
+			       loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nlong_sequential_write_test\n"
+		 "=========\n"
+		 "Description:\n"
+		 "This test runs the following scenarios\n"
+		 "- Long Sequential Write Test: this test measures write "
+		 "throughput at the driver level by sequentially writing many "
+		 "large requests\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else
+		return 0;
+}
+
+const struct file_operations long_sequential_write_test_ops = {
+	.open = test_open,
+	.write = long_sequential_write_test_write,
+	.read = long_sequential_write_test_read,
+};
+
+
 static void mmc_block_test_debugfs_cleanup(void)
 {
 	debugfs_remove(mbtd->debug.random_test_seed);
@@ -2439,6 +2701,8 @@
 	debugfs_remove(mbtd->debug.packing_control_test);
 	debugfs_remove(mbtd->debug.discard_sanitize_test);
 	debugfs_remove(mbtd->debug.bkops_test);
+	debugfs_remove(mbtd->debug.long_sequential_read_test);
+	debugfs_remove(mbtd->debug.long_sequential_write_test);
 }
 
 static int mmc_block_test_debugfs_init(void)
@@ -2521,6 +2785,26 @@
 	if (!mbtd->debug.bkops_test)
 		goto err_nomem;
 
+	mbtd->debug.long_sequential_read_test = debugfs_create_file(
+					"long_sequential_read_test",
+					S_IRUGO | S_IWUGO,
+					tests_root,
+					NULL,
+					&long_sequential_read_test_ops);
+
+	if (!mbtd->debug.long_sequential_read_test)
+		goto err_nomem;
+
+	mbtd->debug.long_sequential_write_test = debugfs_create_file(
+					"long_sequential_write_test",
+					S_IRUGO | S_IWUGO,
+					tests_root,
+					NULL,
+					&long_sequential_write_test_ops);
+
+	if (!mbtd->debug.long_sequential_write_test)
+		goto err_nomem;
+
 	return 0;
 
 err_nomem:
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 2fbd804..72f4a5c 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3197,8 +3197,21 @@
 		/*
 		 * For DDR50 mode, controller needs clock rate to be
 		 * double than what is required on the SD card CLK pin.
+		 *
+		 * Setting DDR timing mode in controller before setting the
+		 * clock rate will make sure that card don't see the double
+		 * clock rate even for very small duration. Some eMMC
+		 * cards seems to lock up if they see clock frequency > 52MHz.
 		 */
 		if (ios->timing == MMC_TIMING_UHS_DDR50) {
+			u32 clk;
+
+			clk = readl_relaxed(host->base + MMCICLOCK);
+			clk &= ~(0x7 << 14); /* clear SELECT_IN field */
+			clk |= (3 << 14); /* set DDR timing mode */
+			writel_relaxed(clk, host->base + MMCICLOCK);
+			msmsdcc_sync_reg_wr(host);
+
 			/*
 			 * Make sure that we don't double the clock if
 			 * doubled clock rate is already set
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 376750f..7b7e05e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -343,6 +343,18 @@
 	  SMB349 be operated as a slave device via the power supply
 	  framework.
 
+config SMB350_CHARGER
+	tristate "smb350 charger"
+	depends on I2C
+	help
+	  Say Y to enable battery charging by SMB350 switching mode based
+	  external charger. The device supports stack-cell battery charging.
+	  The driver configures the device volatile parameters
+	  and the charger device works autonomously.
+	  The driver supports charger-enable and charger-suspend/resume.
+	  The driver reports the charger status via the power supply framework.
+	  A charger status change triggers an IRQ via the device STAT pin.
+
 config BATTERY_MSM_FAKE
 	tristate "Fake MSM battery"
 	depends on ARCH_MSM && BATTERY_MSM
@@ -388,6 +400,18 @@
 	help
 	  Say Y here to enable Test sysfs Interface for BQ27520 Drivers.
 
+config BATTERY_BQ28400
+	tristate "BQ28400 battery driver"
+	depends on I2C
+	default n
+	help
+	  Say Y here to enable support for batteries with BQ28400 (I2C) chips.
+	  The bq28400 Texas Instruments Inc device monitors the battery
+	  charging/discharging status via Rsens resistor, typically 10 mohm.
+	  It monitors the battery temperature via Thermistor.
+	  The device monitors the battery level (Relative-State-Of-Charge).
+	  The device is SBS compliant, providing battery info over I2C.
+
 config PM8921_CHARGER
 	tristate "PM8921 Charger driver"
 	depends on MFD_PM8921_CORE
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 3521cfd..3e74f35 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -48,10 +48,12 @@
 obj-$(CONFIG_PM8058_CHARGER)    += pmic8058-charger.o
 obj-$(CONFIG_ISL9519_CHARGER)   += isl9519q.o
 obj-$(CONFIG_SMB349_CHARGER)   += smb349.o
+obj-$(CONFIG_SMB350_CHARGER)   += smb350_charger.o
 obj-$(CONFIG_PM8058_FIX_USB)    += pm8058_usb_fix.o
 obj-$(CONFIG_BATTERY_QCIBAT)    += qci_battery.o
 obj-$(CONFIG_BATTERY_BQ27520)	+= bq27520_fuelgauger.o
 obj-$(CONFIG_BATTERY_BQ27541)	+= bq27541_fuelgauger.o
+obj-$(CONFIG_BATTERY_BQ28400)	+= bq28400_battery.o
 obj-$(CONFIG_SMB137B_CHARGER)   += smb137b.o
 obj-$(CONFIG_PM8XXX_CCADC)	+= pm8xxx-ccadc.o
 obj-$(CONFIG_PM8921_BMS)	+= pm8921-bms.o
diff --git a/drivers/power/bq28400_battery.c b/drivers/power/bq28400_battery.c
new file mode 100644
index 0000000..39d52cb
--- /dev/null
+++ b/drivers/power/bq28400_battery.c
@@ -0,0 +1,917 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * High Level description:
+ * http://www.ti.com/lit/ds/symlink/bq28400.pdf
+ * Thechnical Reference:
+ * http://www.ti.com/lit/ug/sluu431/sluu431.pdf
+ */
+
+#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/power_supply.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/printk.h>
+
+#define BQ28400_NAME "bq28400"
+#define BQ28400_REV  "1.0"
+
+/* SBS Commands (page 63)  */
+
+#define SBS_MANUFACTURER_ACCESS		0x00
+#define SBS_BATTERY_MODE		0x03
+#define SBS_TEMPERATURE			0x08
+#define SBS_VOLTAGE			0x09
+#define SBS_CURRENT			0x0A
+#define SBS_AVG_CURRENT			0x0B
+#define SBS_MAX_ERROR			0x0C
+#define SBS_RSOC			0x0D	/* Relative State Of Charge */
+#define SBS_REMAIN_CAPACITY		0x0F
+#define SBS_FULL_CAPACITY		0x10
+#define SBS_CHG_CURRENT			0x14
+#define SBS_CHG_VOLTAGE			0x15
+#define SBS_BATTERY_STATUS		0x16
+#define SBS_CYCLE_COUNT			0x17
+#define SBS_DESIGN_CAPACITY		0x18
+#define SBS_DESIGN_VOLTAGE		0x19
+#define SBS_SPEC_INFO			0x1A
+#define SBS_MANUFACTURE_DATE		0x1B
+#define SBS_SERIAL_NUMBER		0x1C
+#define SBS_MANUFACTURER_NAME		0x20
+#define SBS_DEVICE_NAME			0x21
+#define SBS_DEVICE_CHEMISTRY		0x22
+#define SBS_MANUFACTURER_DATA		0x23
+#define SBS_AUTHENTICATE		0x2F
+#define SBS_CELL_VOLTAGE1		0x3E
+#define SBS_CELL_VOLTAGE2		0x3F
+
+/* Extended SBS Commands (page 71)  */
+
+#define SBS_FET_CONTROL			0x46
+#define SBS_SAFETY_ALERT		0x50
+#define SBS_SAFETY_STATUS		0x51
+#define SBS_PE_ALERT			0x52
+#define SBS_PE_STATUS			0x53
+#define SBS_OPERATION_STATUS		0x54
+#define SBS_CHARGING_STATUS		0x55
+#define SBS_FET_STATUS			0x56
+#define SBS_PACK_VOLTAGE		0x5A
+#define SBS_TS0_TEMPERATURE		0x5E
+#define SBS_FULL_ACCESS_KEY		0x61
+#define SBS_PF_KEY			0x62
+#define SBS_AUTH_KEY3			0x63
+#define SBS_AUTH_KEY2			0x64
+#define SBS_AUTH_KEY1			0x65
+#define SBS_AUTH_KEY0			0x66
+#define SBS_MANUFACTURER_INFO		0x70
+#define SBS_SENSE_RESISTOR		0x71
+#define SBS_TEMP_RANGE			0x72
+
+/* SBS Sub-Commands (16 bits) */
+/* SBS_MANUFACTURER_ACCESS CMD */
+#define SUBCMD_DEVICE_TYPE		0x01
+#define SUBCMD_FIRMWARE_VERSION		0x02
+#define SUBCMD_HARDWARE_VERSION		0x03
+#define SUBCMD_DF_CHECKSUM		0x04
+#define SUBCMD_EDV			0x05
+#define SUBCMD_CHEMISTRY_ID		0x08
+
+/* SBS_CHARGING_STATUS */
+#define CHG_STATUS_BATTERY_DEPLETED	BIT(0)
+#define CHG_STATUS_OVERCHARGE		BIT(1)
+#define CHG_STATUS_OVERCHARGE_CURRENT	BIT(2)
+#define CHG_STATUS_OVERCHARGE_VOLTAGE	BIT(3)
+#define CHG_STATUS_CELL_BALANCING	BIT(6)
+#define CHG_STATUS_HOT_TEMP_CHARGING	BIT(8)
+#define CHG_STATUS_STD1_TEMP_CHARGING	BIT(9)
+#define CHG_STATUS_STD2_TEMP_CHARGING	BIT(10)
+#define CHG_STATUS_LOW_TEMP_CHARGING	BIT(11)
+#define CHG_STATUS_PRECHARGING_EXIT	BIT(13)
+#define CHG_STATUS_SUSPENDED		BIT(14)
+#define CHG_STATUS_DISABLED		BIT(15)
+
+/* SBS_FET_STATUS */
+#define FET_STATUS_DISCHARGE		BIT(1)
+#define FET_STATUS_CHARGE		BIT(2)
+#define FET_STATUS_PRECHARGE		BIT(3)
+
+/* SBS_BATTERY_STATUS */
+#define BAT_STATUS_SBS_ERROR		0x0F
+#define BAT_STATUS_EMPTY		BIT(4)
+#define BAT_STATUS_FULL			BIT(5)
+#define BAT_STATUS_DISCHARGING		BIT(6)
+#define BAT_STATUS_OVER_TEMPERATURE	BIT(12)
+#define BAT_STATUS_OVER_CHARGED		BIT(15)
+
+#define ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN   (-2731)
+#define BQ_TERMINATION_CURRENT_MA	200
+
+#define BQ_MAX_STR_LEN	32
+
+struct bq28400_device {
+	struct i2c_client	*client;
+	struct delayed_work	periodic_user_space_update_work;
+	struct dentry		*dent;
+	struct power_supply	batt_psy;
+	struct power_supply	*dc_psy;
+	bool			is_charging_enabled;
+};
+
+static struct bq28400_device *bq28400_dev;
+
+static enum power_supply_property pm_power_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+struct debug_reg {
+	char	*name;
+	u8	reg;
+	u16	subcmd;
+};
+
+#define BQ28400_DEBUG_REG(x) {#x, SBS_##x, 0}
+#define BQ28400_DEBUG_SUBREG(x, y) {#y, SBS_##x, SUBCMD_##y}
+
+/* Note: Some register can be read only in Unsealed mode */
+static struct debug_reg bq28400_debug_regs[] = {
+	BQ28400_DEBUG_REG(MANUFACTURER_ACCESS),
+	BQ28400_DEBUG_REG(BATTERY_MODE),
+	BQ28400_DEBUG_REG(TEMPERATURE),
+	BQ28400_DEBUG_REG(VOLTAGE),
+	BQ28400_DEBUG_REG(CURRENT),
+	BQ28400_DEBUG_REG(AVG_CURRENT),
+	BQ28400_DEBUG_REG(MAX_ERROR),
+	BQ28400_DEBUG_REG(RSOC),
+	BQ28400_DEBUG_REG(REMAIN_CAPACITY),
+	BQ28400_DEBUG_REG(FULL_CAPACITY),
+	BQ28400_DEBUG_REG(CHG_CURRENT),
+	BQ28400_DEBUG_REG(CHG_VOLTAGE),
+	BQ28400_DEBUG_REG(BATTERY_STATUS),
+	BQ28400_DEBUG_REG(CYCLE_COUNT),
+	BQ28400_DEBUG_REG(DESIGN_CAPACITY),
+	BQ28400_DEBUG_REG(DESIGN_VOLTAGE),
+	BQ28400_DEBUG_REG(SPEC_INFO),
+	BQ28400_DEBUG_REG(MANUFACTURE_DATE),
+	BQ28400_DEBUG_REG(SERIAL_NUMBER),
+	BQ28400_DEBUG_REG(MANUFACTURER_NAME),
+	BQ28400_DEBUG_REG(DEVICE_NAME),
+	BQ28400_DEBUG_REG(DEVICE_CHEMISTRY),
+	BQ28400_DEBUG_REG(MANUFACTURER_DATA),
+	BQ28400_DEBUG_REG(AUTHENTICATE),
+	BQ28400_DEBUG_REG(CELL_VOLTAGE1),
+	BQ28400_DEBUG_REG(CELL_VOLTAGE2),
+	BQ28400_DEBUG_REG(SAFETY_ALERT),
+	BQ28400_DEBUG_REG(SAFETY_STATUS),
+	BQ28400_DEBUG_REG(PE_ALERT),
+	BQ28400_DEBUG_REG(PE_STATUS),
+	BQ28400_DEBUG_REG(OPERATION_STATUS),
+	BQ28400_DEBUG_REG(CHARGING_STATUS),
+	BQ28400_DEBUG_REG(FET_STATUS),
+	BQ28400_DEBUG_REG(FULL_ACCESS_KEY),
+	BQ28400_DEBUG_REG(PF_KEY),
+	BQ28400_DEBUG_REG(MANUFACTURER_INFO),
+	BQ28400_DEBUG_REG(SENSE_RESISTOR),
+	BQ28400_DEBUG_REG(TEMP_RANGE),
+	BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, DEVICE_TYPE),
+	BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, FIRMWARE_VERSION),
+	BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, HARDWARE_VERSION),
+	BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, DF_CHECKSUM),
+	BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, EDV),
+	BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, CHEMISTRY_ID),
+};
+
+static int bq28400_read_reg(struct i2c_client *client, u8 reg)
+{
+	int val;
+
+	val = i2c_smbus_read_word_data(client, reg);
+	if (val < 0)
+		pr_err("i2c read fail. reg = 0x%x.ret = %d.\n", reg, val);
+	else
+		pr_debug("reg = 0x%02X.val = 0x%04X.\n", reg , val);
+
+	return val;
+}
+
+static int bq28400_write_reg(struct i2c_client *client, u8 reg, u16 val)
+{
+	int ret;
+
+	ret = i2c_smbus_write_word_data(client, reg, val);
+	if (ret < 0)
+		pr_err("i2c read fail. reg = 0x%x.val = 0x%x.ret = %d.\n",
+		       reg, val, ret);
+	else
+		pr_debug("reg = 0x%02X.val = 0x%02X.\n", reg , val);
+
+	return ret;
+}
+
+static int bq28400_read_subcmd(struct i2c_client *client, u8 reg, u16 subcmd)
+{
+	int ret;
+	u8 buf[4];
+	u16 val = 0;
+
+	buf[0] = reg;
+	buf[1] = subcmd & 0xFF;
+	buf[2] = (subcmd >> 8) & 0xFF;
+
+	/* Control sub-command */
+	ret = i2c_master_send(client, buf, 3);
+	if (ret < 0) {
+		pr_err("i2c tx fail. reg = 0x%x.ret = %d.\n", reg, ret);
+		return ret;
+	}
+	udelay(66);
+
+	/* Read Result of subcmd */
+	ret = i2c_master_send(client, buf, 1);
+	memset(buf, 0xAA, sizeof(buf));
+	ret = i2c_master_recv(client, buf, 2);
+	if (ret < 0) {
+		pr_err("i2c rx fail. reg = 0x%x.ret = %d.\n", reg, ret);
+		return ret;
+	}
+	val = (buf[1] << 8) + buf[0];
+
+	pr_debug("reg = 0x%02X.subcmd = 0x%x.val = 0x%04X.\n",
+		 reg , subcmd, val);
+
+	return val;
+}
+
+static int bq28400_read_block(struct i2c_client *client, u8 reg,
+			      u8 len, u8 *buf)
+{
+	int ret;
+	u32 val;
+
+	ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf);
+	val = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
+
+	if (ret < 0)
+		pr_err("i2c read fail. reg = 0x%x.ret = %d.\n", reg, ret);
+	else
+		pr_debug("reg = 0x%02X.val = 0x%04X.\n", reg , val);
+
+	return val;
+}
+
+/*
+ * Read a string from a device.
+ * Returns string length on success or error on failure (negative value).
+ */
+static int bq28400_read_string(struct i2c_client *client, u8 reg, char *str,
+			       u8 max_len)
+{
+	int ret;
+	int len;
+
+	ret = bq28400_read_block(client, reg, max_len, str);
+	if (ret < 0)
+		return ret;
+
+	len = str[0]; /* Actual length */
+	if (len > max_len - 2) { /* reduce len byte and null */
+		pr_err("len = %d invalid.\n", len);
+		return -EINVAL;
+	}
+
+	memcpy(&str[0], &str[1], len); /* Move sting to the start */
+	str[len] = 0; /* put NULL after actual size */
+
+	pr_debug("len = %d.str = %s.\n", len, str);
+
+	return len;
+}
+
+#define BQ28400_INVALID_TEMPERATURE	-999
+/*
+ * Return the battery temperature in tenths of degree Celsius
+ * Or -99.9 C if something fails.
+ */
+static int bq28400_read_temperature(struct i2c_client *client)
+{
+	int temp;
+
+	/* temperature resolution 0.1 Kelvin */
+	temp = bq28400_read_reg(client, SBS_TEMPERATURE);
+	if (temp < 0)
+		return BQ28400_INVALID_TEMPERATURE;
+
+	temp = temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
+
+	pr_debug("temp = %d C\n", temp/10);
+
+	return temp;
+}
+
+/*
+ * Return the battery Voltage in milivolts 0..20 V
+ * Or < 0 if something fails.
+ */
+static int bq28400_read_voltage(struct i2c_client *client)
+{
+	int mvolt = 0;
+
+	mvolt = bq28400_read_reg(client, SBS_VOLTAGE);
+	if (mvolt < 0)
+		return mvolt;
+
+	pr_debug("volt = %d mV.\n", mvolt);
+
+	return mvolt;
+}
+
+/*
+ * Return the battery Current in miliamps
+ * Or 0 if something fails.
+ * Positive current indicates charging
+ * Negative current indicates discharging.
+ * Current-now is calculated every second.
+ */
+static int bq28400_read_current(struct i2c_client *client)
+{
+	s16 current_ma = 0;
+
+	current_ma = bq28400_read_reg(client, SBS_CURRENT);
+
+	pr_debug("current = %d mA.\n", current_ma);
+
+	return current_ma;
+}
+
+/*
+ * Return the Average battery Current in miliamps
+ * Or 0 if something fails.
+ * Positive current indicates charging
+ * Negative current indicates discharging.
+ * Average Current is the rolling 1 minute average current.
+ */
+static int bq28400_read_avg_current(struct i2c_client *client)
+{
+	s16 current_ma = 0;
+
+	current_ma = bq28400_read_reg(client, SBS_AVG_CURRENT);
+
+	pr_debug("avg_current=%d mA.\n", current_ma);
+
+	return current_ma;
+}
+
+/*
+ * Return the battery Relative-State-Of-Charge 0..100 %
+ * Or 0 if something fails.
+ */
+static int bq28400_read_rsoc(struct i2c_client *client)
+{
+	int percentage = 0;
+
+	/* This register is only 1 byte */
+	percentage = i2c_smbus_read_byte_data(client, SBS_RSOC);
+
+	if (percentage < 0)
+		return 0;
+
+	pr_debug("percentage = %d.\n", percentage);
+
+	return percentage;
+}
+
+/*
+ * Return the battery Capacity in mAh.
+ * Or 0 if something fails.
+ */
+static int bq28400_read_full_capacity(struct i2c_client *client)
+{
+	int capacity = 0;
+
+	capacity = bq28400_read_reg(client, SBS_FULL_CAPACITY);
+	if (capacity < 0)
+		return 0;
+
+	pr_debug("full-capacity = %d mAh.\n", capacity);
+
+	return capacity;
+}
+
+/*
+ * Return the battery Capacity in mAh.
+ * Or 0 if something fails.
+ */
+static int bq28400_read_remain_capacity(struct i2c_client *client)
+{
+	int capacity = 0;
+
+	capacity = bq28400_read_reg(client, SBS_REMAIN_CAPACITY);
+	if (capacity < 0)
+		return 0;
+
+	pr_debug("remain-capacity = %d mAh.\n", capacity);
+
+	return capacity;
+}
+
+static int bq28400_enable_charging(struct bq28400_device *bq28400_dev,
+				   bool enable)
+{
+	int ret;
+	static bool is_charging_enabled;
+
+	if (bq28400_dev->dc_psy == NULL) {
+		bq28400_dev->dc_psy = power_supply_get_by_name("dc");
+		if (bq28400_dev->dc_psy == NULL) {
+			pr_err("fail to get dc-psy.\n");
+			return -ENODEV;
+		}
+	}
+
+	if (is_charging_enabled == enable) {
+		pr_debug("Charging enable already = %d.\n", enable);
+		return 0;
+	}
+
+	ret = power_supply_set_online(bq28400_dev->dc_psy, enable);
+	if (ret < 0) {
+		pr_err("fail to set dc-psy online to %d.\n", enable);
+		return ret;
+	}
+
+	is_charging_enabled = enable;
+
+	pr_debug("Charging enable = %d.\n", enable);
+
+	return 0;
+}
+
+static int bq28400_get_prop_status(struct i2c_client *client)
+{
+	int status = POWER_SUPPLY_STATUS_UNKNOWN;
+	int rsoc;
+	s16 current_ma = 0;
+	u16 battery_status;
+
+	battery_status = bq28400_read_reg(client, SBS_BATTERY_STATUS);
+
+	if (battery_status & BAT_STATUS_EMPTY)
+		pr_debug("Battery report Empty.\n");
+
+	/* Battery may report FULL before rsoc is 100%
+	 * for protection and cell-balancing.
+	 * The FULL report may remain when rsoc drops from 100%.
+	 */
+	if (battery_status & BAT_STATUS_FULL) {
+		pr_debug("Battery report Full.\n");
+		bq28400_enable_charging(bq28400_dev, false);
+		return POWER_SUPPLY_STATUS_FULL;
+	}
+
+	rsoc = bq28400_read_rsoc(client);
+	current_ma = bq28400_read_current(client);
+
+	if (rsoc == 100) {
+		bq28400_enable_charging(bq28400_dev, false);
+		pr_debug("Full.\n");
+		return POWER_SUPPLY_STATUS_FULL;
+	}
+
+	/*
+	* Positive current indicates charging
+	* Negative current indicates discharging.
+	* Charging is stopped at termination-current.
+	*/
+	if (current_ma < 0) {
+		bq28400_enable_charging(bq28400_dev, true);
+		pr_debug("Discharging.\n");
+		status = POWER_SUPPLY_STATUS_DISCHARGING;
+	} else if (current_ma > BQ_TERMINATION_CURRENT_MA) {
+		pr_debug("Charging.\n");
+		status = POWER_SUPPLY_STATUS_CHARGING;
+	} else {
+		pr_debug("Not Charging.\n");
+		status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+	}
+
+	return status;
+}
+
+static int bq28400_get_prop_charge_type(struct i2c_client *client)
+{
+	u16 battery_status;
+	u16 chg_status;
+	u16 fet_status;
+
+	battery_status = bq28400_read_reg(client, SBS_BATTERY_STATUS);
+	chg_status = bq28400_read_reg(client, SBS_CHARGING_STATUS);
+	fet_status = bq28400_read_reg(client, SBS_FET_STATUS);
+
+	if (battery_status & BAT_STATUS_DISCHARGING) {
+		pr_debug("Discharging.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	if (fet_status & FET_STATUS_PRECHARGE) {
+		pr_debug("Pre-Charging.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+	}
+
+	if (chg_status & CHG_STATUS_HOT_TEMP_CHARGING) {
+		pr_debug("Hot-Temp-Charging.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	}
+
+	if (chg_status & CHG_STATUS_LOW_TEMP_CHARGING) {
+		pr_debug("Low-Temp-Charging.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	}
+
+	if (chg_status & CHG_STATUS_STD1_TEMP_CHARGING) {
+		pr_debug("STD1-Temp-Charging.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	}
+
+	if (chg_status & CHG_STATUS_STD2_TEMP_CHARGING) {
+		pr_debug("STD2-Temp-Charging.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	}
+
+	if (chg_status & CHG_STATUS_BATTERY_DEPLETED)
+		pr_debug("battery_depleted.\n");
+
+	if (chg_status & CHG_STATUS_CELL_BALANCING)
+		pr_debug("cell_balancing.\n");
+
+	if (chg_status & CHG_STATUS_OVERCHARGE) {
+		pr_err("overcharge fault.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	if (chg_status & CHG_STATUS_SUSPENDED) {
+		pr_info("Suspended.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	if (chg_status & CHG_STATUS_DISABLED) {
+		pr_info("Disabled.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+}
+
+static bool bq28400_get_prop_present(struct i2c_client *client)
+{
+	int val;
+
+	val = bq28400_read_reg(client, SBS_BATTERY_STATUS);
+
+	/* If the bq28400 is inside the battery pack
+	 * then when battery is removed the i2c transfer will fail.
+	 */
+
+	if (val < 0)
+		return false;
+
+	/* TODO - support when bq28400 is not embedded in battery pack */
+
+	return true;
+}
+
+/*
+ * User sapce read the battery info.
+ * Get data online via I2C from the battery gauge.
+ */
+static int bq28400_get_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  union power_supply_propval *val)
+{
+	int ret = 0;
+	struct bq28400_device *dev = container_of(psy,
+						  struct bq28400_device,
+						  batt_psy);
+	struct i2c_client *client = dev->client;
+	static char str[BQ_MAX_STR_LEN];
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = bq28400_get_prop_status(client);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		val->intval = bq28400_get_prop_charge_type(client);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = bq28400_get_prop_present(client);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = bq28400_read_voltage(client);
+		val->intval *= 1000; /* mV to uV */
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = bq28400_read_rsoc(client);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		/* Positive current indicates drawing */
+		val->intval = -bq28400_read_current(client);
+		val->intval *= 1000; /* mA to uA */
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		/* Positive current indicates drawing */
+		val->intval = -bq28400_read_avg_current(client);
+		val->intval *= 1000; /* mA to uA */
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = bq28400_read_temperature(client);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		val->intval = bq28400_read_full_capacity(client);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = bq28400_read_remain_capacity(client);
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		bq28400_read_string(client, SBS_DEVICE_NAME, str, 20);
+		val->strval = str;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		bq28400_read_string(client, SBS_MANUFACTURER_NAME, str, 20);
+		val->strval = str;
+		break;
+	default:
+		pr_err(" psp %d Not supoprted.\n", psp);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int bq28400_set_reg(void *data, u64 val)
+{
+	struct debug_reg *dbg = data;
+	u8 reg = dbg->reg;
+	int ret;
+	struct i2c_client *client = bq28400_dev->client;
+
+	ret = bq28400_write_reg(client, reg, val);
+
+	return ret;
+}
+
+static int bq28400_get_reg(void *data, u64 *val)
+{
+	struct debug_reg *dbg = data;
+	u8 reg = dbg->reg;
+	u16 subcmd = dbg->subcmd;
+	int ret;
+	struct i2c_client *client = bq28400_dev->client;
+
+	if (subcmd)
+		ret = bq28400_read_subcmd(client, reg, subcmd);
+	else
+		ret = bq28400_read_reg(client, reg);
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, bq28400_get_reg, bq28400_set_reg,
+			"0x%04llx\n");
+
+static int bq28400_create_debugfs_entries(struct bq28400_device *bq28400_dev)
+{
+	int i;
+
+	bq28400_dev->dent = debugfs_create_dir(BQ28400_NAME, NULL);
+	if (IS_ERR(bq28400_dev->dent)) {
+		pr_err("bq28400 driver couldn't create debugfs dir\n");
+		return -EFAULT;
+	}
+
+	for (i = 0 ; i < ARRAY_SIZE(bq28400_debug_regs) ; i++) {
+		char *name = bq28400_debug_regs[i].name;
+		struct dentry *file;
+		void *data = &bq28400_debug_regs[i];
+
+		file = debugfs_create_file(name, 0644, bq28400_dev->dent,
+					   data, &reg_fops);
+		if (IS_ERR(file)) {
+			pr_err("debugfs_create_file %s failed.\n", name);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int bq28400_set_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  const union power_supply_propval *val)
+{
+	pr_debug("psp = %d.val = %d.\n", psp, val->intval);
+
+	return -EINVAL;
+}
+
+static void bq28400_external_power_changed(struct power_supply *psy)
+{
+	pr_debug("Notify power_supply_changed.\n");
+	/* Update LEDs and notify uevents */
+	power_supply_changed(&bq28400_dev->batt_psy);
+}
+
+static int __devinit bq28400_register_psy(struct bq28400_device *bq28400_dev)
+{
+	int ret;
+
+	bq28400_dev->batt_psy.name = "battery";
+	bq28400_dev->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	bq28400_dev->batt_psy.num_supplicants = 0;
+	bq28400_dev->batt_psy.properties = pm_power_props;
+	bq28400_dev->batt_psy.num_properties = ARRAY_SIZE(pm_power_props);
+	bq28400_dev->batt_psy.get_property = bq28400_get_property;
+	bq28400_dev->batt_psy.set_property = bq28400_set_property;
+	bq28400_dev->batt_psy.external_power_changed =
+		bq28400_external_power_changed;
+
+	ret = power_supply_register(&bq28400_dev->client->dev,
+				&bq28400_dev->batt_psy);
+	if (ret) {
+		pr_err("failed to register power_supply. ret=%d.\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * Update userspace every 1 minute.
+ * Normally it takes more than 120 minutes (two hours) to
+ * charge/discahrge the battery,
+ * so updating every 1 minute should be enough for 1% change
+ * detection.
+ * Any immidiate change detected by the DC charger is notified
+ * by the bq28400_external_power_changed callback, which notify
+ * the user space.
+ */
+static void bq28400_periodic_user_space_update_worker(struct work_struct *work)
+{
+	u32 delay_msec = 60*1000;
+
+	pr_debug("Notify user space.\n");
+
+	/* Notify user space via kobject_uevent change notification */
+	power_supply_changed(&bq28400_dev->batt_psy);
+
+	schedule_delayed_work(&bq28400_dev->periodic_user_space_update_work,
+			      round_jiffies_relative(msecs_to_jiffies
+						     (delay_msec)));
+}
+
+static int __devinit bq28400_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	int ret = 0;
+
+	if (!i2c_check_functionality(client->adapter,
+				I2C_FUNC_SMBUS_BYTE_DATA)) {
+		pr_err(" i2c func fail.\n");
+		return -EIO;
+	}
+
+	bq28400_dev = kzalloc(sizeof(*bq28400_dev), GFP_KERNEL);
+	if (!bq28400_dev) {
+		pr_err(" alloc fail.\n");
+		return -ENOMEM;
+	}
+
+	bq28400_dev->client = client;
+	i2c_set_clientdata(client, bq28400_dev);
+
+	ret = bq28400_register_psy(bq28400_dev);
+	if (ret) {
+		pr_err(" bq28400_register_psy fail.\n");
+		goto err_register_psy;
+	}
+
+	ret = bq28400_create_debugfs_entries(bq28400_dev);
+	if (ret) {
+		pr_err(" bq28400_create_debugfs_entries fail.\n");
+		goto err_debugfs;
+	}
+
+	INIT_DELAYED_WORK(&bq28400_dev->periodic_user_space_update_work,
+			  bq28400_periodic_user_space_update_worker);
+
+	schedule_delayed_work(&bq28400_dev->periodic_user_space_update_work,
+			      msecs_to_jiffies(1000));
+
+	pr_info("Device is ready.\n");
+
+	return 0;
+
+err_debugfs:
+	if (bq28400_dev->dent)
+		debugfs_remove_recursive(bq28400_dev->dent);
+	power_supply_unregister(&bq28400_dev->batt_psy);
+err_register_psy:
+	kfree(bq28400_dev);
+	bq28400_dev = NULL;
+
+	pr_info("FAIL.\n");
+
+	return ret;
+}
+
+static int __devexit bq28400_remove(struct i2c_client *client)
+{
+	struct bq28400_device *bq28400_dev = i2c_get_clientdata(client);
+
+	power_supply_unregister(&bq28400_dev->batt_psy);
+	if (bq28400_dev->dent)
+		debugfs_remove_recursive(bq28400_dev->dent);
+	kfree(bq28400_dev);
+	bq28400_dev = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id bq28400_match[] = {
+	{ .compatible = "ti,bq28400-battery", },
+	{ },
+	};
+
+static const struct i2c_device_id bq28400_id[] = {
+	{BQ28400_NAME, 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, bq28400_id);
+
+static struct i2c_driver bq28400_driver = {
+	.driver	= {
+		.name	= BQ28400_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(bq28400_match),
+	},
+	.probe		= bq28400_probe,
+	.remove		= __devexit_p(bq28400_remove),
+	.id_table	= bq28400_id,
+};
+
+static int __init bq28400_init(void)
+{
+	pr_info(" bq28400 driver rev %s.\n", BQ28400_REV);
+
+	return i2c_add_driver(&bq28400_driver);
+}
+module_init(bq28400_init);
+
+static void __exit bq28400_exit(void)
+{
+	return i2c_del_driver(&bq28400_driver);
+}
+module_exit(bq28400_exit);
+
+MODULE_DESCRIPTION("Driver for BQ28400 charger chip");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:" BQ28400_NAME);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 3977f17..d2d0c03 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -289,6 +289,7 @@
 	bool				has_dc_supply;
 	u8				active_path;
 	int				recent_reported_soc;
+	int				battery_less_hardware;
 };
 
 /* user space parameter to limit usb current */
@@ -1420,6 +1421,9 @@
 {
 	int percent_soc;
 
+	if (chip->battery_less_hardware)
+		return 100;
+
 	if (!get_prop_batt_present(chip))
 		percent_soc = voltage_based_capacity(chip);
 	else
@@ -1582,6 +1586,9 @@
 	int rc;
 	struct pm8xxx_adc_chan_result result;
 
+	if (chip->battery_less_hardware)
+		return 300;
+
 	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
 	if (rc) {
 		pr_err("error reading adc channel = %d, rc = %d\n",
@@ -4288,6 +4295,10 @@
 	chip->rconn_mohm = pdata->rconn_mohm;
 	chip->led_src_config = pdata->led_src_config;
 	chip->has_dc_supply = pdata->has_dc_supply;
+	chip->battery_less_hardware = pdata->battery_less_hardware;
+
+	if (chip->battery_less_hardware)
+		charging_disabled = 1;
 
 	rc = pm8921_chg_hw_init(chip);
 	if (rc) {
diff --git a/drivers/power/smb350_charger.c b/drivers/power/smb350_charger.c
new file mode 100644
index 0000000..93e208c
--- /dev/null
+++ b/drivers/power/smb350_charger.c
@@ -0,0 +1,865 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/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/power_supply.h>
+#include <linux/i2c/smb350.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/printk.h>
+
+/* Register definitions */
+#define CHG_CURRENT_REG			0x00	/* Non-Volatile + mirror */
+#define CHG_OTHER_CURRENT_REG		0x01	/* Non-Volatile + mirror */
+#define VAR_FUNC_REG			0x02	/* Non-Volatile + mirror */
+#define FLOAT_VOLTAGE_REG		0x03	/* Non-Volatile + mirror */
+#define CHG_CTRL_REG			0x04	/* Non-Volatile + mirror */
+#define STAT_TIMER_REG			0x05	/* Non-Volatile + mirror */
+#define PIN_ENABLE_CTRL_REG		0x06	/* Non-Volatile + mirror */
+#define THERM_CTRL_A_REG		0x07	/* Non-Volatile + mirror */
+#define SYSOK_USB3_SELECT_REG		0x08	/* Non-Volatile + mirror */
+#define CTRL_FUNCTIONS_REG		0x09	/* Non-Volatile + mirror */
+#define OTG_TLIM_THERM_CNTRL_REG	0x0A	/* Non-Volatile + mirror */
+#define TEMP_MONITOR_REG		0x0B	/* Non-Volatile + mirror */
+#define FAULT_IRQ_REG			0x0C	/* Non-Volatile */
+#define IRQ_ENABLE_REG			0x0D	/* Non-Volatile */
+#define SYSOK_REG			0x0E	/* Non-Volatile + mirror */
+
+#define AUTO_INPUT_VOLT_DETECT_REG	0x10	/* Non-Volatile Read-Only */
+#define STATUS_IRQ_REG			0x11	/* Non-Volatile Read-Only */
+#define I2C_SLAVE_ADDR_REG		0x12	/* Non-Volatile Read-Only */
+
+#define CMD_A_REG			0x30	/* Volatile Read-Write */
+#define CMD_B_REG			0x31	/* Volatile Read-Write */
+#define CMD_C_REG			0x33	/* Volatile Read-Write */
+
+#define IRQ_STATUS_A_REG		0x35	/* Volatile Read-Only */
+#define IRQ_STATUS_B_REG		0x36	/* Volatile Read-Only */
+#define IRQ_STATUS_C_REG		0x37	/* Volatile Read-Only */
+#define IRQ_STATUS_D_REG		0x38	/* Volatile Read-Only */
+#define IRQ_STATUS_E_REG		0x39	/* Volatile Read-Only */
+#define IRQ_STATUS_F_REG		0x3A	/* Volatile Read-Only */
+
+#define STATUS_A_REG			0x3B	/* Volatile Read-Only */
+#define STATUS_B_REG			0x3D	/* Volatile Read-Only */
+/* Note: STATUS_C_REG was removed from SMB349 to SMB350 */
+#define STATUS_D_REG			0x3E	/* Volatile Read-Only */
+#define STATUS_E_REG			0x3F	/* Volatile Read-Only */
+
+#define IRQ_STATUS_NUM (IRQ_STATUS_F_REG - IRQ_STATUS_A_REG + 1)
+
+/* Status bits and masks */
+#define SMB350_MASK(BITS, POS)		((u8)(((1 << BITS) - 1) << POS))
+#define FAST_CHG_CURRENT_MASK		SMB350_MASK(4, 4)
+
+#define SMB350_FAST_CHG_MIN_MA		1000
+#define SMB350_FAST_CHG_STEP_MA		200
+#define SMB350_FAST_CHG_MAX_MA		3600
+
+#define TERM_CURRENT_MASK		SMB350_MASK(3, 2)
+
+#define SMB350_TERM_CUR_MIN_MA		200
+#define SMB350_TERM_CUR_STEP_MA		100
+#define SMB350_TERM_CUR_MAX_MA		700
+
+#define CMD_A_VOLATILE_WR_PERM		BIT(7)
+#define CHG_CTRL_CURR_TERM_END_CHG	BIT(6)
+
+enum smb350_chg_status {
+	SMB_CHG_STATUS_NONE		= 0,
+	SMB_CHG_STATUS_PRE_CHARGE	= 1,
+	SMB_CHG_STATUS_FAST_CHARGE	= 2,
+	SMB_CHG_STATUS_TAPER_CHARGE	= 3,
+};
+
+static const char * const smb350_chg_status[] = {
+	"none",
+	"pre-charge",
+	"fast-charge",
+	"taper-charge"
+};
+
+struct smb350_device {
+	/* setup */
+	int			chg_current_ma;
+	int			term_current_ma;
+	int			chg_en_n_gpio;
+	int			chg_susp_n_gpio;
+	int			stat_gpio;
+	int			irq;
+	/* internal */
+	enum smb350_chg_status	chg_status;
+	struct i2c_client	*client;
+	struct delayed_work	irq_work;
+	struct dentry		*dent;
+	struct wake_lock	chg_wake_lock;
+	struct power_supply	dc_psy;
+};
+
+static struct smb350_device *smb350_dev;
+
+struct debug_reg {
+	char	*name;
+	u8	reg;
+};
+
+#define SMB350_DEBUG_REG(x) {#x, x##_REG}
+
+static struct debug_reg smb350_debug_regs[] = {
+	SMB350_DEBUG_REG(CHG_CURRENT),
+	SMB350_DEBUG_REG(CHG_OTHER_CURRENT),
+	SMB350_DEBUG_REG(VAR_FUNC),
+	SMB350_DEBUG_REG(FLOAT_VOLTAGE),
+	SMB350_DEBUG_REG(CHG_CTRL),
+	SMB350_DEBUG_REG(STAT_TIMER),
+	SMB350_DEBUG_REG(PIN_ENABLE_CTRL),
+	SMB350_DEBUG_REG(THERM_CTRL_A),
+	SMB350_DEBUG_REG(SYSOK_USB3_SELECT),
+	SMB350_DEBUG_REG(CTRL_FUNCTIONS),
+	SMB350_DEBUG_REG(OTG_TLIM_THERM_CNTRL),
+	SMB350_DEBUG_REG(TEMP_MONITOR),
+	SMB350_DEBUG_REG(FAULT_IRQ),
+	SMB350_DEBUG_REG(IRQ_ENABLE),
+	SMB350_DEBUG_REG(SYSOK),
+	SMB350_DEBUG_REG(AUTO_INPUT_VOLT_DETECT),
+	SMB350_DEBUG_REG(STATUS_IRQ),
+	SMB350_DEBUG_REG(I2C_SLAVE_ADDR),
+	SMB350_DEBUG_REG(CMD_A),
+	SMB350_DEBUG_REG(CMD_B),
+	SMB350_DEBUG_REG(CMD_C),
+	SMB350_DEBUG_REG(IRQ_STATUS_A),
+	SMB350_DEBUG_REG(IRQ_STATUS_B),
+	SMB350_DEBUG_REG(IRQ_STATUS_C),
+	SMB350_DEBUG_REG(IRQ_STATUS_D),
+	SMB350_DEBUG_REG(IRQ_STATUS_E),
+	SMB350_DEBUG_REG(IRQ_STATUS_F),
+	SMB350_DEBUG_REG(STATUS_A),
+	SMB350_DEBUG_REG(STATUS_B),
+	SMB350_DEBUG_REG(STATUS_D),
+	SMB350_DEBUG_REG(STATUS_E),
+};
+
+/*
+ * Read 8-bit register value. return negative value on error.
+ */
+static int smb350_read_reg(struct i2c_client *client, u8 reg)
+{
+	int val;
+
+	val = i2c_smbus_read_byte_data(client, reg);
+	if (val < 0)
+		pr_err("i2c read fail. reg=0x%x.ret=%d.\n", reg, val);
+	else
+		pr_debug("reg=0x%02X.val=0x%02X.\n", reg , val);
+
+	return val;
+}
+
+/*
+ * Write 8-bit register value. return negative value on error.
+ */
+static int smb350_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, reg, val);
+	if (ret < 0)
+		pr_err("i2c read fail. reg=0x%x.val=0x%x.ret=%d.\n",
+		       reg, val, ret);
+	else
+		pr_debug("reg=0x%02X.val=0x%02X.\n", reg , val);
+
+	return ret;
+}
+
+static int smb350_masked_write(struct i2c_client *client, int reg, u8 mask,
+			       u8 val)
+{
+	int ret;
+	int temp;
+	int shift = find_first_bit((unsigned long *) &mask, 8);
+
+	temp = smb350_read_reg(client, reg);
+	if (temp < 0)
+		return temp;
+
+	temp &= ~mask;
+	temp |= (val << shift) & mask;
+	ret = smb350_write_reg(client, reg, temp);
+
+	return ret;
+}
+
+#define SMB350_FLOAT_VOLT_BASE_MV 6920
+#define SMB350_FLOAT_VOLT_STEP_MV   40
+#define SMB350_FLOAT_VOLT_MAX_MV  (6920 + 0x2F * 40)
+
+/* Fast-to-Taper charging volatge */
+static int smb350_get_float_voltage(struct i2c_client *client)
+{
+	u16 val = smb350_read_reg(client, STATUS_A_REG);
+
+	val = SMB350_FLOAT_VOLT_BASE_MV +
+		((val & 0x2F) * SMB350_FLOAT_VOLT_STEP_MV);
+
+	return val;
+}
+
+static bool smb350_is_dc_present(struct i2c_client *client)
+{
+	u16 irq_status_f = smb350_read_reg(client, IRQ_STATUS_F_REG);
+	bool power_ok = irq_status_f & 0x01;
+
+	/* Power-ok , IRQ_STATUS_F_REG bit#0 */
+	if (power_ok)
+		pr_debug("DC is present.\n");
+	else
+		pr_debug("DC is missing.\n");
+
+	return power_ok;
+}
+
+static bool smb350_is_charging(struct i2c_client *client)
+{
+	int val;
+	bool is_charging;
+
+	val = smb350_read_reg(client, STATUS_B_REG);
+	if (val < 0)
+		return false;
+
+	val = (val >> 1) & 0x3;
+
+	is_charging = (val != 0);
+
+	return is_charging;
+}
+
+static int smb350_get_prop_charge_type(struct smb350_device *dev)
+{
+	int status_b;
+	enum smb350_chg_status status;
+	int chg_type = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+	bool chg_enabled;
+	bool charger_err;
+	struct i2c_client *client = dev->client;
+
+	status_b = smb350_read_reg(client, STATUS_B_REG);
+	if (status_b < 0) {
+		pr_err("failed to read STATUS_B_REG.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+	}
+
+	chg_enabled = (bool) (status_b & 0x01);
+	charger_err = (bool) (status_b & (1<<6));
+
+	if (!chg_enabled) {
+		pr_warn("Charging not enabled.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	if (charger_err) {
+		pr_warn("Charger error detected.\n");
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	status = (status_b >> 1) & 0x3;
+
+	if (status == SMB_CHG_STATUS_NONE)
+		chg_type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+	else if (status == SMB_CHG_STATUS_FAST_CHARGE) /* constant current */
+		chg_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+	else if (status == SMB_CHG_STATUS_TAPER_CHARGE) /* constant voltage */
+		chg_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+	else if (status == SMB_CHG_STATUS_PRE_CHARGE)
+		chg_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+
+	pr_debug("smb-chg-status=%d=%s.\n", status, smb350_chg_status[status]);
+
+	if (dev->chg_status != status) { /* Status changed */
+		if (status == SMB_CHG_STATUS_NONE) {
+			pr_debug("Charging stopped.\n");
+			wake_unlock(&dev->chg_wake_lock);
+		} else {
+			pr_debug("Charging started.\n");
+			wake_lock(&dev->chg_wake_lock);
+		}
+	}
+
+	dev->chg_status = status;
+
+	return chg_type;
+}
+
+static void smb350_enable_charging(struct smb350_device *dev, bool enable)
+{
+	int val = !enable; /* active low */
+
+	pr_debug("enable=%d.\n", enable);
+
+	gpio_set_value_cansleep(dev->chg_en_n_gpio, val);
+}
+
+/* When the status bit of a certain condition is read,
+ * the corresponding IRQ signal is cleared.
+ */
+static int smb350_clear_irq(struct i2c_client *client)
+{
+	int ret;
+
+	ret = smb350_read_reg(client, IRQ_STATUS_A_REG);
+	if (ret < 0)
+		return ret;
+	ret = smb350_read_reg(client, IRQ_STATUS_B_REG);
+	if (ret < 0)
+		return ret;
+	ret = smb350_read_reg(client, IRQ_STATUS_C_REG);
+	if (ret < 0)
+		return ret;
+	ret = smb350_read_reg(client, IRQ_STATUS_D_REG);
+	if (ret < 0)
+		return ret;
+	ret = smb350_read_reg(client, IRQ_STATUS_E_REG);
+	if (ret < 0)
+		return ret;
+	ret = smb350_read_reg(client, IRQ_STATUS_F_REG);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * Do the IRQ work from a thread context rather than interrupt context.
+ * Read status registers to clear interrupt source.
+ * Notify the power-supply driver about change detected.
+ * Relevant events for start/stop charging:
+ * 1. DC insert/remove
+ * 2. End-Of-Charging
+ * 3. Battery insert/remove
+ * 4. Temperture too hot/cold
+ * 5. Charging timeout expired.
+ */
+static void smb350_irq_worker(struct work_struct *work)
+{
+	int ret = 0;
+	struct smb350_device *dev =
+		container_of(work, struct smb350_device, irq_work.work);
+
+	ret = smb350_clear_irq(dev->client);
+	if (ret == 0) { /* Cleared ok */
+		/* Notify Battery-psy about status changed */
+		pr_debug("Notify power_supply_changed.\n");
+		power_supply_changed(&dev->dc_psy);
+	}
+}
+
+/*
+ * The STAT pin is low when charging and high when not charging.
+ * When the smb350 start/stop charging the STAT pin triggers an interrupt.
+ * Interrupt is triggered on both rising or falling edge.
+ */
+static irqreturn_t smb350_irq(int irq, void *dev_id)
+{
+	struct smb350_device *dev = dev_id;
+
+	pr_debug("\n");
+
+	/* I2C transfers API should not run in interrupt context */
+	schedule_delayed_work(&dev->irq_work, msecs_to_jiffies(100));
+
+	return IRQ_HANDLED;
+}
+
+static enum power_supply_property pm_power_props[] = {
+	/* real time */
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	/* fixed */
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static char *pm_power_supplied_to[] = {
+	"battery",
+};
+
+static int smb350_get_property(struct power_supply *psy,
+			       enum power_supply_property psp,
+			       union power_supply_propval *val)
+{
+	int ret = 0;
+	struct smb350_device *dev = container_of(psy,
+						 struct smb350_device,
+						 dc_psy);
+	struct i2c_client *client = dev->client;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = smb350_is_dc_present(client);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = smb350_is_charging(client);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		val->intval = smb350_get_prop_charge_type(dev);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = smb350_get_float_voltage(client);
+		val->intval *= 1000; /* mV to uV */
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = SMB350_NAME;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = "Summit Microelectronics";
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = dev->chg_current_ma;
+		break;
+	default:
+		pr_err("Invalid prop = %d.\n", psp);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int smb350_set_property(struct power_supply *psy,
+			       enum power_supply_property psp,
+			       const union power_supply_propval *val)
+{
+	int ret = 0;
+	struct smb350_device *dev =
+		container_of(psy, struct smb350_device, dc_psy);
+
+	switch (psp) {
+	/*
+	 *  Allow a smart battery to Start/Stop charging.
+	 *  i.e. when End-Of-Charging detected.
+	 *  The SMB350 can be configured to terminate charging
+	 *  when charge-current reaching Termination-Current.
+	 */
+	case POWER_SUPPLY_PROP_ONLINE:
+		smb350_enable_charging(dev, val->intval);
+		break;
+	default:
+		pr_err("Invalid prop = %d.\n", psp);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int smb350_set_chg_current(struct i2c_client *client, int current_ma)
+{
+	int ret;
+	u8 temp;
+
+	if ((current_ma < SMB350_FAST_CHG_MIN_MA) ||
+	    (current_ma >  SMB350_FAST_CHG_MAX_MA)) {
+		pr_err("invalid current %d mA.\n", current_ma);
+		return -EINVAL;
+	}
+
+	temp = (current_ma - SMB350_FAST_CHG_MIN_MA) / SMB350_FAST_CHG_STEP_MA;
+
+	pr_debug("fast-chg-current=%d mA setting %02x\n", current_ma, temp);
+
+	ret = smb350_masked_write(client, CHG_CURRENT_REG,
+				  FAST_CHG_CURRENT_MASK, temp);
+
+	return ret;
+}
+
+static int smb350_set_term_current(struct i2c_client *client, int current_ma)
+{
+	int ret;
+	u8 temp;
+
+	if ((current_ma < SMB350_TERM_CUR_MIN_MA) ||
+	    (current_ma >  SMB350_TERM_CUR_MAX_MA)) {
+		pr_err("invalid current %d mA to set\n", current_ma);
+		return -EINVAL;
+	}
+
+	temp = (current_ma - SMB350_TERM_CUR_MIN_MA) / SMB350_TERM_CUR_STEP_MA;
+
+	pr_debug("term-current=%d mA setting %02x\n", current_ma, temp);
+
+	ret = smb350_masked_write(client, CHG_OTHER_CURRENT_REG,
+				  TERM_CURRENT_MASK, temp);
+
+	return ret;
+}
+
+static int smb350_set_reg(void *data, u64 val)
+{
+	u32 addr = (u32) data;
+	int ret;
+	struct i2c_client *client = smb350_dev->client;
+
+	ret = smb350_write_reg(client, addr, (u8) val);
+
+	return ret;
+}
+
+static int smb350_get_reg(void *data, u64 *val)
+{
+	u32 addr = (u32) data;
+	int ret;
+	struct i2c_client *client = smb350_dev->client;
+
+	ret = smb350_read_reg(client, addr);
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, smb350_get_reg, smb350_set_reg, "0x%02llx\n");
+
+static int smb350_create_debugfs_entries(struct smb350_device *dev)
+{
+	int i;
+	dev->dent = debugfs_create_dir(SMB350_NAME, NULL);
+	if (IS_ERR(dev->dent)) {
+		pr_err("smb350 driver couldn't create debugfs dir\n");
+		return -EFAULT;
+	}
+
+	for (i = 0 ; i < ARRAY_SIZE(smb350_debug_regs) ; i++) {
+		char *name = smb350_debug_regs[i].name;
+		u32 reg = smb350_debug_regs[i].reg;
+		struct dentry *file;
+
+		file = debugfs_create_file(name, 0644, dev->dent,
+					(void *) reg, &reg_fops);
+		if (IS_ERR(file)) {
+			pr_err("debugfs_create_file %s failed.\n", name);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int smb350_set_volatile_params(struct smb350_device *dev)
+{
+	int ret;
+	struct i2c_client *client = dev->client;
+
+	pr_debug("\n");
+
+	ret = smb350_write_reg(client, CMD_A_REG, CMD_A_VOLATILE_WR_PERM);
+	if (ret) {
+		pr_err("Failed to set VOLATILE_WR_PERM ret=%d\n", ret);
+		return ret;
+	}
+
+	/* Disable SMB350 pulse-IRQ mechanism,
+	 * we use interrupts based on charging-status-transition
+	 */
+	/* Enable STATUS output (regardless of IRQ-pulses) */
+	smb350_masked_write(client, CMD_A_REG, BIT(0), 0);
+
+	/* Disable LED blinking - avoid periodic irq */
+	smb350_masked_write(client, PIN_ENABLE_CTRL_REG, BIT(7), 0);
+
+	/* Disable Failure SMB-IRQ */
+	ret = smb350_write_reg(client, FAULT_IRQ_REG, 0x00);
+	if (ret) {
+		pr_err("Failed to set FAULT_IRQ_REG ret=%d\n", ret);
+		return ret;
+	}
+
+	/* Disable Event IRQ */
+	ret = smb350_write_reg(client, IRQ_ENABLE_REG, 0x00);
+	if (ret) {
+		pr_err("Failed to set IRQ_ENABLE_REG ret=%d\n", ret);
+		return ret;
+	}
+
+	/* Enable charging/not-charging status output via STAT pin */
+	smb350_masked_write(client, STAT_TIMER_REG, BIT(5), 0);
+
+	/* Disable Automatic Recharge */
+	smb350_masked_write(client, CHG_CTRL_REG, BIT(7), 1);
+
+	/* Set fast-charge current */
+	ret = smb350_set_chg_current(client, dev->chg_current_ma);
+	if (ret) {
+		pr_err("Failed to set FAST_CHG_CURRENT ret=%d\n", ret);
+		return ret;
+	}
+
+	if (dev->term_current_ma > 0) {
+		/* Enable Current Termination */
+		smb350_masked_write(client, CHG_CTRL_REG, BIT(6), 0);
+
+		/* Set Termination current */
+		smb350_set_term_current(client, dev->term_current_ma);
+	} else {
+		/* Disable Current Termination */
+		smb350_masked_write(client, CHG_CTRL_REG, BIT(6), 1);
+	}
+
+	return 0;
+}
+
+static int __devinit smb350_register_psy(struct smb350_device *dev)
+{
+	int ret;
+
+	dev->dc_psy.name = "dc";
+	dev->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+	dev->dc_psy.supplied_to = pm_power_supplied_to;
+	dev->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+	dev->dc_psy.properties = pm_power_props;
+	dev->dc_psy.num_properties = ARRAY_SIZE(pm_power_props);
+	dev->dc_psy.get_property = smb350_get_property;
+	dev->dc_psy.set_property = smb350_set_property;
+
+	ret = power_supply_register(&dev->client->dev,
+				&dev->dc_psy);
+	if (ret) {
+		pr_err("failed to register power_supply. ret=%d.\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit smb350_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	int ret = 0;
+	const struct smb350_platform_data *pdata;
+	struct device_node *dev_node = client->dev.of_node;
+	struct smb350_device *dev;
+
+	/* STAT pin change on start/stop charging */
+	u32 irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+	if (!i2c_check_functionality(client->adapter,
+				I2C_FUNC_SMBUS_BYTE_DATA)) {
+		pr_err("i2c func fail.\n");
+		return -EIO;
+	}
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		pr_err("alloc fail.\n");
+		return -ENOMEM;
+	}
+
+	smb350_dev = dev;
+	dev->client = client;
+
+	if (dev_node) {
+		dev->chg_en_n_gpio =
+			of_get_named_gpio(dev_node, "summit,chg-en-n-gpio", 0);
+		pr_debug("chg_en_n_gpio = %d.\n", dev->chg_en_n_gpio);
+
+		dev->chg_susp_n_gpio =
+			of_get_named_gpio(dev_node,
+					  "summit,chg-susp-n-gpio", 0);
+		pr_debug("chg_susp_n_gpio = %d.\n", dev->chg_susp_n_gpio);
+
+		dev->stat_gpio =
+			of_get_named_gpio(dev_node, "summit,stat-gpio", 0);
+		pr_debug("stat_gpio = %d.\n", dev->stat_gpio);
+
+		ret = of_property_read_u32(dev_node, "summit,chg-current-ma",
+					   &(dev->chg_current_ma));
+		pr_debug("chg_current_ma = %d.\n", dev->chg_current_ma);
+		if (ret) {
+			pr_err("Unable to read chg_current.\n");
+			return ret;
+		}
+		ret = of_property_read_u32(dev_node, "summit,term-current-ma",
+					   &(dev->term_current_ma));
+		pr_debug("term_current_ma = %d.\n", dev->term_current_ma);
+		if (ret) {
+			pr_err("Unable to read term_current_ma.\n");
+			return ret;
+		}
+	} else {
+		pdata = client->dev.platform_data;
+
+		if (pdata == NULL) {
+			pr_err("no platform data.\n");
+			return -EINVAL;
+		}
+
+		dev->chg_en_n_gpio = pdata->chg_en_n_gpio;
+		dev->chg_susp_n_gpio = pdata->chg_susp_n_gpio;
+		dev->stat_gpio = pdata->stat_gpio;
+
+		dev->chg_current_ma = pdata->chg_current_ma;
+		dev->term_current_ma = pdata->term_current_ma;
+	}
+
+	ret = gpio_request(dev->stat_gpio, "smb350_stat");
+	if (ret) {
+		pr_err("gpio_request failed for %d ret=%d\n",
+		       dev->stat_gpio, ret);
+		goto err_stat_gpio;
+	}
+	dev->irq = gpio_to_irq(dev->stat_gpio);
+	pr_debug("irq#=%d.\n", dev->irq);
+
+	ret = gpio_request(dev->chg_susp_n_gpio, "smb350_suspend");
+	if (ret) {
+		pr_err("gpio_request failed for %d ret=%d\n",
+			dev->chg_susp_n_gpio, ret);
+		goto err_susp_gpio;
+	}
+
+	ret = gpio_request(dev->chg_en_n_gpio, "smb350_charger_enable");
+	if (ret) {
+		pr_err("gpio_request failed for %d ret=%d\n",
+			dev->chg_en_n_gpio, ret);
+		goto err_en_gpio;
+	}
+
+	i2c_set_clientdata(client, dev);
+
+	pr_debug("set charge-enable + not suspend.\n");
+	gpio_set_value_cansleep(dev->chg_en_n_gpio, 1);	/* Disable */
+	msleep(100);
+	gpio_set_value_cansleep(dev->chg_susp_n_gpio, 1); /* Normal */
+	msleep(100); /* Allow the device to exist shutdown */
+
+	smb350_read_reg(client, I2C_SLAVE_ADDR_REG);
+
+	ret = smb350_set_volatile_params(dev);
+	if (ret)
+		goto err_set_params;
+
+	ret = smb350_register_psy(dev);
+	if (ret)
+		goto err_set_params;
+
+	ret = smb350_create_debugfs_entries(dev);
+	if (ret)
+		goto err_debugfs;
+
+	INIT_DELAYED_WORK(&dev->irq_work, smb350_irq_worker);
+	wake_lock_init(&dev->chg_wake_lock,
+		       WAKE_LOCK_SUSPEND, SMB350_NAME);
+
+	ret = request_irq(dev->irq, smb350_irq, irq_flags,
+			  "smb350_irq", dev);
+	if (ret) {
+		pr_err("request_irq %d failed.ret=%d\n", dev->irq, ret);
+		goto err_irq;
+	}
+
+	smb350_enable_charging(dev, true);
+
+	return 0;
+
+err_irq:
+err_debugfs:
+	if (dev->dent)
+		debugfs_remove_recursive(dev->dent);
+err_set_params:
+	gpio_free(dev->chg_en_n_gpio);
+err_en_gpio:
+	gpio_free(dev->chg_susp_n_gpio);
+err_susp_gpio:
+	gpio_free(dev->stat_gpio);
+err_stat_gpio:
+	kfree(smb350_dev);
+	smb350_dev = NULL;
+
+	pr_info("FAIL.\n");
+
+	return ret;
+}
+
+static int __devexit smb350_remove(struct i2c_client *client)
+{
+	struct smb350_device *dev = i2c_get_clientdata(client);
+
+	power_supply_unregister(&dev->dc_psy);
+	gpio_free(dev->chg_en_n_gpio);
+	gpio_free(dev->chg_susp_n_gpio);
+	if (dev->stat_gpio)
+		gpio_free(dev->stat_gpio);
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+	if (dev->dent)
+		debugfs_remove_recursive(dev->dent);
+	kfree(smb350_dev);
+	smb350_dev = NULL;
+
+	return 0;
+}
+
+static const struct i2c_device_id smb350_id[] = {
+	{SMB350_NAME, 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, smb350_id);
+
+static const struct of_device_id smb350_match[] = {
+	{ .compatible = "summit,smb350-charger", },
+	{ },
+};
+
+static struct i2c_driver smb350_driver = {
+	.driver	= {
+			.name	= SMB350_NAME,
+			.owner	= THIS_MODULE,
+			.of_match_table = of_match_ptr(smb350_match),
+	},
+	.probe		= smb350_probe,
+	.remove		= __devexit_p(smb350_remove),
+	.id_table	= smb350_id,
+};
+
+static int __init smb350_init(void)
+{
+	return i2c_add_driver(&smb350_driver);
+}
+module_init(smb350_init);
+
+static void __exit smb350_exit(void)
+{
+	return i2c_del_driver(&smb350_driver);
+}
+module_exit(smb350_exit);
+
+MODULE_DESCRIPTION("Driver for SMB350 charger chip");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:" SMB350_NAME);
diff --git a/drivers/slimbus/Kconfig b/drivers/slimbus/Kconfig
index a6a068d..72bd28a 100644
--- a/drivers/slimbus/Kconfig
+++ b/drivers/slimbus/Kconfig
@@ -16,4 +16,13 @@
 	help
 	  Select driver for Qualcomm's Slimbus Master Component.
 
+config SLIMBUS_MSM_NGD
+	tristate "Qualcomm Slimbus Satellite Component"
+	help
+	  Select driver for Qualcomm's Slimbus Satellite Component.
+	  This is light-weight slimbus controller driver responsible for
+	  communicating with slave HW directly over the bus using messaging
+	  interface, and communicating with master component residing on ADSP
+	  for bandwidth and data-channel management.
+
 endif
diff --git a/drivers/slimbus/Makefile b/drivers/slimbus/Makefile
index 674f057..45d6e6e 100644
--- a/drivers/slimbus/Makefile
+++ b/drivers/slimbus/Makefile
@@ -3,3 +3,4 @@
 #
 obj-$(CONFIG_SLIMBUS)			+= slimbus.o
 obj-$(CONFIG_SLIMBUS_MSM_CTRL)		+= slim-msm.o slim-msm-ctrl.o
+obj-$(CONFIG_SLIMBUS_MSM_NGD)		+= slim-msm.o slim-msm-ngd.o
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
new file mode 100644
index 0000000..1f2a95e
--- /dev/null
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -0,0 +1,962 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_slimbus.h>
+#include <linux/timer.h>
+#include <mach/sps.h>
+#include "slim-msm.h"
+#include <mach/qdsp6v2/apr.h>
+
+#define NGD_SLIM_NAME	"ngd_msm_ctrl"
+#define SLIM_LA_MGR	0xFF
+#define SLIM_ROOT_FREQ	24576000
+
+#define NGD_BASE_V1(r)	(((r) % 2) ? 0x800 : 0xA00)
+#define NGD_BASE_V2(r)	(((r) % 2) ? 0x1000 : 0x2000)
+#define NGD_BASE(r, v) ((v) ? NGD_BASE_V2(r) : NGD_BASE_V1(r))
+/* NGD (Non-ported Generic Device) registers */
+enum ngd_reg {
+	NGD_CFG		= 0x0,
+	NGD_STATUS	= 0x4,
+	NGD_RX_MSGQ_CFG	= 0x8,
+	NGD_INT_EN	= 0x10,
+	NGD_INT_STAT	= 0x14,
+	NGD_INT_CLR	= 0x18,
+	NGD_TX_MSG	= 0x30,
+	NGD_RX_MSG	= 0x70,
+	NGD_IE_STAT	= 0xF0,
+	NGD_VE_STAT	= 0x100,
+};
+
+enum ngd_msg_cfg {
+	NGD_CFG_ENABLE		= 1,
+	NGD_CFG_RX_MSGQ_EN	= 1 << 1,
+	NGD_CFG_TX_MSGQ_EN	= 1 << 2,
+};
+
+enum ngd_intr {
+	NGD_INT_RECFG_DONE	= 1 << 24,
+	NGD_INT_TX_NACKED_2	= 1 << 25,
+	NGD_INT_MSG_BUF_CONTE	= 1 << 26,
+	NGD_INT_MSG_TX_INVAL	= 1 << 27,
+	NGD_INT_IE_VE_CHG	= 1 << 28,
+	NGD_INT_DEV_ERR		= 1 << 29,
+	NGD_INT_RX_MSG_RCVD	= 1 << 30,
+	NGD_INT_TX_MSG_SENT	= 1 << 31,
+};
+
+enum ngd_offsets {
+	NGD_NACKED_MC		= 0x7F00000,
+	NGD_ACKED_MC		= 0xFE000,
+	NGD_ERROR		= 0x1800,
+	NGD_MSGQ_SUPPORT	= 0x400,
+	NGD_RX_MSGQ_TIME_OUT	= 0x16,
+	NGD_ENUMERATED		= 0x1,
+	NGD_TX_BUSY		= 0x0,
+};
+
+static irqreturn_t ngd_slim_interrupt(int irq, void *d)
+{
+	struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
+	void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
+	u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
+
+	if (stat & NGD_INT_TX_MSG_SENT) {
+		writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
+		/* Make sure interrupt is cleared */
+		mb();
+		if (dev->wr_comp)
+			complete(dev->wr_comp);
+	} else if ((stat & NGD_INT_MSG_BUF_CONTE) ||
+		(stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
+		(stat & NGD_INT_TX_NACKED_2)) {
+		dev_err(dev->dev, "NGD interrupt error:0x%x", stat);
+		writel_relaxed(stat, ngd + NGD_INT_CLR);
+		/* Guarantee that error interrupts are cleared */
+		mb();
+		if (((stat & NGD_INT_TX_NACKED_2) ||
+			(stat & NGD_INT_MSG_TX_INVAL))) {
+			dev->err = -EIO;
+		if (dev->wr_comp)
+			complete(dev->wr_comp);
+		}
+	}
+	if (stat & NGD_INT_RX_MSG_RCVD) {
+		u32 rx_buf[10];
+		u8 len, i;
+		rx_buf[0] = readl_relaxed(ngd + NGD_RX_MSG);
+		len = rx_buf[0] & 0x1F;
+		for (i = 1; i < ((len + 3) >> 2); i++) {
+			rx_buf[i] = readl_relaxed(ngd + NGD_RX_MSG +
+						(4 * i));
+			dev_dbg(dev->dev, "REG-RX data: %x\n", rx_buf[i]);
+		}
+		msm_slim_rx_enqueue(dev, rx_buf, len);
+		writel_relaxed(NGD_INT_RX_MSG_RCVD,
+				ngd + NGD_INT_CLR);
+		/*
+		 * Guarantee that CLR bit write goes through before
+		 * queuing work
+		 */
+		mb();
+		if (dev->use_rx_msgqs)
+			dev_err(dev->dev,
+				"direct message received even with RX MSGQs");
+		else
+			complete(&dev->rx_msgq_notify);
+	}
+	if (stat & NGD_INT_RECFG_DONE) {
+		writel_relaxed(NGD_INT_RECFG_DONE, ngd + NGD_INT_CLR);
+		/* Guarantee RECONFIG DONE interrupt is cleared */
+		mb();
+		/* In satellite mode, just log the reconfig done IRQ */
+		dev_dbg(dev->dev, "reconfig done IRQ for NGD");
+	}
+	if (stat & NGD_INT_IE_VE_CHG) {
+		writel_relaxed(NGD_INT_IE_VE_CHG, ngd + NGD_INT_CLR);
+		/* Guarantee IE VE change interrupt is cleared */
+		mb();
+		dev_err(dev->dev, "NGD IE VE change");
+	}
+	return IRQ_HANDLED;
+}
+
+static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
+				u8 *tid, struct completion *done)
+{
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+	if (ctrl->last_tid <= 255) {
+		ctrl->txnt = krealloc(ctrl->txnt,
+				(ctrl->last_tid + 1) *
+				sizeof(struct slim_msg_txn *),
+				GFP_KERNEL);
+		if (!ctrl->txnt)
+			return -ENOMEM;
+		dev->msg_cnt = ctrl->last_tid;
+		ctrl->last_tid++;
+	} else {
+		int i;
+		for (i = 0; i < 256; i++) {
+			dev->msg_cnt = ((dev->msg_cnt + 1) & 0xFF);
+			if (ctrl->txnt[dev->msg_cnt] == NULL)
+				break;
+		}
+		if (i >= 256) {
+			dev_err(&ctrl->dev, "out of TID");
+			return -ENOMEM;
+		}
+	}
+	ctrl->txnt[dev->msg_cnt] = txn;
+	txn->tid = dev->msg_cnt;
+	txn->comp = done;
+	*tid = dev->msg_cnt;
+	return 0;
+}
+static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
+{
+	DECLARE_COMPLETION_ONSTACK(done);
+	DECLARE_COMPLETION_ONSTACK(tx_sent);
+
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+	u32 *pbuf;
+	u8 *puc;
+	int ret = 0;
+	int msgv = -1;
+	u8 la = txn->la;
+	u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+
+	if (txn->mt == SLIM_MSG_MT_CORE &&
+		(txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+		 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
+		return 0;
+	}
+	msgv = msm_slim_get_ctrl(dev);
+	mutex_lock(&dev->tx_lock);
+	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
+		(dev->state == MSM_CTRL_ASLEEP ||
+		dev->state == MSM_CTRL_SLEEPING)) {
+		int timeout;
+		dev_err(dev->dev, "controller not ready");
+		mutex_unlock(&dev->tx_lock);
+		/* Reconf is signalled when master responds */
+		timeout = wait_for_completion_timeout(&dev->reconf, HZ);
+		if (timeout) {
+			mutex_lock(&dev->tx_lock);
+		} else {
+			if (msgv >= 0)
+				msm_slim_put_ctrl(dev);
+			return -EBUSY;
+		}
+	}
+	if (txn->mt == SLIM_MSG_MT_CORE &&
+		(txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
+		txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
+		txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
+		int i = 0;
+		txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+		if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
+			txn->mc = SLIM_USR_MC_CONNECT_SRC;
+		else if (txn->mc == SLIM_MSG_MC_CONNECT_SINK)
+			txn->mc = SLIM_USR_MC_CONNECT_SINK;
+		else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
+			txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
+		if (txn->la == SLIM_LA_MGR)
+			txn->la = dev->pgdla;
+		wbuf[i++] = txn->la;
+		la = SLIM_LA_MGR;
+		wbuf[i++] = txn->wbuf[0];
+		if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
+			wbuf[i++] = txn->wbuf[1];
+		ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
+		if (ret) {
+			pr_err("TID for connect/disconnect fail:%d", ret);
+			goto ngd_xfer_err;
+		}
+		txn->len = i;
+		txn->wbuf = wbuf;
+		txn->rl = txn->len + 4;
+	}
+	txn->rl--;
+	pbuf = msm_get_msg_buf(dev, txn->rl);
+	if (!pbuf) {
+		dev_err(dev->dev, "Message buffer unavailable");
+		ret = -ENOMEM;
+		goto ngd_xfer_err;
+	}
+	dev->err = 0;
+
+	if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
+		ret = -EPROTONOSUPPORT;
+		goto ngd_xfer_err;
+	}
+	if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
+		*pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 0,
+				la);
+	else
+		*pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 1,
+				la);
+	if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
+		puc = ((u8 *)pbuf) + 3;
+	else
+		puc = ((u8 *)pbuf) + 2;
+	if (txn->rbuf)
+		*(puc++) = txn->tid;
+	if ((txn->mt == SLIM_MSG_MT_CORE) &&
+		((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
+		txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
+		(txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
+		 txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
+		*(puc++) = (txn->ec & 0xFF);
+		*(puc++) = (txn->ec >> 8)&0xFF;
+	}
+	if (txn->wbuf)
+		memcpy(puc, txn->wbuf, txn->len);
+	if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
+		(txn->mc == SLIM_USR_MC_CONNECT_SRC ||
+		 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
+		 txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
+		wbuf[0] == dev->pgdla) {
+		if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
+			dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
+		else {
+			struct msm_slim_endp *endpoint = &dev->pipes[wbuf[1]];
+			struct sps_register_event sps_event;
+			memset(&sps_event, 0, sizeof(sps_event));
+			sps_register_event(endpoint->sps, &sps_event);
+			sps_disconnect(endpoint->sps);
+			/*
+			 * Remove channel disconnects master-side ports from
+			 * channel. No need to send that again on the bus
+			 */
+			dev->pipes[wbuf[1]].connected = false;
+			mutex_unlock(&dev->tx_lock);
+			if (msgv >= 0)
+				msm_slim_put_ctrl(dev);
+			return 0;
+		}
+		if (dev->err) {
+			dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
+			goto ngd_xfer_err;
+		}
+	}
+	dev->err = 0;
+	dev->wr_comp = &tx_sent;
+	ret = msm_send_msg_buf(dev, pbuf, txn->rl,
+			NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
+	if (!ret) {
+		int timeout = wait_for_completion_timeout(&tx_sent, HZ);
+		if (!timeout)
+			ret = -ETIMEDOUT;
+		else
+			ret = dev->err;
+	}
+	dev->wr_comp = NULL;
+	if (ret) {
+		u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
+		void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
+							dev->ver);
+		dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
+				txn->mc, txn->mt, ret, dev->ver);
+		conf = readl_relaxed(ngd);
+		stat = readl_relaxed(ngd + NGD_STATUS);
+		rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
+		int_stat = readl_relaxed(ngd + NGD_INT_STAT);
+		int_en = readl_relaxed(ngd + NGD_INT_EN);
+		int_clr = readl_relaxed(ngd + NGD_INT_CLR);
+
+		pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
+		pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
+						int_en, int_clr);
+	} else if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
+		(txn->mc == SLIM_USR_MC_CONNECT_SRC ||
+		 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
+		 txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
+		int timeout;
+		mutex_unlock(&dev->tx_lock);
+		if (msgv >= 0)
+			msm_slim_put_ctrl(dev);
+		timeout = wait_for_completion_timeout(txn->comp, HZ);
+		if (!timeout) {
+			pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
+					txn->tid);
+			ret = -ETIMEDOUT;
+		} else {
+			ret = txn->ec;
+		}
+		if (ret)
+			pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
+					txn->tid, ret);
+		return ret ? ret : dev->err;
+	}
+ngd_xfer_err:
+	mutex_unlock(&dev->tx_lock);
+	if (msgv >= 0)
+		msm_slim_put_ctrl(dev);
+	return ret ? ret : dev->err;
+}
+
+static int ngd_xferandwait_ack(struct slim_controller *ctrl,
+				struct slim_msg_txn *txn)
+{
+	int ret = ngd_xfer_msg(ctrl, txn);
+	if (!ret) {
+		int timeout;
+		timeout = wait_for_completion_timeout(txn->comp, HZ);
+		if (!timeout) {
+			pr_err("master req:0x%x, tid:%d timed out", txn->mc,
+					txn->tid);
+			ret = -ETIMEDOUT;
+		} else {
+			ret = txn->ec;
+		}
+	}
+	if (ret)
+		pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
+				txn->tid, ret);
+
+	return ret;
+}
+
+static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
+{
+	int ret;
+	struct slim_pending_ch *pch;
+	struct slim_msg_txn txn;
+	struct slim_controller *ctrl = sb->ctrl;
+	DECLARE_COMPLETION_ONSTACK(done);
+	u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+
+	txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+	txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+	txn.la = SLIM_LA_MGR;
+	txn.len = 0;
+	txn.ec = 0;
+	txn.wbuf = wbuf;
+	txn.rbuf = NULL;
+
+	list_for_each_entry(pch, &sb->mark_define, pending) {
+		struct slim_ich *slc;
+		slc = &ctrl->chans[pch->chan];
+		if (!slc) {
+			pr_err("no channel in define?");
+			return -ENXIO;
+		}
+		if (txn.len == 0) {
+			wbuf[txn.len++] = (u8) (slc->prop.dataf << 5) |
+					sb->laddr;
+			wbuf[txn.len] = slc->seglen;
+			if (slc->coeff == SLIM_COEFF_3)
+				wbuf[txn.len] |= 1 << 5;
+			wbuf[txn.len++] |= slc->prop.auxf << 6;
+			wbuf[txn.len++] = slc->rootexp << 4 | slc->prop.prot;
+			wbuf[txn.len++] = slc->prrate;
+			ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
+			if (ret) {
+				pr_err("no tid for channel define?");
+				return -ENXIO;
+			}
+		}
+		wbuf[txn.len++] = slc->chan;
+	}
+	if (txn.len) {
+		txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
+		txn.rl = txn.len + 4;
+		ret = ngd_xferandwait_ack(ctrl, &txn);
+		if (ret)
+			return ret;
+
+		txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+		txn.len = 2;
+		wbuf[1] = sb->laddr;
+		txn.rl = txn.len + 4;
+		ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+		if (ret)
+			return ret;
+		ret = ngd_xferandwait_ack(ctrl, &txn);
+		if (ret)
+			return ret;
+	}
+	txn.len = 0;
+	list_for_each_entry(pch, &sb->mark_removal, pending) {
+		struct slim_ich *slc;
+		slc = &ctrl->chans[pch->chan];
+		if (!slc) {
+			pr_err("no channel in removal?");
+			return -ENXIO;
+		}
+		if (txn.len == 0) {
+			wbuf[txn.len++] = (u8) (SLIM_CH_REMOVE << 6) |
+					sb->laddr;
+			ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
+			if (ret) {
+				pr_err("no tid for channel define?");
+				return -ENXIO;
+			}
+		}
+		wbuf[txn.len++] = slc->chan;
+	}
+	if (txn.len) {
+		txn.mc = SLIM_USR_MC_CHAN_CTRL;
+		txn.rl = txn.len + 4;
+		ret = ngd_xferandwait_ack(ctrl, &txn);
+		if (ret)
+			return ret;
+
+		txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+		txn.len = 2;
+		wbuf[1] = sb->laddr;
+		txn.rl = txn.len + 4;
+		ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+		if (ret)
+			return ret;
+		ret = ngd_xferandwait_ack(ctrl, &txn);
+		if (ret)
+			return ret;
+		txn.len = 0;
+	}
+	return ret;
+}
+
+static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
+				u8 elen, u8 laddr)
+{
+	return 0;
+}
+
+static int ngd_get_laddr(struct slim_controller *ctrl, const u8 *ea,
+				u8 elen, u8 *laddr)
+{
+	int ret;
+	u8 wbuf[10];
+	struct slim_msg_txn txn;
+	DECLARE_COMPLETION_ONSTACK(done);
+	txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+	txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+	txn.la = SLIM_LA_MGR;
+	txn.ec = 0;
+	mutex_lock(&ctrl->m_ctrl);
+	ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+	if (ret) {
+		mutex_unlock(&ctrl->m_ctrl);
+		return ret;
+	}
+	memcpy(&wbuf[1], ea, elen);
+	txn.mc = SLIM_USR_MC_ADDR_QUERY;
+	txn.rl = 11;
+	txn.len = 7;
+	txn.wbuf = wbuf;
+	txn.rbuf = NULL;
+	ret = ngd_xferandwait_ack(ctrl, &txn);
+	if (!ret && txn.la == 0xFF)
+		ret = -ENXIO;
+	else if (!ret)
+		*laddr = txn.la;
+	mutex_unlock(&ctrl->m_ctrl);
+	return ret;
+}
+
+static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
+{
+	u8 mc, mt, len;
+	int ret;
+	u32 msgq_en = 1;
+
+	len = buf[0] & 0x1F;
+	mt = (buf[0] >> 5) & 0x7;
+	mc = buf[1];
+	if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
+		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
+		struct slim_msg_txn txn;
+		u8 wbuf[8];
+		txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+		txn.ec = 0;
+		txn.rbuf = NULL;
+		txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
+		txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
+		txn.la = SLIM_LA_MGR;
+		txn.rl = 8;
+		wbuf[0] = SAT_MAGIC_LSB;
+		wbuf[1] = SAT_MAGIC_MSB;
+		wbuf[2] = SAT_MSG_VER;
+		wbuf[3] = SAT_MSG_PROT;
+		txn.wbuf = wbuf;
+		txn.len = 4;
+		dev->use_rx_msgqs = 1;
+		msm_slim_sps_init(dev, dev->bam_mem,
+			NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS, true);
+		if (dev->use_rx_msgqs)
+			msgq_en |= NGD_CFG_RX_MSGQ_EN;
+		writel_relaxed(msgq_en, dev->base +
+				NGD_BASE(dev->ctrl.nr, dev->ver));
+		/* make sure NGD MSG-Q config goes through */
+		mb();
+
+		ret = ngd_xfer_msg(&dev->ctrl, &txn);
+		if (!ret) {
+			dev->state = MSM_CTRL_AWAKE;
+			complete(&dev->reconf);
+		}
+	}
+	if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
+			mc == SLIM_MSG_MC_REPLY_VALUE) {
+		u8 tid = buf[3];
+		dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len);
+		slim_msg_response(&dev->ctrl, &buf[4], tid,
+					len - 4);
+		pm_runtime_mark_last_busy(dev->dev);
+	}
+	if (mc == SLIM_USR_MC_ADDR_REPLY &&
+		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
+		struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
+		u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
+		if (!txn)
+			return;
+		if (memcmp(&buf[4], failed_ea, 6))
+			txn->la = buf[10];
+		dev->ctrl.txnt[buf[3]] = NULL;
+		complete(txn->comp);
+	}
+	if (mc == SLIM_USR_MC_GENERIC_ACK &&
+		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
+		struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
+		if (!txn)
+			return;
+		dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
+				(int)buf[3], buf[4]);
+		if (!(buf[4] & MSM_SAT_SUCCSS)) {
+			dev_err(dev->dev, "TID:%d, NACK code:0x%x", (int)buf[3],
+						buf[4]);
+			txn->ec = -EIO;
+		}
+		dev->ctrl.txnt[buf[3]] = NULL;
+		complete(txn->comp);
+	}
+}
+static int ngd_slim_rx_msgq_thread(void *data)
+{
+	struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
+	struct completion *notify = &dev->rx_msgq_notify;
+	int ret = 0, index = 0;
+	u32 mc = 0;
+	u32 mt = 0;
+	u32 buffer[10];
+	u8 msg_len = 0;
+
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		ret = wait_for_completion_interruptible(notify);
+		if (ret) {
+			dev_err(dev->dev, "rx thread wait err:%d", ret);
+			continue;
+		}
+		/* 1 irq notification per message */
+		if (!dev->use_rx_msgqs) {
+			msm_slim_rx_dequeue(dev, (u8 *)buffer);
+			ngd_slim_rx(dev, (u8 *)buffer);
+			continue;
+		}
+		ret = msm_slim_rx_msgq_get(dev, buffer, index);
+		if (ret) {
+			dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
+			continue;
+		}
+
+		/* Wait for complete message */
+		if (index++ == 0) {
+			msg_len = *buffer & 0x1F;
+			mt = (buffer[0] >> 5) & 0x7;
+			mc = (buffer[0] >> 8) & 0xff;
+			dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
+		}
+		if ((index * 4) >= msg_len) {
+			index = 0;
+			ngd_slim_rx(dev, (u8 *)buffer);
+		} else
+			continue;
+	}
+	return 0;
+}
+
+static int __devinit ngd_slim_probe(struct platform_device *pdev)
+{
+	struct msm_slim_ctrl *dev;
+	int ret;
+	struct resource		*bam_mem;
+	struct resource		*slim_mem;
+	struct resource		*irq, *bam_irq;
+	enum apr_subsys_state q6_state;
+	u32 ngd_int;
+
+	q6_state = apr_get_q6_state();
+	if (q6_state == APR_SUBSYS_DOWN) {
+		dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
+			q6_state);
+		return -EPROBE_DEFER;
+	} else
+		dev_dbg(&pdev->dev, "adsp is ready\n");
+
+	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"slimbus_physical");
+	if (!slim_mem) {
+		dev_err(&pdev->dev, "no slimbus physical memory resource\n");
+		return -ENODEV;
+	}
+	bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"slimbus_bam_physical");
+	if (!bam_mem) {
+		dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
+		return -ENODEV;
+	}
+	irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"slimbus_irq");
+	if (!irq) {
+		dev_err(&pdev->dev, "no slimbus IRQ resource\n");
+		return -ENODEV;
+	}
+	bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"slimbus_bam_irq");
+	if (!bam_irq) {
+		dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
+		return -ENODEV;
+	}
+
+	dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
+	if (IS_ERR(dev)) {
+		dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
+		return PTR_ERR(dev);
+	}
+	dev->dev = &pdev->dev;
+	platform_set_drvdata(pdev, dev);
+	slim_set_ctrldata(&dev->ctrl, dev);
+	dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
+	if (!dev->base) {
+		dev_err(&pdev->dev, "IOremap failed\n");
+		ret = -ENOMEM;
+		goto err_ioremap_failed;
+	}
+	dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
+	if (!dev->bam.base) {
+		dev_err(&pdev->dev, "BAM IOremap failed\n");
+		ret = -ENOMEM;
+		goto err_ioremap_bam_failed;
+	}
+	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_ctrl_failed;
+		}
+	} else {
+		dev->ctrl.nr = pdev->id;
+	}
+	dev->ctrl.nchans = MSM_SLIM_NCHANS;
+	dev->ctrl.nports = MSM_SLIM_NPORTS;
+	dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
+	dev->framer.superfreq =
+		dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
+	dev->ctrl.a_framer = &dev->framer;
+	dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
+	dev->ctrl.set_laddr = ngd_set_laddr;
+	dev->ctrl.get_laddr = ngd_get_laddr;
+	dev->ctrl.allocbw = ngd_allocbw;
+	dev->ctrl.xfer_msg = ngd_xfer_msg;
+	dev->ctrl.wakeup =  NULL;
+	dev->ctrl.config_port = msm_config_port;
+	dev->ctrl.port_xfer = msm_slim_port_xfer;
+	dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
+	/* Reserve some messaging BW for satellite-apps driver communication */
+	dev->ctrl.sched.pending_msgsl = 30;
+	dev->bam_mem = bam_mem;
+
+	init_completion(&dev->reconf);
+	mutex_init(&dev->tx_lock);
+	spin_lock_init(&dev->rx_lock);
+	dev->ee = 1;
+	dev->irq = irq->start;
+	dev->bam.irq = bam_irq->start;
+
+	dev->ver = readl_relaxed(dev->base);
+	/* Version info in 16 MSbits */
+	dev->ver >>= 16;
+	ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
+			NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
+			NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
+			NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
+	init_completion(&dev->rx_msgq_notify);
+
+	/* Register with framework */
+	ret = slim_add_numbered_controller(&dev->ctrl);
+	if (ret) {
+		dev_err(dev->dev, "error adding controller\n");
+		goto err_ctrl_failed;
+	}
+
+	dev->ctrl.dev.parent = &pdev->dev;
+	dev->ctrl.dev.of_node = pdev->dev.of_node;
+	dev->state = MSM_CTRL_ASLEEP;
+
+	ret = request_irq(dev->irq, ngd_slim_interrupt,
+			IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
+
+	if (ret) {
+		dev_err(&pdev->dev, "request IRQ failed\n");
+		goto err_request_irq_failed;
+	}
+
+	/* Fire up the Rx message queue thread */
+	dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
+					NGD_SLIM_NAME "_ngd_msgq_thread");
+	if (IS_ERR(dev->rx_msgq_thread)) {
+		ret = PTR_ERR(dev->rx_msgq_thread);
+		dev_err(dev->dev, "Failed to start Rx message queue thread\n");
+		goto err_thread_create_failed;
+	}
+
+	writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
+				NGD_BASE(dev->ctrl.nr, dev->ver));
+	/*
+	 * Enable NGD. Configure NGD in register access mode until master
+	 * announcement is received
+	 */
+	writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+	/* make sure NGD enabling goes through */
+	mb();
+
+	if (pdev->dev.of_node)
+		of_register_slim_devices(&dev->ctrl);
+
+	/* Add devices registered with board-info now that controller is up */
+	slim_ctrl_add_boarddevs(&dev->ctrl);
+
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
+	pm_runtime_set_active(&pdev->dev);
+
+	dev_dbg(dev->dev, "NGD SB controller is up!\n");
+	return 0;
+
+err_thread_create_failed:
+	free_irq(dev->irq, dev);
+err_request_irq_failed:
+	slim_del_controller(&dev->ctrl);
+err_ctrl_failed:
+	iounmap(dev->bam.base);
+err_ioremap_bam_failed:
+	iounmap(dev->base);
+err_ioremap_failed:
+	kfree(dev);
+	return ret;
+}
+
+static int __devexit ngd_slim_remove(struct platform_device *pdev)
+{
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+	free_irq(dev->irq, dev);
+	slim_del_controller(&dev->ctrl);
+	kthread_stop(dev->rx_msgq_thread);
+	iounmap(dev->bam.base);
+	iounmap(dev->base);
+	kfree(dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int ngd_slim_runtime_idle(struct device *device)
+{
+	dev_dbg(device, "pm_runtime: idle...\n");
+	pm_request_autosuspend(device);
+	return -EAGAIN;
+}
+#endif
+
+/*
+ * If PM_RUNTIME is not defined, these 2 functions become helper
+ * functions to be called from system suspend/resume. So they are not
+ * inside ifdef CONFIG_PM_RUNTIME
+ */
+#ifdef CONFIG_PM_SLEEP
+static int ngd_slim_runtime_suspend(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	int ret;
+	dev_dbg(device, "pm_runtime: suspending...\n");
+	dev->state = MSM_CTRL_SLEEPING;
+	ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
+	if (ret) {
+		dev_err(device, "clk pause not entered:%d", ret);
+		dev->state = MSM_CTRL_AWAKE;
+	} else {
+		dev->state = MSM_CTRL_ASLEEP;
+	}
+	return ret;
+}
+
+static int ngd_slim_runtime_resume(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	int ret = 0;
+	dev_dbg(device, "pm_runtime: resuming...\n");
+	if (dev->state == MSM_CTRL_ASLEEP)
+		ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
+	if (ret) {
+		dev_err(device, "clk pause not exited:%d", ret);
+		dev->state = MSM_CTRL_ASLEEP;
+	} else {
+		dev->state = MSM_CTRL_AWAKE;
+	}
+	return ret;
+}
+
+static int ngd_slim_suspend(struct device *dev)
+{
+	int ret = -EBUSY;
+	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+		dev_dbg(dev, "system suspend");
+		ret = ngd_slim_runtime_suspend(dev);
+	}
+	if (ret == -EBUSY) {
+		/*
+		* There is a possibility that some audio stream is active
+		* during suspend. We dont want to return suspend failure in
+		* that case so that display and relevant components can still
+		* go to suspend.
+		* If there is some other error, then it should be passed-on
+		* to system level suspend
+		*/
+		ret = 0;
+	}
+	return ret;
+}
+
+static int ngd_slim_resume(struct device *dev)
+{
+	/* If runtime_pm is enabled, this resume shouldn't do anything */
+	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+		int ret;
+		dev_dbg(dev, "system resume");
+		ret = ngd_slim_runtime_resume(dev);
+		if (!ret) {
+			pm_runtime_mark_last_busy(dev);
+			pm_request_autosuspend(dev);
+		}
+		return ret;
+
+	}
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops ngd_slim_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(
+		ngd_slim_suspend,
+		ngd_slim_resume
+	)
+	SET_RUNTIME_PM_OPS(
+		ngd_slim_runtime_suspend,
+		ngd_slim_runtime_resume,
+		ngd_slim_runtime_idle
+	)
+};
+
+static struct of_device_id ngd_slim_dt_match[] = {
+	{
+		.compatible = "qcom,slim-ngd",
+	},
+	{}
+};
+
+static struct platform_driver ngd_slim_driver = {
+	.probe = ngd_slim_probe,
+	.remove = ngd_slim_remove,
+	.driver	= {
+		.name = NGD_SLIM_NAME,
+		.owner = THIS_MODULE,
+		.pm = &ngd_slim_dev_pm_ops,
+		.of_match_table = ngd_slim_dt_match,
+	},
+};
+
+static int ngd_slim_init(void)
+{
+	return platform_driver_register(&ngd_slim_driver);
+}
+late_initcall(ngd_slim_init);
+
+static void ngd_slim_exit(void)
+{
+	platform_driver_unregister(&ngd_slim_driver);
+}
+module_exit(ngd_slim_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM Slimbus controller");
+MODULE_ALIAS("platform:msm-slim-ngd");
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 35bb040..7d50620 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -167,6 +167,7 @@
 	struct device		*dev;
 	void __iomem		*base;
 	struct resource		*slew_mem;
+	struct resource		*bam_mem;
 	u32			curr_bw;
 	u8			msg_cnt;
 	u32			tx_buf[10];
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index a4c7131..92cbe6f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -844,9 +844,14 @@
 		motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
 	dcp = motg->chg_type == USB_DCP_CHARGER;
 
-	/* charging detection in progress due to cable plug-in */
-	if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
-		!dcp) {
+	/*
+	 * Abort suspend when,
+	 * 1. charging detection in progress due to cable plug-in
+	 * 2. host mode activation in progress due to Micro-A cable insertion
+	 */
+
+	if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
+		!dcp) || test_bit(A_BUS_REQ, &motg->inputs)) {
 		enable_irq(motg->irq);
 		return -EBUSY;
 	}
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 712d41b..c7f9e55 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2873,7 +2873,7 @@
 		pdata->on = mdp4_dtv_on;
 		pdata->off = mdp4_dtv_off;
 		mfd->hw_refresh = TRUE;
-		mfd->cursor_update = mdp_hw_cursor_update;
+		mfd->cursor_update = mdp_hw_cursor_sync_update;
 		mfd->dma_fnc = mdp4_dtv_overlay;
 		mfd->dma = &dma_e_data;
 		mfd->do_histogram = mdp_do_histogram;
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 516722e..ee9ca3c 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -630,6 +630,7 @@
 		if (panel & MDP4_PANEL_ATV)
 			mdp4_overlay1_done_atv();
 #endif
+		mdp_hw_cursor_done();
 	}
 #if defined(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL)
 	if (isr & INTR_OVERLAY2_DONE) {
diff --git a/drivers/video/msm/mdp_cursor.c b/drivers/video/msm/mdp_cursor.c
index f8c08e3..b5930a1 100644
--- a/drivers/video/msm/mdp_cursor.c
+++ b/drivers/video/msm/mdp_cursor.c
@@ -52,7 +52,11 @@
 
 	/* disable vsync */
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	mdp_disable_irq(MDP_OVERLAY0_TERM);
+	if (hdmi_prim_display)
+		mdp_disable_irq(MDP_OVERLAY1_TERM);
+	else
+		mdp_disable_irq(MDP_OVERLAY0_TERM);
+
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 }
 
@@ -78,29 +82,37 @@
 	 *
 	 * Moving this code out of the ISR will cause the MDP to underrun!
 	 */
+	uint32_t base = 0;
+
+	if (hdmi_prim_display)
+		base = ((uint32_t)(MDP_BASE + 0xB0000));
+	else
+		base = ((uint32_t)(MDP_BASE + 0x90000));
+
+
 	spin_lock(&mdp_spin_lock);
 	if (sync_disabled) {
 		spin_unlock(&mdp_spin_lock);
 		return;
 	}
 
-	MDP_OUTP(MDP_BASE + 0x90044, (height << 16) | width);
-	MDP_OUTP(MDP_BASE + 0x90048, cursor_buf_phys);
+	MDP_OUTP(base + 0x44, (height << 16) | width);
+	MDP_OUTP(base + 0x48, cursor_buf_phys);
 
-	MDP_OUTP(MDP_BASE + 0x90060,
+	MDP_OUTP(base + 0x60,
 		 (transp_en << 3) | (calpha_en << 1) |
-		 (inp32(MDP_BASE + 0x90060) & 0x1));
+		 (inp32(base + 0x60) & 0x1));
 
-	MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24));
-	MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & bg_color));
-	MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & bg_color));
+	MDP_OUTP(base + 0x64, (alpha << 24));
+	MDP_OUTP(base + 0x68, (0xffffff & bg_color));
+	MDP_OUTP(base + 0x6C, (0xffffff & bg_color));
 
 	/* enable/disable the cursor as per the last request */
-	if (cursor_enabled && !(inp32(MDP_BASE + 0x90060) & (0x1)))
-		MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1);
-	else if (!cursor_enabled && (inp32(MDP_BASE + 0x90060) & (0x1)))
-		MDP_OUTP(MDP_BASE + 0x90060,
-					inp32(MDP_BASE + 0x90060) & (~0x1));
+	if (cursor_enabled && !(inp32(base + 0x60) & (0x1)))
+		MDP_OUTP(base + 0x60, inp32(base + 0x60) | 0x1);
+	else if (!cursor_enabled && (inp32(base + 0x60) & (0x1)))
+		MDP_OUTP(base + 0x60,
+					inp32(base + 0x60) & (~0x1));
 
 	/* enqueue the task to disable MDP interrupts */
 	queue_work(mdp_cursor_ctrl_wq, &mdp_cursor_ctrl_worker);
@@ -119,17 +131,26 @@
 	if (sync_disabled) {
 
 		/* cancel pending task to disable MDP interrupts */
-		if (work_pending(&mdp_cursor_ctrl_worker))
+		if (work_pending(&mdp_cursor_ctrl_worker)) {
 			cancel_work_sync(&mdp_cursor_ctrl_worker);
-		else
+		} else {
 			/* enable irq */
-			mdp_enable_irq(MDP_OVERLAY0_TERM);
+			if (hdmi_prim_display)
+				mdp_enable_irq(MDP_OVERLAY1_TERM);
+			else
+				mdp_enable_irq(MDP_OVERLAY0_TERM);
+		}
 
 		sync_disabled = 0;
 
 		/* enable vsync intr */
-		outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
-		mdp_intr_mask |= INTR_OVERLAY0_DONE;
+		if (hdmi_prim_display) {
+			outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE);
+			mdp_intr_mask |= INTR_OVERLAY1_DONE;
+		} else {
+			outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
+			mdp_intr_mask |= INTR_OVERLAY0_DONE;
+		}
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	}
 }
@@ -140,14 +161,20 @@
 	struct fb_image *img = &cursor->image;
 	unsigned long flag;
 	int sync_needed = 0, ret = 0;
+	uint32_t base = 0;
 
 	if ((img->width > MDP_CURSOR_WIDTH) ||
 	    (img->height > MDP_CURSOR_HEIGHT) ||
 	    (img->depth != 32))
 		return -EINVAL;
 
+	if (hdmi_prim_display)
+		base = ((uint32_t)(MDP_BASE + 0xB0000));
+	else
+		base = ((uint32_t)(MDP_BASE + 0x90000));
+
 	if (cursor->set & FB_CUR_SETPOS)
-		MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx);
+		MDP_OUTP(base + 0x4c, (img->dy << 16) | img->dx);
 
 	if (cursor->set & FB_CUR_SETIMAGE) {
 		ret = copy_from_user(mfd->cursor_buf, img->data,
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 9460d71..b35be75 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -22,6 +22,8 @@
 #include <linux/of_gpio.h>
 #include <linux/gpio.h>
 #include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pwm.h>
 
 #include <asm/system.h>
 #include <asm/mach-types.h>
@@ -37,15 +39,14 @@
 #define VDDA_UA_ON_LOAD		100000	/* uA units */
 #define VDDA_UA_OFF_LOAD	100		/* uA units */
 
-
 static int mdss_edp_get_base_address(struct mdss_edp_drv_pdata *edp_drv);
 static int mdss_edp_get_mmss_cc_base_address(struct mdss_edp_drv_pdata
 		*edp_drv);
 static int mdss_edp_regulator_init(struct mdss_edp_drv_pdata *edp_drv);
 static int mdss_edp_regulator_on(struct mdss_edp_drv_pdata *edp_drv);
 static int mdss_edp_regulator_off(struct mdss_edp_drv_pdata *edp_drv);
-
 static int mdss_edp_gpio_panel_en(struct mdss_edp_drv_pdata *edp_drv);
+static int mdss_edp_pwm_config(struct mdss_edp_drv_pdata *edp_drv);
 
 static void mdss_edp_edid2pinfo(struct mdss_edp_drv_pdata *edp_drv);
 static void mdss_edp_fill_edid_data(struct mdss_edp_drv_pdata *edp_drv);
@@ -134,7 +135,7 @@
 }
 
 /*
- * Enables the gpio that supply power to the panel
+ * Enables the gpio that supply power to the panel and enable the backlight
  */
 static int mdss_edp_gpio_panel_en(struct mdss_edp_drv_pdata *edp_drv)
 {
@@ -143,7 +144,8 @@
 	edp_drv->gpio_panel_en = of_get_named_gpio(edp_drv->pdev->dev.of_node,
 			"gpio-panel-en", 0);
 	if (!gpio_is_valid(edp_drv->gpio_panel_en)) {
-		pr_err("%s: gpio_panel_en not specified\n", __func__);
+		pr_err("%s: gpio_panel_en=%d not specified\n", __func__,
+				edp_drv->gpio_panel_en);
 		goto gpio_err;
 	}
 
@@ -171,7 +173,94 @@
 	return -ENODEV;
 }
 
-static void mdss_edp_config_sync(unsigned char *edp_base)
+static int mdss_edp_pwm_config(struct mdss_edp_drv_pdata *edp_drv)
+{
+	int ret = 0;
+
+	ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
+			"qcom,panel-pwm-period", &edp_drv->pwm_period);
+	if (ret) {
+		pr_err("%s: panel pwm period is not specified, %d", __func__,
+				edp_drv->pwm_period);
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
+			"qcom,panel-lpg-channel", &edp_drv->lpg_channel);
+	if (ret) {
+		pr_err("%s: panel lpg channel is not specified, %d", __func__,
+				edp_drv->lpg_channel);
+		return -EINVAL;
+	}
+
+	edp_drv->bl_pwm = pwm_request(edp_drv->lpg_channel, "lcd-backlight");
+	if (edp_drv->bl_pwm == NULL || IS_ERR(edp_drv->bl_pwm)) {
+		pr_err("%s: pwm request failed", __func__);
+		edp_drv->bl_pwm = NULL;
+		return -EIO;
+	}
+
+	edp_drv->gpio_panel_pwm = of_get_named_gpio(edp_drv->pdev->dev.of_node,
+			"gpio-panel-pwm", 0);
+	if (!gpio_is_valid(edp_drv->gpio_panel_pwm)) {
+		pr_err("%s: gpio_panel_pwm=%d not specified\n", __func__,
+				edp_drv->gpio_panel_pwm);
+		goto edp_free_pwm;
+	}
+
+	ret = gpio_request(edp_drv->gpio_panel_pwm, "disp_pwm");
+	if (ret) {
+		pr_err("%s: Request reset gpio_panel_pwm failed, ret=%d\n",
+				__func__, ret);
+		goto edp_free_gpio_pwm;
+	}
+
+	return 0;
+
+edp_free_gpio_pwm:
+	gpio_free(edp_drv->gpio_panel_pwm);
+edp_free_pwm:
+	pwm_free(edp_drv->bl_pwm);
+	return -ENODEV;
+}
+
+void mdss_edp_set_backlight(struct mdss_panel_data *pdata, u32 bl_level)
+{
+	int ret = 0;
+	struct mdss_edp_drv_pdata *edp_drv = NULL;
+	int bl_max;
+
+	edp_drv = container_of(pdata, struct mdss_edp_drv_pdata, panel_data);
+	if (!edp_drv) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	bl_max = edp_drv->panel_data.panel_info.bl_max;
+	if (bl_level > bl_max)
+		bl_level = bl_max;
+
+	if (edp_drv->bl_pwm == NULL) {
+		pr_err("%s: edp_drv->bl_pwm=NULL.\n", __func__);
+		return;
+	}
+
+	ret = pwm_config(edp_drv->bl_pwm,
+			bl_level * edp_drv->pwm_period / bl_max,
+			edp_drv->pwm_period);
+	if (ret) {
+		pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+		return;
+	}
+
+	ret = pwm_enable(edp_drv->bl_pwm);
+	if (ret) {
+		pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
+		return;
+	}
+}
+
+void mdss_edp_config_sync(unsigned char *edp_base)
 {
 	int ret = 0;
 
@@ -251,6 +340,7 @@
 		return -EINVAL;
 	}
 
+	pwm_disable(edp_drv->bl_pwm);
 	mdss_edp_enable(edp_drv->edp_base, 0);
 	mdss_edp_unconfig_clk(edp_drv->edp_base, edp_drv->mmss_cc_base);
 	mdss_edp_enable_mainlink(edp_drv->edp_base, 0);
@@ -322,9 +412,12 @@
 	int ret;
 
 	mdss_edp_edid2pinfo(edp_drv);
+	edp_drv->panel_data.panel_info.bl_min = 1;
+	edp_drv->panel_data.panel_info.bl_max = 255;
 
 	edp_drv->panel_data.on = mdss_edp_on;
 	edp_drv->panel_data.off = mdss_edp_off;
+	edp_drv->panel_data.set_backlight = mdss_edp_set_backlight;
 
 	ret = mdss_register_panel(&edp_drv->panel_data);
 	if (ret) {
@@ -468,12 +561,19 @@
 	if (ret)
 		goto edp_clk_deinit;
 
+	ret = mdss_edp_pwm_config(edp_drv);
+	if (ret)
+		goto edp_free_gpio_panel_en;
+
 	mdss_edp_fill_edid_data(edp_drv);
 	mdss_edp_fill_dpcd_data(edp_drv);
 	mdss_edp_device_register(edp_drv);
 
 	return 0;
 
+
+edp_free_gpio_panel_en:
+	gpio_free(edp_drv->gpio_panel_en);
 edp_clk_deinit:
 	mdss_edp_clk_deinit(edp_drv);
 	mdss_edp_regulator_off(edp_drv);
diff --git a/drivers/video/msm/mdss/mdss_edp.h b/drivers/video/msm/mdss/mdss_edp.h
index 72c061f..00ef206 100644
--- a/drivers/video/msm/mdss/mdss_edp.h
+++ b/drivers/video/msm/mdss/mdss_edp.h
@@ -92,6 +92,12 @@
 
 	/* gpios */
 	int gpio_panel_en;
+	int gpio_panel_pwm;
+
+	/* backlight */
+	struct pwm_device *bl_pwm;
+	int lpg_channel;
+	int pwm_period;
 };
 
 void mdss_edp_phy_sw_reset(unsigned char *edp_base);
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index f0e42c2..60fa04e 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -18,14 +18,14 @@
 #define EVENT_MASKS_TYPE		4
 #define PKT_TYPE			8
 #define DEINIT_TYPE			16
-#define USER_SPACE_LOG_TYPE		32
+#define USER_SPACE_DATA_TYPE		32
 #define DCI_DATA_TYPE			64
 #define USB_MODE			1
 #define MEMORY_DEVICE_MODE		2
 #define NO_LOGGING_MODE			3
 #define UART_MODE			4
 #define SOCKET_MODE			5
-
+#define CALLBACK_MODE			6
 /* different values that go in for diag_data_type */
 #define DATA_TYPE_EVENT         	0
 #define DATA_TYPE_F3            	1
diff --git a/include/linux/i2c/smb350.h b/include/linux/i2c/smb350.h
new file mode 100644
index 0000000..5bb5cec
--- /dev/null
+++ b/include/linux/i2c/smb350.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful;
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __SMB350_H__
+#define __SMB350_H__
+
+#define SMB350_NAME		"smb350"
+
+/**
+ * struct smb350_platform_data
+ * structure to pass board specific information to the smb137b charger driver
+ * @chg_current_ma:	maximum fast charge current in mA
+ * @term_current_ma:	charge termination current in mA
+ * @chg_en_n_gpio:	gpio to enable or disable charging
+ * @chg_susp_n_gpio:	put active low to allow chip to suspend and disable I2C
+ * @stat_gpio:		STAT pin, active low, '0' when charging.
+ */
+struct smb350_platform_data {
+	int chg_en_n_gpio;
+	int chg_susp_n_gpio;
+	int chg_current_ma;
+	int term_current_ma;
+	int stat_gpio;
+};
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 16d4a4b..130fb54 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -163,6 +163,7 @@
 	enum pm8921_chg_hot_thr		hot_thr;
 	int				rconn_mohm;
 	enum pm8921_chg_led_src_config	led_src_config;
+	int				battery_less_hardware;
 };
 
 enum pm8921_charger_source {
diff --git a/include/linux/test-iosched.h b/include/linux/test-iosched.h
index 1e428c5..b52762c 100644
--- a/include/linux/test-iosched.h
+++ b/include/linux/test-iosched.h
@@ -129,6 +129,8 @@
  * @check_test_result_fn: Test specific test result checking
  *			callback
  * @get_test_case_str_fn: Test specific function to get the test name
+ * @test_duration:	A jiffies value saved for timing
+ *			calculations
  * @data:		Test specific private data
  */
 struct test_info {
@@ -139,6 +141,7 @@
 	check_test_result_fn *check_test_result_fn;
 	post_test_fn *post_test_fn;
 	get_test_case_str_fn *get_test_case_str_fn;
+	unsigned long test_duration;
 	void *data;
 };