Merge "slim_msm: Make sure runtime PM reference count doesn't go -ve" into msm-3.0
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 860e2bf..eca2ffa 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -66,6 +66,7 @@
 CONFIG_MSM_PIL_QDSP6V4=y
 CONFIG_MSM_PIL_RIVA=y
 CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_GSS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_MODEM_8960=y
 CONFIG_MSM_LPASS_8960=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index eb4244f..18e9085 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -66,6 +66,7 @@
 CONFIG_MSM_PIL_QDSP6V4=y
 CONFIG_MSM_PIL_RIVA=y
 CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_GSS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_MODEM_8960=y
 CONFIG_MSM_LPASS_8960=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 3f04ce0..904839b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1705,6 +1705,13 @@
 	  used to decrypt data and perform secure operations on the behalf of
 	  the kernel.
 
+config MSM_PIL_GSS
+	tristate "GSS (Coretx A5) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down Cortex A5 processors which run
+	  GPS subsystem firmware.
+
 config MSM_SCM
 	bool "Secure Channel Manager (SCM) support"
 	default n
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 939b036..19a316e 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -71,6 +71,7 @@
 obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
 obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
 obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o
+obj-$(CONFIG_MSM_PIL_GSS) += pil-gss.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
 obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 23d03ef..6140559 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -369,34 +369,39 @@
 };
 
 #ifdef CONFIG_CPU_FREQ_MSM
-static struct cpufreq_frequency_table freq_table[20];
+static struct cpufreq_frequency_table freq_table[NR_CPUS][20];
 
 static void __init cpufreq_table_init(void)
 {
-	unsigned int i;
-	unsigned int freq_cnt = 0;
+	int cpu;
+	for_each_possible_cpu(cpu) {
+		unsigned int i, freq_cnt = 0;
 
-	/* Construct the freq_table table from acpu_freq_tbl since the
-	 * freq_table values need to match frequencies specified in
-	 * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init.
-	 */
-	for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0
-			&& freq_cnt < ARRAY_SIZE(freq_table)-1; i++) {
-		if (acpu_freq_tbl[i].use_for_scaling) {
-			freq_table[freq_cnt].index = freq_cnt;
-			freq_table[freq_cnt].frequency
-				= acpu_freq_tbl[i].a11clk_khz;
-			freq_cnt++;
+		/* Construct the freq_table table from acpu_freq_tbl since
+		 * the freq_table values need to match frequencies specified
+		 * in acpu_freq_tbl and acpu_freq_tbl needs to be fixed up
+		 * during init.
+		 */
+		for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0
+				&& freq_cnt < ARRAY_SIZE(*freq_table)-1; i++) {
+			if (acpu_freq_tbl[i].use_for_scaling) {
+				freq_table[cpu][freq_cnt].index = freq_cnt;
+				freq_table[cpu][freq_cnt].frequency
+					= acpu_freq_tbl[i].a11clk_khz;
+				freq_cnt++;
+			}
 		}
+
+		/* freq_table not big enough to store all usable freqs. */
+		BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0);
+
+		freq_table[cpu][freq_cnt].index = freq_cnt;
+		freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+		/* Register table with CPUFreq. */
+		cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+		pr_info("CPU%d: %d scaling frequencies supported.\n",
+			cpu, freq_cnt);
 	}
-
-	/* freq_table not big enough to store all usable freqs. */
-	BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0);
-
-	freq_table[freq_cnt].index = freq_cnt;
-	freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
-
-	pr_info("%d scaling frequencies supported.\n", freq_cnt);
 }
 #endif
 
@@ -995,7 +1000,6 @@
 
 #ifdef CONFIG_CPU_FREQ_MSM
 	cpufreq_table_init();
-	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
 #endif
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 57f4a0a..de80a3e 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -21,6 +21,7 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
+#include <mach/socinfo.h>
 #include "devices.h"
 #include "board-8064.h"
 
@@ -34,17 +35,24 @@
 /* The SPI configurations apply to GSBI 5*/
 static struct gpiomux_setting gpio_spi_config = {
 	.func = GPIOMUX_FUNC_2,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
 /* The SPI configurations apply to GSBI 5 chip select 2*/
 static struct gpiomux_setting gpio_spi_cs2_config = {
 	.func = GPIOMUX_FUNC_3,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+/* Chip selects for SPI clients */
+static struct gpiomux_setting gpio_spi_cs_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
 struct msm_gpiomux_config apq8064_ethernet_configs[] = {
 	{
 		.gpio = 43,
@@ -89,6 +97,45 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting ext_regulator_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct gpiomux_setting hsic_act_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hsic_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct msm_gpiomux_config apq8064_hsic_configs[] = {
+	{
+		.gpio = 88,               /*HSIC_STROBE */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+	{
+		.gpio = 89,               /* HSIC_DATA */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+};
+#endif
+
 static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
 	{
 		.gpio      = 18,		/* GSBI1 UART TX */
@@ -116,6 +163,12 @@
 		},
 	},
 	{
+		.gpio      = 53,		/* Funny CS0 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
 		.gpio      = 31,		/* GSBI5 QUP SPI_CS2_N */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
@@ -128,6 +181,24 @@
 		},
 	},
 #endif
+	{
+		.gpio      = 30,		/* FP CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+	{
+		.gpio      = 32,		/* EPM CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+	{
+		.gpio      = 53,		/* NOR CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config apq8064_slimbus_config[] __initdata = {
@@ -185,6 +256,78 @@
 	},
 };
 
+/* External 3.3 V regulator enable */
+static struct msm_gpiomux_config apq8064_ext_regulator_configs[] __initdata = {
+	{
+		.gpio = APQ8064_EXT_3P3V_REG_EN_GPIO,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ext_regulator_config,
+		},
+	},
+};
+
+static struct gpiomux_setting ap2mdm_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_pon_reset_n_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+	/* AP2MDM_STATUS */
+	{
+		.gpio = 48,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 49,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+		}
+	},
+	/* MDM2AP_ERRFATAL */
+	{
+		.gpio = 19,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+		}
+	},
+	/* AP2MDM_ERRFATAL */
+	{
+		.gpio = 18,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* AP2MDM_PON_RESET_N */
+	{
+		.gpio = 27,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_pon_reset_n_cfg,
+		}
+	}
+};
+
 void __init apq8064_init_gpiomux(void)
 {
 	int rc;
@@ -211,4 +354,16 @@
 
 	msm_gpiomux_install(apq8064_audio_auxpcm_configs,
 			ARRAY_SIZE(apq8064_audio_auxpcm_configs));
+
+	msm_gpiomux_install(apq8064_ext_regulator_configs,
+			ARRAY_SIZE(apq8064_ext_regulator_configs));
+
+	if (machine_is_apq8064_mtp())
+		msm_gpiomux_install(mdm_configs,
+			ARRAY_SIZE(mdm_configs));
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+	msm_gpiomux_install(apq8064_hsic_configs,
+			ARRAY_SIZE(apq8064_hsic_configs));
+#endif
 }
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 2182079..5204e48 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,15 +15,236 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/bootmem.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/mmc.h>
 #include <mach/msm_bus_board.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
+#include <mach/restart.h>
 #include "devices.h"
 #include "board-8064.h"
 
+struct pm8xxx_gpio_init {
+	unsigned			gpio;
+	struct pm_gpio			config;
+};
+
+struct pm8xxx_mpp_init {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8921_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8921_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8921_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8921_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8821_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8821_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8921_GPIO_DISABLE(_gpio) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+			 0, 0, 0, 1)
+
+#define PM8921_GPIO_OUTPUT(_gpio, _val, _strength) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_##_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8921_GPIO_INPUT(_gpio, _pull) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8921_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8921_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8921 GPIO configurations */
+static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
+};
+
+/* Initial PM8XXX MPP configurations */
+static struct pm8xxx_mpp_init pm8xxx_mpps[] __initdata = {
+	/* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
+	PM8921_MPP_INIT(7, D_INPUT, PM8921_MPP_DIG_LEVEL_VPH, DIN_TO_INT),
+};
+
+void __init apq8064_pm8xxx_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
+					&pm8921_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pm8xxx_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8xxx_mpps[i].mpp,
+					&pm8xxx_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
+static struct pm8xxx_pwrkey_platform_data apq8064_pm8921_pwrkey_pdata = {
+	.pull_up		= 1,
+	.kpd_trigger_delay_us	= 15625,
+	.wakeup			= 1,
+};
+
+static struct pm8xxx_misc_platform_data apq8064_pm8921_misc_pdata = {
+	.priority		= 0,
+};
+
+#define PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
+#define PM8921_LC_LED_LOW_CURRENT	1	/* I = 1mA */
+#define PM8XXX_LED_PWM_PERIOD		1000
+#define PM8XXX_LED_PWM_DUTY_MS		20
+/**
+ * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be
+ * driven using PWM feature.
+ */
+#define PM8XXX_PWM_CHANNEL_NONE		-1
+
+static struct led_info pm8921_led_info[] = {
+	[0] = {
+		.name			= "led:red",
+		.default_trigger	= "ac-online",
+	},
+};
+
+static struct led_platform_data pm8921_led_core_pdata = {
+	.num_leds = ARRAY_SIZE(pm8921_led_info),
+	.leds = pm8921_led_info,
+};
+
+static int pm8921_led0_pwm_duty_pcts[56] = {
+	1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+	40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+	80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+	92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+	58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+	14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
+	.duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
+	.num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
+	.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+	.start_idx = 0,
+};
+
+static struct pm8xxx_led_config pm8921_led_configs[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_0,
+		.mode = PM8XXX_LED_MODE_PWM2,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+		.pwm_channel = 5,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8921_led0_pwm_duty_cycles,
+	},
+};
+
+static struct pm8xxx_led_platform_data apq8064_pm8921_leds_pdata = {
+		.led_core = &pm8921_led_core_pdata,
+		.configs = pm8921_led_configs,
+		.num_configs = ARRAY_SIZE(pm8921_led_configs),
+};
+
+static struct pm8xxx_adc_amux apq8064_pm8921_adc_channels_data[] = {
+	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+	{"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+	{"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+};
+
+static struct pm8xxx_adc_properties apq8064_pm8921_adc_data = {
+	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
+	.bitresolution		= 15,
+	.bipolar                = 0,
+};
+
+static struct pm8xxx_adc_platform_data apq8064_pm8921_adc_pdata = {
+	.adc_channel		= apq8064_pm8921_adc_channels_data,
+	.adc_num_board_channel	= ARRAY_SIZE(apq8064_pm8921_adc_channels_data),
+	.adc_prop		= &apq8064_pm8921_adc_data,
+	.adc_mpp_base		= PM8921_MPP_PM_TO_SYS(1),
+};
 
 static struct pm8xxx_mpp_platform_data
 apq8064_pm8921_mpp_pdata __devinitdata = {
@@ -49,6 +270,48 @@
 	.rtc_alarm_powerup      = false,
 };
 
+static int apq8064_pm8921_therm_mitigation[] = {
+	1100,
+	700,
+	600,
+	325,
+};
+
+#define MAX_VOLTAGE_MV          4200
+static struct pm8921_charger_platform_data
+apq8064_pm8921_chg_pdata __devinitdata = {
+	.safety_time		= 180,
+	.update_time		= 60000,
+	.max_voltage		= MAX_VOLTAGE_MV,
+	.min_voltage		= 3200,
+	.resume_voltage_delta	= 100,
+	.term_current		= 100,
+	.cool_temp		= 10,
+	.warm_temp		= 40,
+	.temp_check_period	= 1,
+	.max_bat_chg_current	= 1100,
+	.cool_bat_chg_current	= 350,
+	.warm_bat_chg_current	= 350,
+	.cool_bat_voltage	= 4100,
+	.warm_bat_voltage	= 4100,
+	.thermal_mitigation	= apq8064_pm8921_therm_mitigation,
+	.thermal_levels		= ARRAY_SIZE(apq8064_pm8921_therm_mitigation),
+};
+
+static struct pm8xxx_ccadc_platform_data
+apq8064_pm8xxx_ccadc_pdata = {
+	.r_sense		= 10,
+};
+
+static struct pm8921_bms_platform_data
+apq8064_pm8921_bms_pdata __devinitdata = {
+	.r_sense		= 10,
+	.i_test			= 2500,
+	.v_failure		= 3000,
+	.calib_delay_ms		= 600000,
+	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+};
+
 static struct pm8921_platform_data
 apq8064_pm8921_platform_data __devinitdata = {
 	.regulator_pdatas	= msm8064_pm8921_regulator_pdata,
@@ -56,12 +319,19 @@
 	.gpio_pdata		= &apq8064_pm8921_gpio_pdata,
 	.mpp_pdata		= &apq8064_pm8921_mpp_pdata,
 	.rtc_pdata		= &apq8064_pm8921_rtc_pdata,
+	.pwrkey_pdata		= &apq8064_pm8921_pwrkey_pdata,
+	.misc_pdata		= &apq8064_pm8921_misc_pdata,
+	.leds_pdata		= &apq8064_pm8921_leds_pdata,
+	.adc_pdata		= &apq8064_pm8921_adc_pdata,
+	.charger_pdata		= &apq8064_pm8921_chg_pdata,
+	.bms_pdata		= &apq8064_pm8921_bms_pdata,
+	.ccadc_pdata		= &apq8064_pm8xxx_ccadc_pdata,
 };
 
 static struct pm8xxx_irq_platform_data
 apq8064_pm8821_irq_pdata __devinitdata = {
 	.irq_base		= PM8821_IRQ_BASE,
-	.devirq			= PM8821_USR_IRQ_N,
+	.devirq			= PM8821_SEC_IRQ_N,
 	.irq_trigger_flag	= IRQF_TRIGGER_HIGH,
 	.dev_id			= 1,
 };
@@ -95,6 +365,8 @@
 
 void __init apq8064_init_pmic(void)
 {
+	pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ;
+
 	apq8064_device_ssbi_pmic1.dev.platform_data =
 						&apq8064_ssbi_pm8921_pdata;
 	apq8064_device_ssbi_pmic2.dev.platform_data =
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 7267f96..f3eebce 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -129,6 +129,7 @@
 	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
 	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_ehci_host.0"),
 	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_ehci_host.1"),
+	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_host"),
 	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(S4) = {
@@ -179,6 +180,7 @@
 };
 VREG_CONSUMERS(USB_OTG) = {
 	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
 };
 VREG_CONSUMERS(HDMI_MVS) = {
 	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
@@ -194,6 +196,14 @@
 	REGULATOR_SUPPLY("8821_s1",		NULL),
 	REGULATOR_SUPPLY("krait3",		NULL),
 };
+VREG_CONSUMERS(EXT_5V) = {
+	REGULATOR_SUPPLY("ext_5v",		NULL),
+};
+VREG_CONSUMERS(EXT_3P3V) = {
+	REGULATOR_SUPPLY("ext_3p3v",		NULL),
+	REGULATOR_SUPPLY("vdd_io",		"spi0.2"),
+	REGULATOR_SUPPLY("mhl_ext_3p3v",	"msm_otg"),
+};
 
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
 			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
@@ -290,6 +300,22 @@
 		.pin_ctrl	= _pin_ctrl, \
 	}
 
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
+	[GPIO_VREG_ID_##_id] = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.regulator_name = _reg_name, \
+		.gpio_label	= _gpio_label, \
+		.gpio		= _gpio, \
+	}
+
 #define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
 	{ \
 		.constraints = { \
@@ -302,6 +328,15 @@
 		.consumer_supplies	= vreg_consumers_##_id, \
 	}
 
+/* GPIO regulator constraints */
+struct gpio_regulator_platform_data
+apq8064_gpio_regulator_pdata[] __devinitdata = {
+	/*        ID      vreg_name gpio_label   gpio                  supply */
+	GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7), NULL),
+	GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
+		  APQ8064_EXT_3P3V_REG_EN_GPIO, NULL),
+};
+
 /* SAW regulator constraints */
 struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
 	/*	      ID  vreg_name	       min_uV   max_uV */
@@ -329,7 +364,7 @@
 		3),
 	PM8XXX_SMPS(S4, "8921_s4",  1, 1, 1800000, 1800000, 500, NULL, 100000,
 		4),
-	PM8XXX_SMPS(S7, "8921_s7",  0, 1, 1200000, 1200000, 500, NULL, 100000,
+	PM8XXX_SMPS(S7, "8921_s7",  0, 1, 1300000, 1300000, 500, NULL, 100000,
 		5),
 
 	PM8XXX_LDO(L1,  "8921_l1",  1, 1, 1100000, 1100000, 200, "8921_s4", 0,
@@ -337,10 +372,11 @@
 	PM8XXX_LDO(L2,  "8921_l2",  0, 1, 1200000, 1200000, 200, "8921_s4", 0,
 		7),
 	PM8XXX_LDO(L3,  "8921_l3",  0, 1, 3075000, 3075000, 200, NULL, 0, 8),
-	PM8XXX_LDO(L4,  "8921_l4",  1, 1, 1800000, 1800000, 200, NULL, 0, 9),
+	PM8XXX_LDO(L4,  "8921_l4",  1, 1, 1800000, 1800000, 200, NULL, 10000,
+		9),
 	PM8XXX_LDO(L5,  "8921_l5",  0, 1, 2950000, 2950000, 200, NULL, 0, 10),
 	PM8XXX_LDO(L6,  "8921_l6",  0, 1, 2950000, 2950000, 200, NULL, 0, 11),
-	PM8XXX_LDO(L7,  "8921_l7",  1, 1, 1850000, 2950000, 200, NULL, 0, 12),
+	PM8XXX_LDO(L7,  "8921_l7",  0, 1, 1850000, 2950000, 200, NULL, 0, 12),
 	PM8XXX_LDO(L8,  "8921_l8",  0, 1, 2800000, 2800000, 200, NULL, 0, 13),
 	PM8XXX_LDO(L9,  "8921_l9",  0, 1, 2850000, 2850000, 200, NULL, 0, 14),
 	PM8XXX_LDO(L10, "8921_l10", 0, 1, 2900000, 2900000, 200, NULL, 0, 15),
@@ -358,10 +394,10 @@
 	PM8XXX_NLDO1200(L24, "8921_l24", 1, 1, 1150000, 1150000, 200, "8921_s1",
 		10000, 25),
 	PM8XXX_NLDO1200(L25, "8921_l25", 1, 1, 1225000, 1225000, 200, "8921_s1",
-		0, 26),
+		10000, 26),
 	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
 		0, 27),
-	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1000000, 1000000, 200, "8921_s7",
+	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1100000, 1100000, 200, "8921_s7",
 		0, 28),
 	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
 		0, 29),
@@ -375,8 +411,8 @@
 	PM8XXX_VS(LVS6,    "8921_lvs6", 0, 1,                 0, "8921_s4", 35),
 	PM8XXX_VS(LVS7,    "8921_lvs7", 1, 1,                 0, "8921_s4", 36),
 
-	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1,         0, NULL, 37),
-	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1,         0, NULL, 38),
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 0,         0, "ext_5v", 37),
+	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1,         0, "ext_5v", 38),
 
 	/*         ID   name  always_on   min_uV   max_uV  en_t supply reg_ID */
 	PM8XXX_NCP(NCP,	"8921_ncp", 0,    1800000, 1800000, 200, "8921_l6", 39),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 3e99b2a..79b4c07 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -49,8 +49,8 @@
 #include <asm/setup.h>
 #include <mach/dma.h>
 #include <mach/msm_bus_board.h>
-#include <mach/pm.h>
 #include <mach/cpuidle.h>
+#include <mach/mdm2.h>
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
@@ -58,6 +58,7 @@
 #include "spm.h"
 #include "mpm.h"
 #include "rpm_resources.h"
+#include "pm.h"
 #include "pm-boot.h"
 #include "devices-msm8x60.h"
 
@@ -374,15 +375,26 @@
 	msm_reserve();
 }
 
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct msm_hsic_host_platform_data msm_hsic_pdata = {
+	.strobe		= 88,
+	.data		= 89,
+};
+#else
+static struct msm_hsic_host_platform_data msm_hsic_pdata;
+#endif
+
 static struct platform_device android_usb_device = {
 	.name = "android_usb",
 	.id = -1,
 };
 
 static struct msm_otg_platform_data msm_otg_pdata = {
-	.mode			= USB_PERIPHERAL,
-	.otg_control		= OTG_PHY_CONTROL,
+	.mode			= USB_OTG,
+	.otg_control		= OTG_PMIC_CONTROL,
 	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
+	.pmic_id_irq		= PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
+	.power_budget		= 750,
 };
 
 #define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
@@ -567,6 +579,11 @@
 };
 #endif
 
+static struct mdm_platform_data mdm_platform_data = {
+	.mdm_version = "3.0",
+	.ramdump_delay_ms = 2000,
+	.peripheral_platform_device = &apq8064_device_hsic_host,
+};
 
 #define MSM_SHARED_RAM_PHYS 0x80000000
 static void __init apq8064_map_io(void)
@@ -1006,16 +1023,38 @@
 	msm_bus_8064_cpss_fpb.dev.platform_data = &msm_bus_8064_cpss_fpb_pdata;
 }
 
+static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_MPP_PM_TO_SYS(7),
+	.dev	= {
+		.platform_data
+			= &apq8064_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
+	},
+};
+
+static struct platform_device apq8064_device_ext_3p3v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= APQ8064_EXT_3P3V_REG_EN_GPIO,
+	.dev	= {
+		.platform_data =
+			&apq8064_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V],
+	},
+};
+
 static struct platform_device *common_devices[] __initdata = {
 	&apq8064_device_dmov,
 	&apq8064_device_qup_i2c_gsbi4,
 	&apq8064_device_qup_spi_gsbi5,
 	&apq8064_slim_ctrl,
+	&apq8064_device_ext_5v_vreg,
+	&apq8064_device_ext_3p3v_vreg,
 	&apq8064_device_ssbi_pmic1,
 	&apq8064_device_ssbi_pmic2,
 	&msm_device_smd_apq8064,
 	&apq8064_device_otg,
 	&apq8064_device_gadget_peripheral,
+	&apq8064_device_hsusb_host,
+	&apq8064_device_hsic_host,
 	&android_usb_device,
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -1078,6 +1117,7 @@
 	&msm_device_vidc,
 	&msm_8960_riva,
 	&msm_8960_q6_lpass,
+	&msm_gss,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -1099,7 +1139,7 @@
 };
 
 static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
-	.max_clock_speed = 24000000,
+	.max_clock_speed = 1100000,
 };
 
 #define KS8851_IRQ_GPIO		43
@@ -1138,7 +1178,7 @@
 					&apq8064_i2c_qup_gsbi4_pdata;
 }
 
-#ifdef CONFIG_KS8851
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static int ethernet_init(void)
 {
 	int ret;
@@ -1180,9 +1220,13 @@
 	apq8064_device_qup_spi_gsbi5.dev.platform_data =
 						&apq8064_qup_spi_gsbi5_pdata;
 	apq8064_init_pmic();
+	if (machine_is_apq8064_liquid())
+		msm_otg_pdata.mhl_enable = true;
 	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
+	apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
 	apq8064_init_buses();
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	apq8064_pm8xxx_gpio_mpp_init();
 	apq8064_init_mmc();
 	slim_register_board_info(apq8064_slim_devices,
 		ARRAY_SIZE(apq8064_slim_devices));
@@ -1195,6 +1239,10 @@
 				msm_pm_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
+	if (machine_is_apq8064_mtp()) {
+		mdm_8064_device.dev.platform_data = &mdm_platform_data;
+		platform_device_register(&mdm_8064_device);
+	}
 }
 
 static void __init apq8064_allocate_memory_regions(void)
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 4735504..e1451f5 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -13,9 +13,12 @@
 #ifndef __ARCH_ARM_MACH_MSM_BOARD_APQ8064_H
 #define __ARCH_ARM_MACH_MSM_BOARD_APQ8064_H
 
+#include <linux/regulator/gpio-regulator.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/mfd/pm8xxx/pm8821.h>
 #include <mach/msm_memtypes.h>
+#include <mach/irqs.h>
+
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
 #define PM8921_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8921_GPIO_BASE)
@@ -32,6 +35,14 @@
 
 extern int msm8064_pm8921_regulator_pdata_len __devinitdata;
 
+#define GPIO_VREG_ID_EXT_5V		0
+#define GPIO_VREG_ID_EXT_3P3V		1
+
+#define APQ8064_EXT_3P3V_REG_EN_GPIO	77
+
+extern struct gpio_regulator_platform_data
+	apq8064_gpio_regulator_pdata[] __devinitdata;
+
 extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5;
 extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6;
 extern struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0;
@@ -54,5 +65,6 @@
 void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
 
 void apq8064_init_gpu(void);
+void apq8064_pm8xxx_gpio_mpp_init(void);
 
 #endif
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index f080d50..3858e63 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -81,7 +81,7 @@
 #include "devices.h"
 #include "devices-msm8x60.h"
 #include "spm.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include "mpm.h"
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 075f358..9985b32 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -87,7 +87,7 @@
 #include "devices-msm8x60.h"
 #include "spm.h"
 #include "board-8960.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include "mpm.h"
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 9c0a80e..84a8a42 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -35,7 +35,7 @@
 #include "devices.h"
 #include "board-9615.h"
 #include <mach/cpuidle.h>
-#include <mach/pm.h>
+#include "pm.h"
 #include "acpuclock.h"
 #include "pm-boot.h"
 
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 36ab719..87fea3f 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -38,7 +38,7 @@
 #include "devices.h"
 #include "timer.h"
 #include "acpuclock.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include "spm.h"
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/machine.h>
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 5c189fe..8eb92a4 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -68,7 +68,7 @@
 #include "clock.h"
 #include "acpuclock.h"
 #include "msm-keypad-devices.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include "pm-boot.h"
 
 #ifdef CONFIG_ARCH_MSM7X25
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 0437134..d2add18 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -50,7 +50,7 @@
 #include "timer.h"
 #include "board-msm7x27a-regulator.h"
 #include "devices-msm7x2xa.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include <mach/rpc_server_handset.h>
 #include <mach/socinfo.h>
 #include "pm-boot.h"
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 3e7b7f4..e0b3c49 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -78,7 +78,7 @@
 #include <linux/usb/android.h>
 #include <mach/usbdiag.h>
 #endif
-#include <mach/pm.h>
+#include "pm.h"
 #include "pm-boot.h"
 #include "spm.h"
 #include "acpuclock.h"
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 5cb022e..29f5fac 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -89,7 +89,7 @@
 #include "devices.h"
 #include "devices-msm8x60.h"
 #include <mach/cpuidle.h>
-#include <mach/pm.h>
+#include "pm.h"
 #include "mpm.h"
 #include "spm.h"
 #include "rpm_log.h"
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 5052bb0..1222b67 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -49,7 +49,7 @@
 #include "board-msm7x27a-regulator.h"
 #include "devices.h"
 #include "devices-msm7x2xa.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include "timer.h"
 #include "pm-boot.h"
 #include "board-msm7x27a-regulator.h"
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 65aaa9a..5a77333 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -54,7 +54,7 @@
 #include "timer.h"
 #include "msm-keypad-devices.h"
 #include "acpuclock.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include "pm-boot.h"
 #include "proc_comm.h"
 #ifdef CONFIG_USB_ANDROID
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index eb3cb13..47e51a3 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -69,6 +69,7 @@
 #define PDM_CLK_NS_REG				REG(0x2CC0)
 /* 8064 name BB_PLL_ENA_APCS_REG */
 #define BB_PLL_ENA_SC0_REG			REG(0x34C0)
+#define BB_PLL_ENA_RPM_REG			REG(0x34A0)
 #define BB_PLL0_STATUS_REG			REG(0x30D8)
 #define BB_PLL5_STATUS_REG			REG(0x30F8)
 #define BB_PLL6_STATUS_REG			REG(0x3118)
@@ -364,6 +365,7 @@
 #define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
 
 static int rpm_vreg_id_vdd_dig;
+static int rpm_vreg_id_vdd_sr2_pll;
 
 enum vdd_dig_levels {
 	VDD_DIG_NONE,
@@ -399,16 +401,16 @@
 	.fmax[VDD_DIG_##l2] = (f2), \
 	.fmax[VDD_DIG_##l3] = (f3)
 
-enum vdd_l23_levels {
-	VDD_L23_OFF,
-	VDD_L23_ON
+enum vdd_sr2_pll_levels {
+	VDD_SR2_PLL_OFF,
+	VDD_SR2_PLL_ON
 };
 
-static int set_vdd_l23(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_sr2_pll(struct clk_vdd_class *vdd_class, int level)
 {
 	int rc = 0;
 	if (cpu_is_msm8960()) {
-		if (level == VDD_L23_OFF) {
+		if (level == VDD_SR2_PLL_OFF) {
 			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
 					RPM_VREG_VOTER3, 0, 0, 1);
 			if (rc)
@@ -429,14 +431,14 @@
 				rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
 						RPM_VREG_VOTER3, 0, 0, 1);
 		}
-	} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
-		if (level == VDD_L23_OFF) {
-			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23,
+	} else {
+		if (level == VDD_SR2_PLL_OFF) {
+			rc = rpm_vreg_set_voltage(rpm_vreg_id_vdd_sr2_pll,
 					RPM_VREG_VOTER3, 0, 0, 1);
 			if (rc)
 				return rc;
 		} else {
-			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23,
+			rc = rpm_vreg_set_voltage(rpm_vreg_id_vdd_sr2_pll,
 					RPM_VREG_VOTER3, 1800000, 1800000, 1);
 			if (rc)
 				return rc;
@@ -446,7 +448,7 @@
 	return rc;
 }
 
-static DEFINE_VDD_CLASS(vdd_l23, set_vdd_l23);
+static DEFINE_VDD_CLASS(vdd_sr2_pll, set_vdd_sr2_pll);
 
 /*
  * Clock Descriptions
@@ -524,8 +526,8 @@
 	.c = {
 		.dbg_name = "pll3_clk",
 		.ops = &clk_ops_pll,
-		.vdd_class = &vdd_l23,
-		.fmax[VDD_L23_ON] = ULONG_MAX,
+		.vdd_class = &vdd_sr2_pll,
+		.fmax[VDD_SR2_PLL_ON] = ULONG_MAX,
 		CLK_INIT(pll3_clk.c),
 	},
 };
@@ -3323,37 +3325,12 @@
 	F_GFX3D(200000000, pll2, 1,  4),
 	F_GFX3D(228571000, pll2, 2,  7),
 	F_GFX3D(266667000, pll2, 1,  3),
-	F_GFX3D(320000000, pll2, 2,  5),
-	F_END
-};
-
-static struct clk_freq_tbl clk_tbl_gfx3d_8960_v2[] = {
-	F_GFX3D(        0, gnd,  0,  0),
-	F_GFX3D( 27000000, pxo,  0,  0),
-	F_GFX3D( 48000000, pll8, 1,  8),
-	F_GFX3D( 54857000, pll8, 1,  7),
-	F_GFX3D( 64000000, pll8, 1,  6),
-	F_GFX3D( 76800000, pll8, 1,  5),
-	F_GFX3D( 96000000, pll8, 1,  4),
-	F_GFX3D(128000000, pll8, 1,  3),
-	F_GFX3D(145455000, pll2, 2, 11),
-	F_GFX3D(160000000, pll2, 1,  5),
-	F_GFX3D(177778000, pll2, 2,  9),
-	F_GFX3D(200000000, pll2, 1,  4),
-	F_GFX3D(228571000, pll2, 2,  7),
-	F_GFX3D(266667000, pll2, 1,  3),
 	F_GFX3D(300000000, pll3, 1,  4),
 	F_GFX3D(320000000, pll2, 2,  5),
 	F_GFX3D(400000000, pll2, 1,  2),
 	F_END
 };
 
-static unsigned long fmax_gfx3d_8960_v2[MAX_VDD_LEVELS] __initdata = {
-	[VDD_DIG_LOW]     = 128000000,
-	[VDD_DIG_NOMINAL] = 300000000,
-	[VDD_DIG_HIGH]    = 400000000
-};
-
 static struct clk_freq_tbl clk_tbl_gfx3d_8064[] = {
 	F_GFX3D(        0, gnd,   0,  0),
 	F_GFX3D( 27000000, pxo,   0,  0),
@@ -3418,8 +3395,8 @@
 	.c = {
 		.dbg_name = "gfx3d_clk",
 		.ops = &clk_ops_rcg_8960,
-		VDD_DIG_FMAX_MAP3(LOW,  128000000, NOMINAL, 266667000,
-				  HIGH, 320000000),
+		VDD_DIG_FMAX_MAP3(LOW,  128000000, NOMINAL, 300000000,
+				  HIGH, 400000000),
 		CLK_INIT(gfx3d_clk.c),
 		.depends = &gmem_axi_clk.c,
 	},
@@ -3528,12 +3505,6 @@
 	F_END
 };
 
-static unsigned long fmax_ijpeg_8960_v2[MAX_VDD_LEVELS] __initdata = {
-	[VDD_DIG_LOW]     = 110000000,
-	[VDD_DIG_NOMINAL] = 266667000,
-	[VDD_DIG_HIGH]    = 320000000
-};
-
 static unsigned long fmax_ijpeg_8064[MAX_VDD_LEVELS] __initdata = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 266667000,
@@ -3562,7 +3533,8 @@
 	.c = {
 		.dbg_name = "ijpeg_clk",
 		.ops = &clk_ops_rcg_8960,
-		VDD_DIG_FMAX_MAP2(LOW, 110000000, NOMINAL, 266667000),
+		VDD_DIG_FMAX_MAP3(LOW, 110000000, NOMINAL, 266667000,
+				  HIGH, 320000000),
 		CLK_INIT(ijpeg_clk.c),
 		.depends = &ijpeg_axi_clk.c,
 	},
@@ -4139,12 +4111,6 @@
 	F_END
 };
 
-static unsigned long fmax_vfe_8960_v2[MAX_VDD_LEVELS] __initdata = {
-	[VDD_DIG_LOW]     = 110000000,
-	[VDD_DIG_NOMINAL] = 266667000,
-	[VDD_DIG_HIGH]    = 320000000
-};
-
 static unsigned long fmax_vfe_8064[MAX_VDD_LEVELS] __initdata = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 266667000,
@@ -4173,7 +4139,8 @@
 	.c = {
 		.dbg_name = "vfe_clk",
 		.ops = &clk_ops_rcg_8960,
-		VDD_DIG_FMAX_MAP2(LOW, 110000000, NOMINAL, 266667000),
+		VDD_DIG_FMAX_MAP3(LOW, 110000000, NOMINAL, 266667000,
+				  HIGH, 320000000),
 		CLK_INIT(vfe_clk.c),
 		.depends = &vfe_axi_clk.c,
 	},
@@ -4475,6 +4442,8 @@
 static DEFINE_CLK_MEASURE(l2_m_clk);
 static DEFINE_CLK_MEASURE(krait0_m_clk);
 static DEFINE_CLK_MEASURE(krait1_m_clk);
+static DEFINE_CLK_MEASURE(krait2_m_clk);
+static DEFINE_CLK_MEASURE(krait3_m_clk);
 static DEFINE_CLK_MEASURE(q6sw_clk);
 static DEFINE_CLK_MEASURE(q6fw_clk);
 static DEFINE_CLK_MEASURE(q6_func_clk);
@@ -4661,8 +4630,8 @@
 	{ TEST_MM_HS(0x32), &csi_rdi2_clk.c },
 	{ TEST_MM_HS(0x33), &vcap_clk.c },
 	{ TEST_MM_HS(0x34), &vcap_npl_clk.c },
-	{ TEST_MM_HS(0x36), &vcap_axi_clk.c },
-	{ TEST_MM_HS(0x39), &gfx3d_axi_clk.c },
+	{ TEST_MM_HS(0x35), &vcap_axi_clk.c },
+	{ TEST_MM_HS(0x38), &gfx3d_axi_clk.c },
 
 	{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
 	{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
@@ -4677,6 +4646,8 @@
 	{ TEST_CPUL2(0x2), &l2_m_clk },
 	{ TEST_CPUL2(0x0), &krait0_m_clk },
 	{ TEST_CPUL2(0x1), &krait1_m_clk },
+	{ TEST_CPUL2(0x4), &krait2_m_clk },
+	{ TEST_CPUL2(0x5), &krait3_m_clk },
 };
 
 static struct measure_sel *find_measure_sel(struct clk *clk)
@@ -4869,6 +4840,7 @@
 	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_gss"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -4896,7 +4868,7 @@
 	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
 	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
 	CLK_LOOKUP("core_clk",		gp2_clk.c,		""),
-	CLK_LOOKUP("core_clk",		gsbi1_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi1_uart_clk.c, "msm_serial_hsl.0"),
 	CLK_LOOKUP("core_clk",		gsbi2_uart_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
@@ -4907,11 +4879,11 @@
 	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi3_qup_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi4_qup_clk.c,	""),
-	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	"spi_qsd.0"),
 	CLK_LOOKUP("core_clk",		gsbi6_qup_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi7_qup_clk.c,	""),
 	CLK_LOOKUP("core_clk",		pdm_clk.c,		""),
-	CLK_LOOKUP("pmem_clk",		pmem_clk.c,		NULL),
+	CLK_LOOKUP("mem_clk",		pmem_clk.c,		"msm_sps"),
 	CLK_DUMMY("core_clk",           PRNG_CLK,	"msm_rng.0", OFF),
 	CLK_LOOKUP("core_clk",		sdc1_clk.c,		"msm_sdcc.1"),
 	CLK_LOOKUP("core_clk",		sdc2_clk.c,		"msm_sdcc.2"),
@@ -4936,11 +4908,11 @@
 	CLK_LOOKUP("ce3_core_src_clk",	ce3_src_clk.c,		"qce.0"),
 	CLK_LOOKUP("ce3_core_src_clk",	ce3_src_clk.c,		"qcrypto.0"),
 	CLK_LOOKUP("dma_bam_pclk",	dma_bam_p_clk.c,	NULL),
-	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,	"msm_serial_hsl.0"),
 	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		""),
 	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c,		""),
 	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		""),
-	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		"spi_qsd.0"),
 	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,		""),
 	CLK_LOOKUP("iface_clk",		gsbi7_p_clk.c,		""),
 	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		""),
@@ -5049,7 +5021,7 @@
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("mdp_pclk",		mdp_p_clk.c,		""),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
-	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,		"msm_iommu"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,		"msm_vidc.0"),
@@ -5070,7 +5042,7 @@
 	CLK_LOOKUP("i2s_spkr_osr_clk",	spare_i2s_spkr_osr_clk.c, ""),
 	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		""),
 	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	""),
-	CLK_LOOKUP("audio_slimbus_clk",	audio_slimbus_clk.c,	""),
+	CLK_LOOKUP("audio_slimbus_clk",	audio_slimbus_clk.c,	NULL),
 	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	""),
 	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		""),
 	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		""),
@@ -5097,14 +5069,29 @@
 	CLK_LOOKUP("core_clk",	      usb_hsic_system_clk.c,   "msm_hsic_host"),
 	CLK_LOOKUP("iface_clk",	      usb_hsic_p_clk.c,        "msm_hsic_host"),
 
+	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		"msm_iommu.1"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.2"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.3"),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		"msm_iommu.4"),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		"msm_iommu.6"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk.c,	"msm_iommu.9"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk.c,	"msm_iommu.10"),
+	CLK_LOOKUP("core_clk",		vcap_axi_clk.c,		"msm_iommu.11"),
+
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
 	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
+	CLK_LOOKUP("krait2_mclk",	krait2_m_clk, ""),
+	CLK_LOOKUP("krait3_mclk",	krait3_m_clk, ""),
 };
 
-static struct clk_lookup msm_clocks_8960_v1[] __initdata = {
+static struct clk_lookup msm_clocks_8960[] = {
 	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_otg"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
@@ -5182,6 +5169,11 @@
 	CLK_LOOKUP("alt_core_clk",	usb_fs2_xcvr_clk.c,	""),
 	CLK_LOOKUP("sys_clk",		usb_fs2_sys_clk.c,	""),
 	CLK_LOOKUP("src_clk",		usb_fs2_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk",	      usb_hsic_hsio_cal_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("core_clk",	      usb_hsic_system_clk.c,   "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",	      usb_hsic_p_clk.c,        "msm_hsic_host"),
 	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qce.0"),
 	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qcrypto.0"),
 	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qce.0"),
@@ -5218,6 +5210,7 @@
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-006c"),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0048"),
+	CLK_LOOKUP("cam_clk",		cam2_clk.c,		NULL),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("csi_clk",		csi0_clk.c,		"msm_csid.0"),
@@ -5226,6 +5219,13 @@
 	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		"msm_ispif.0"),
 	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		NULL),
+	CLK_LOOKUP("csi_pix1_clk",	csi_pix1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi1_clk",	csi_rdi1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi2_clk",	csi_rdi2_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		NULL),
+	CLK_LOOKUP("csi2phy_timer_clk",	csi2phy_timer_clk.c,	NULL),
 	CLK_LOOKUP("csiphy_timer_src_clk",
 			   csiphy_timer_src_clk.c, "msm_csiphy.0"),
 	CLK_LOOKUP("csiphy_timer_src_clk",
@@ -5361,26 +5361,6 @@
 	CLK_LOOKUP("q6_func_clk",	q6_func_clk,  ""),
 };
 
-static struct clk_lookup msm_clocks_8960_v2[] __initdata = {
-	CLK_LOOKUP("cam_clk",		cam2_clk.c,		NULL),
-	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		NULL),
-	CLK_LOOKUP("csi_clk",		csi2_clk.c,		NULL),
-	CLK_LOOKUP("csi_pix1_clk",	csi_pix1_clk.c,		"msm_ispif.0"),
-	CLK_LOOKUP("csi_rdi1_clk",	csi_rdi1_clk.c,		"msm_ispif.0"),
-	CLK_LOOKUP("csi_rdi2_clk",	csi_rdi2_clk.c,		"msm_ispif.0"),
-	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		NULL),
-	CLK_LOOKUP("csi2phy_timer_clk",	csi2phy_timer_clk.c,	NULL),
-	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
-	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
-	CLK_LOOKUP("cal_clk",	      usb_hsic_hsio_cal_clk.c, "msm_hsic_host"),
-	CLK_LOOKUP("core_clk",	      usb_hsic_system_clk.c,   "msm_hsic_host"),
-	CLK_LOOKUP("iface_clk",	      usb_hsic_p_clk.c,        "msm_hsic_host"),
-};
-
-/* Add v2 clocks dynamically at runtime */
-static struct clk_lookup msm_clocks_8960[ARRAY_SIZE(msm_clocks_8960_v1) +
-					 ARRAY_SIZE(msm_clocks_8960_v2)];
-
 /*
  * Miscellaneous clock register initializations
  */
@@ -5430,13 +5410,12 @@
 	 */
 	/*
 	 * Initialize MM AHB registers: Enable the FPB clock and disable HW
-	 * gating on 8960v1/8064 for all clocks. Also set VFE_AHB's
+	 * gating on non-8960 for all clocks. Also set VFE_AHB's
 	 * FORCE_CORE_ON bit to prevent its memory from being collapsed when
 	 * the clock is halted. The sleep and wake-up delays are set to safe
 	 * values.
 	 */
-	if (cpu_is_msm8960() &&
-			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) {
+	if (cpu_is_msm8960()) {
 		rmwreg(0x44000000, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
 	} else {
@@ -5466,8 +5445,7 @@
 	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
 	if (cpu_is_apq8064())
 		rmwreg(0x009FE4FF, MAXI_EN5_REG, 0x01FFEFFF);
-	if (cpu_is_msm8960() &&
-			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+	if (cpu_is_msm8960())
 		rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
 	else
 		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
@@ -5593,6 +5571,11 @@
 			writel_relaxed(regval, BB_PLL8_TEST_CTL_REG);
 
 			set_fsm_mode(BB_PLL8_MODE_REG);
+
+			/* Enable PLL8 by voting from RPM */
+			regval = readl_relaxed(BB_PLL_ENA_RPM_REG);
+			regval |= BIT(8);
+			writel_relaxed(regval, BB_PLL_ENA_RPM_REG);
 		}
 		/* Check if PLL3 is active */
 		is_pll_enabled = readl_relaxed(GPLL1_STATUS_REG) & BIT(16);
@@ -5709,19 +5692,21 @@
 	}
 }
 
-struct clock_init_data msm8960_clock_init_data __initdata;
-
 /* Local clock driver initialization. */
 static void __init msm8960_clock_init(void)
 {
-	size_t num_lookups = ARRAY_SIZE(msm_clocks_8960_v1);
 
-	if (cpu_is_msm8960() || cpu_is_apq8064())
+	if (cpu_is_msm8960()) {
 		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
-	else if (cpu_is_msm8930() || cpu_is_msm8627())
+	} else if (cpu_is_apq8064()) {
+		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
+		rpm_vreg_id_vdd_sr2_pll = RPM_VREG_ID_PM8921_LVS7;
+	} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
 		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8038_S1;
-	else
+		rpm_vreg_id_vdd_sr2_pll = RPM_VREG_ID_PM8038_L23;
+	} else {
 		BUG();
+	}
 
 	xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8960");
 	if (IS_ERR(xo_pxo)) {
@@ -5734,26 +5719,6 @@
 		BUG();
 	}
 
-	if (cpu_is_msm8960() || cpu_is_msm8930()) {
-		memcpy(msm_clocks_8960, msm_clocks_8960_v1,
-				sizeof(msm_clocks_8960_v1));
-		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) {
-			gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960_v2;
-
-			memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8960_v2,
-			       sizeof(gfx3d_clk.c.fmax));
-			memcpy(ijpeg_clk.c.fmax, fmax_ijpeg_8960_v2,
-			       sizeof(ijpeg_clk.c.fmax));
-			memcpy(vfe_clk.c.fmax, fmax_vfe_8960_v2,
-			       sizeof(vfe_clk.c.fmax));
-
-			memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_v1),
-				msm_clocks_8960_v2, sizeof(msm_clocks_8960_v2));
-			num_lookups = ARRAY_SIZE(msm_clocks_8960);
-		}
-		msm8960_clock_init_data.size = num_lookups;
-	}
-
 	/*
 	 * Change the freq tables for and voltage requirements for
 	 * clocks which differ between 8960 and 8064.
@@ -5815,13 +5780,8 @@
 	rcg_clk_disable(&pdm_clk.c);
 	rcg_clk_enable(&tssc_clk.c);
 	rcg_clk_disable(&tssc_clk.c);
-	if (cpu_is_msm8960() &&
-			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) {
-		clk_enable(&usb_hsic_hsic_clk.c);
-		clk_disable(&usb_hsic_hsic_clk.c);
-	} else
-		/* CSI2 hardware not present on 8960v1 devices */
-		pix_rdi_mux_map[2] = NULL;
+	clk_enable(&usb_hsic_hsic_clk.c);
+	clk_disable(&usb_hsic_hsic_clk.c);
 }
 
 static int __init msm8960_clock_late_init(void)
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 9bc8eb3..81d01c2 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -174,6 +174,8 @@
 #endif
 
 	table = cpufreq_frequency_get_table(policy->cpu);
+	if (table == NULL)
+		return -ENODEV;
 	if (cpufreq_frequency_table_cpuinfo(policy, table)) {
 #ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX
 		policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_MIN;
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index abaa925..cccba2d 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -17,7 +17,8 @@
 #include <linux/cpu_pm.h>
 
 #include <mach/cpuidle.h>
-#include <mach/pm.h>
+
+#include "pm.h"
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuidle_device, msm_cpuidle_devs);
 static struct cpuidle_driver msm_cpuidle_driver = {
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f3ef2ce..92bd59b 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/msm_rotator.h>
 #include <linux/clkdev.h>
+#include <linux/dma-mapping.h>
 #include <mach/irqs-8064.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
@@ -26,6 +27,7 @@
 #include <sound/apr_audio.h>
 #include <mach/msm_bus_board.h>
 #include <mach/rpm.h>
+#include <mach/mdm2.h>
 #include "clock.h"
 #include "devices.h"
 #include "msm_watchdog.h"
@@ -59,8 +61,8 @@
 #define MSM_PMIC_SSBI_SIZE	SZ_4K
 
 /* Address of HS USBOTG1 */
-#define MSM_HSUSB_PHYS		0x12500000
-#define MSM_HSUSB_SIZE		SZ_4K
+#define MSM_HSUSB1_PHYS		0x12500000
+#define MSM_HSUSB1_SIZE		SZ_4K
 
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
@@ -413,8 +415,8 @@
 
 static struct resource resources_otg[] = {
 	{
-		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE - 1,
+		.start	= MSM_HSUSB1_PHYS,
+		.end	= MSM_HSUSB1_PHYS + MSM_HSUSB1_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -436,8 +438,8 @@
 
 static struct resource resources_hsusb[] = {
 	{
-		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE - 1,
+		.start	= MSM_HSUSB1_PHYS,
+		.end	= MSM_HSUSB1_PHYS + MSM_HSUSB1_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -457,6 +459,61 @@
 	},
 };
 
+static struct resource resources_hsusb_host[] = {
+	{
+		.start  = MSM_HSUSB1_PHYS,
+		.end    = MSM_HSUSB1_PHYS + MSM_HSUSB1_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB1_HS_IRQ,
+		.end    = USB1_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_hsic_host[] = {
+	{
+		.start	= 0x12510000,
+		.end	= 0x12510000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB2_HSIC_IRQ,
+		.end	= USB2_HSIC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_GPIO_TO_INT(49),
+		.end	= MSM_GPIO_TO_INT(49),
+		.name	= "peripheral_status_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+struct platform_device apq8064_device_hsusb_host = {
+	.name           = "msm_hsusb_host",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_hsusb_host),
+	.resource       = resources_hsusb_host,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+struct platform_device apq8064_device_hsic_host = {
+	.name		= "msm_hsic_host",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsic_host),
+	.resource	= resources_hsic_host,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
 #define MSM_SDC1_BASE         0x12400000
 #define MSM_SDC1_DML_BASE     (MSM_SDC1_BASE + 0x800)
 #define MSM_SDC1_BAM_BASE     (MSM_SDC1_BASE + 0x2000)
@@ -754,6 +811,21 @@
 };
 #endif
 
+static struct resource msm_gss_resources[] = {
+	{
+		.start  = 0x10000000,
+		.end    = 0x10000000 + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_gss = {
+	.name = "pil_gss",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_gss_resources),
+	.resource       = msm_gss_resources,
+};
+
 static struct clk_lookup msm_clocks_8064_dummy[] = {
 	CLK_DUMMY("pll2",		PLL2,		NULL, 0),
 	CLK_DUMMY("pll8",		PLL8,		NULL, 0),
@@ -1329,3 +1401,50 @@
 
 };
 #endif
+
+#define MDM2AP_ERRFATAL			19
+#define AP2MDM_ERRFATAL			18
+#define MDM2AP_STATUS			49
+#define AP2MDM_STATUS			48
+#define AP2MDM_PMIC_RESET_N		27
+
+static struct resource mdm_resources[] = {
+	{
+		.start	= MDM2AP_ERRFATAL,
+		.end	= MDM2AP_ERRFATAL,
+		.name	= "MDM2AP_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_ERRFATAL,
+		.end	= AP2MDM_ERRFATAL,
+		.name	= "AP2MDM_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= MDM2AP_STATUS,
+		.end	= MDM2AP_STATUS,
+		.name	= "MDM2AP_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_STATUS,
+		.end	= AP2MDM_STATUS,
+		.name	= "AP2MDM_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_PMIC_RESET_N,
+		.end	= AP2MDM_PMIC_RESET_N,
+		.name	= "AP2MDM_PMIC_RESET_N",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+struct platform_device mdm_8064_device = {
+	.name		= "mdm2_modem",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(mdm_resources),
+	.resource	= mdm_resources,
+};
+
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 257f372..c75a4e3 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -39,7 +39,8 @@
 		MSM_RPM_MAP(8930, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
 		MSM_RPM_MAP(8930, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
 		MSM_RPM_MAP(8930, INVALIDATE_0, INVALIDATE, 8),
-		MSM_RPM_MAP(8930, TRIGGER_TIMED_0, TRIGGER_TIMED_0, 2),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
 		MSM_RPM_MAP(8930, RPM_CTL, RPM_CTL, 1),
 		MSM_RPM_MAP(8930, CXO_CLK, CXO_CLK, 1),
 		MSM_RPM_MAP(8930, PXO_CLK, PXO_CLK, 1),
@@ -57,7 +58,7 @@
 				APPS_FABRIC_CFG_CLKMOD, 3),
 		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_IOCTL,
 				APPS_FABRIC_CFG_IOCTL, 1),
-		MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 6),
+		MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 12),
 		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_HALT_0,
 				SYS_FABRIC_CFG_HALT, 2),
 		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_CLKMOD_0,
@@ -65,14 +66,14 @@
 		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_IOCTL,
 				SYS_FABRIC_CFG_IOCTL, 1),
 		MSM_RPM_MAP(8930, SYSTEM_FABRIC_ARB_0,
-				SYSTEM_FABRIC_ARB, 20),
+				SYSTEM_FABRIC_ARB, 29),
 		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_HALT_0,
 				MMSS_FABRIC_CFG_HALT, 2),
 		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_CLKMOD_0,
 				MMSS_FABRIC_CFG_CLKMOD, 3),
 		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_IOCTL,
 				MMSS_FABRIC_CFG_IOCTL, 1),
-		MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 11),
+		MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 23),
 		MSM_RPM_MAP(8930, PM8038_S1_0, PM8038_S1, 2),
 		MSM_RPM_MAP(8930, PM8038_S2_0, PM8038_S2, 2),
 		MSM_RPM_MAP(8930, PM8038_S3_0, PM8038_S3, 2),
@@ -217,6 +218,7 @@
 		MSM_RPM_STATUS_ID_MAP(8930, CXO_BUFFERS),
 		MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
 		MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
 	},
 	.target_ctrl_id = {
 		MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 4fc05ce..1f2256f 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -30,7 +30,7 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <mach/msm_sps.h>
 #include <mach/dma.h>
-#include <mach/pm.h>
+#include "pm.h"
 #include "devices.h"
 #include "mpm.h"
 #include "spm.h"
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 5d42f99..9469de8 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -102,6 +102,8 @@
 extern struct platform_device apq8064_device_otg;
 extern struct platform_device apq8064_usb_diag_device;
 extern struct platform_device apq8064_device_gadget_peripheral;
+extern struct platform_device apq8064_device_hsusb_host;
+extern struct platform_device apq8064_device_hsic_host;
 
 extern struct platform_device msm_device_i2c;
 
@@ -193,6 +195,7 @@
 extern struct platform_device msm_8960_q6_mss_fw;
 extern struct platform_device msm_8960_q6_mss_sw;
 extern struct platform_device msm_8960_riva;
+extern struct platform_device msm_gss;
 
 extern struct platform_device apq_pcm;
 extern struct platform_device apq_pcm_routing;
@@ -292,3 +295,5 @@
 extern struct platform_device msm_bus_8064_mm_fabric;
 extern struct platform_device msm_bus_8064_sys_fpb;
 extern struct platform_device msm_bus_8064_cpss_fpb;
+
+extern struct platform_device mdm_8064_device;
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 743e3de..26adec6 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -1,6 +1,7 @@
 /*
  *  Copyright (C) 2002 ARM Ltd.
  *  All Rights Reserved
+ *  Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -13,8 +14,7 @@
 #include <asm/cacheflush.h>
 #include <asm/vfp.h>
 
-#include <mach/pm.h>
-
+#include "pm.h"
 #include "qdss.h"
 #include "spm.h"
 
@@ -68,8 +68,13 @@
 {
 	struct completion *killed =
 		&per_cpu(msm_hotplug_devices, cpu).cpu_killed;
+	int ret;
 
-	return wait_for_completion_timeout(killed, HZ * 5);
+	ret = wait_for_completion_timeout(killed, HZ * 5);
+	if (ret)
+		return ret;
+
+	return msm_pm_wait_cpu_shutdown(cpu);
 }
 
 /*
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
index b0aa902..37b8d00 100644
--- a/arch/arm/mach-msm/include/mach/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -15,7 +15,7 @@
 #define __ARCH_ARM_MACH_MSM_CPUIDLE_H
 
 #include <linux/notifier.h>
-#include <mach/pm.h>
+#include "pm.h"
 
 struct msm_cpuidle_state {
 	unsigned int cpu;
diff --git a/arch/arm/mach-msm/include/mach/irqs-8064.h b/arch/arm/mach-msm/include/mach/irqs-8064.h
index 8597111..a5f78f5 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8064.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8064.h
@@ -57,7 +57,7 @@
 #define TLMM_MSM_DIR_CONN_IRQ_8			(GIC_SPI_START + 12)
 #define TLMM_MSM_DIR_CONN_IRQ_9			(GIC_SPI_START + 13)
 #define PM8921_SEC_IRQ_N			(GIC_SPI_START + 14)
-#define PM8018_SEC_IRQ_N			(GIC_SPI_START + 15)
+#define PM8821_SEC_IRQ_N			(GIC_SPI_START + 15)
 #define TLMM_MSM_SUMMARY_IRQ			(GIC_SPI_START + 16)
 #define SPDM_RT_1_IRQ				(GIC_SPI_START + 17)
 #define SPDM_DIAG_IRQ				(GIC_SPI_START + 18)
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index acfa38a..78ca88f 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -15,6 +15,8 @@
 
 struct mdm_platform_data {
 	char *mdm_version;
+	int ramdump_delay_ms;
+	struct platform_device *peripheral_platform_device;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
index 68a3c44..d50fe2b 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,7 @@
 	unsigned used;		/* Input usage actual DSP produced PCM size  */
 	unsigned addr;
 };
+struct audio;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 struct audio_suspend_ctl {
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 304a185..04218b2 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -117,8 +117,8 @@
 	MSM_RPM_8930_ID_INVALIDATE_7 =
 		MSM_RPM_8930_ID_INVALIDATE_0 + 7,
 
-	MSM_RPM_8930_ID_TRIGGER_TIMED_0				= 16,
-	MSM_RPM_8930_ID_TRIGGER_TIMED_1				= 17,
+	MSM_RPM_8930_ID_TRIGGER_TIMED_TO_			= 16,
+	MSM_RPM_8930_ID_TRIGGER_TIMED_SCLK_COUNT		= 17,
 	MSM_RPM_8930_ID_RPM_CTL					= 18,
 	MSM_RPM_8930_ID_RESERVED_0				= 19,
 	MSM_RPM_8930_ID_RESERVED_5 =
@@ -140,106 +140,105 @@
 	MSM_RPM_8930_ID_APPS_FABRIC_CFG_CLKMOD_2		= 39,
 	MSM_RPM_8930_ID_APPS_FABRIC_CFG_IOCTL			= 40,
 	MSM_RPM_8930_ID_APPS_FABRIC_ARB_0			= 41,
-	MSM_RPM_8930_ID_APPS_FABRIC_ARB_5 =
-		MSM_RPM_8930_ID_APPS_FABRIC_ARB_0 + 5,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_0			= 47,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_1			= 48,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_0			= 49,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_1			= 50,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_2			= 51,
-	MSM_RPM_8930_ID_SYS_FABRIC_CFG_IOCTL			= 52,
-	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0			= 53,
-	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_19 =
-		MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0 + 19,
+	MSM_RPM_8930_ID_APPS_FABRIC_ARB_11 =
+		MSM_RPM_8930_ID_APPS_FABRIC_ARB_0 + 11,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_0			= 53,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_1			= 54,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_0			= 55,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_1			= 56,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_2			= 57,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_IOCTL			= 58,
+	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0			= 59,
+	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_28 =
+		MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0 + 28,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_0			= 88,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_1			= 89,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_0		= 90,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_1		= 91,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_2		= 92,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_IOCTL			= 93,
+	MSM_RPM_8930_ID_MM_FABRIC_ARB_0				= 94,
+	MSM_RPM_8930_ID_MM_FABRIC_ARB_22 =
+		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 22,
 
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_0			= 73,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_1			= 74,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_0		= 75,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_1		= 76,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_2		= 77,
-	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_IOCTL			= 78,
-	MSM_RPM_8930_ID_MM_FABRIC_ARB_0				= 79,
-	MSM_RPM_8930_ID_MM_FABRIC_ARB_10 =
-		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 10,
-
-	MSM_RPM_8930_ID_PM8038_S1_0				= 90,
-	MSM_RPM_8930_ID_PM8038_S1_1				= 91,
-	MSM_RPM_8930_ID_PM8038_S2_0				= 92,
-	MSM_RPM_8930_ID_PM8038_S2_1				= 93,
-	MSM_RPM_8930_ID_PM8038_S3_0				= 94,
-	MSM_RPM_8930_ID_PM8038_S3_1				= 95,
-	MSM_RPM_8930_ID_PM8038_S4_0				= 96,
-	MSM_RPM_8930_ID_PM8038_S4_1				= 97,
-	MSM_RPM_8930_ID_PM8038_S5_0				= 98,
-	MSM_RPM_8930_ID_PM8038_S5_1				= 99,
-	MSM_RPM_8930_ID_PM8038_S6_0				= 100,
-	MSM_RPM_8930_ID_PM8038_S6_1				= 101,
-	MSM_RPM_8930_ID_PM8038_L1_0				= 102,
-	MSM_RPM_8930_ID_PM8038_L1_1				= 103,
-	MSM_RPM_8930_ID_PM8038_L2_0				= 104,
-	MSM_RPM_8930_ID_PM8038_L2_1				= 105,
-	MSM_RPM_8930_ID_PM8038_L3_0				= 106,
-	MSM_RPM_8930_ID_PM8038_L3_1				= 107,
-	MSM_RPM_8930_ID_PM8038_L4_0				= 108,
-	MSM_RPM_8930_ID_PM8038_L4_1				= 109,
-	MSM_RPM_8930_ID_PM8038_L5_0				= 110,
-	MSM_RPM_8930_ID_PM8038_L5_1				= 111,
-	MSM_RPM_8930_ID_PM8038_L6_0				= 112,
-	MSM_RPM_8930_ID_PM8038_L6_1				= 113,
-	MSM_RPM_8930_ID_PM8038_L7_0				= 114,
-	MSM_RPM_8930_ID_PM8038_L7_1				= 115,
-	MSM_RPM_8930_ID_PM8038_L8_0				= 116,
-	MSM_RPM_8930_ID_PM8038_L8_1				= 117,
-	MSM_RPM_8930_ID_PM8038_L9_0				= 118,
-	MSM_RPM_8930_ID_PM8038_L9_1				= 119,
-	MSM_RPM_8930_ID_PM8038_L10_0				= 120,
-	MSM_RPM_8930_ID_PM8038_L10_1				= 121,
-	MSM_RPM_8930_ID_PM8038_L11_0				= 122,
-	MSM_RPM_8930_ID_PM8038_L11_1				= 123,
-	MSM_RPM_8930_ID_PM8038_L12_0				= 124,
-	MSM_RPM_8930_ID_PM8038_L12_1				= 125,
-	MSM_RPM_8930_ID_PM8038_L13_0				= 126,
-	MSM_RPM_8930_ID_PM8038_L13_1				= 127,
-	MSM_RPM_8930_ID_PM8038_L14_0				= 128,
-	MSM_RPM_8930_ID_PM8038_L14_1				= 129,
-	MSM_RPM_8930_ID_PM8038_L15_0				= 130,
-	MSM_RPM_8930_ID_PM8038_L15_1				= 131,
-	MSM_RPM_8930_ID_PM8038_L16_0				= 132,
-	MSM_RPM_8930_ID_PM8038_L16_1				= 133,
-	MSM_RPM_8930_ID_PM8038_L17_0				= 134,
-	MSM_RPM_8930_ID_PM8038_L17_1				= 135,
-	MSM_RPM_8930_ID_PM8038_L18_0				= 136,
-	MSM_RPM_8930_ID_PM8038_L18_1				= 137,
-	MSM_RPM_8930_ID_PM8038_L19_0				= 138,
-	MSM_RPM_8930_ID_PM8038_L19_1				= 139,
-	MSM_RPM_8930_ID_PM8038_L20_0				= 140,
-	MSM_RPM_8930_ID_PM8038_L20_1				= 141,
-	MSM_RPM_8930_ID_PM8038_L21_0				= 142,
-	MSM_RPM_8930_ID_PM8038_L21_1				= 143,
-	MSM_RPM_8930_ID_PM8038_L22_0				= 144,
-	MSM_RPM_8930_ID_PM8038_L22_1				= 145,
-	MSM_RPM_8930_ID_PM8038_L23_0				= 146,
-	MSM_RPM_8930_ID_PM8038_L23_1				= 147,
-	MSM_RPM_8930_ID_PM8038_L24_0				= 148,
-	MSM_RPM_8930_ID_PM8038_L24_1				= 149,
-	MSM_RPM_8930_ID_PM8038_L25_0				= 150,
-	MSM_RPM_8930_ID_PM8038_L25_1				= 151,
-	MSM_RPM_8930_ID_PM8038_L26_0				= 152,
-	MSM_RPM_8930_ID_PM8038_L26_1				= 153,
-	MSM_RPM_8930_ID_PM8038_L27_0				= 154,
-	MSM_RPM_8930_ID_PM8038_L27_1				= 155,
-	MSM_RPM_8930_ID_PM8038_CLK1_0				= 156,
-	MSM_RPM_8930_ID_PM8038_CLK1_1				= 157,
-	MSM_RPM_8930_ID_PM8038_CLK2_0				= 158,
-	MSM_RPM_8930_ID_PM8038_CLK2_1				= 159,
-	MSM_RPM_8930_ID_PM8038_LVS1				= 160,
-	MSM_RPM_8930_ID_PM8038_LVS2				= 161,
-	MSM_RPM_8930_ID_NCP_0					= 162,
-	MSM_RPM_8930_ID_NCP_1					= 163,
-	MSM_RPM_8930_ID_CXO_BUFFERS				= 164,
-	MSM_RPM_8930_ID_USB_OTG_SWITCH				= 165,
-	MSM_RPM_8930_ID_HDMI_SWITCH				= 166,
-	MSM_RPM_8930_ID_QDSS_CLK				= 167,
+	MSM_RPM_8930_ID_PM8038_S1_0				= 117,
+	MSM_RPM_8930_ID_PM8038_S1_1				= 118,
+	MSM_RPM_8930_ID_PM8038_S2_0				= 119,
+	MSM_RPM_8930_ID_PM8038_S2_1				= 120,
+	MSM_RPM_8930_ID_PM8038_S3_0				= 121,
+	MSM_RPM_8930_ID_PM8038_S3_1				= 122,
+	MSM_RPM_8930_ID_PM8038_S4_0				= 123,
+	MSM_RPM_8930_ID_PM8038_S4_1				= 124,
+	MSM_RPM_8930_ID_PM8038_S5_0				= 125,
+	MSM_RPM_8930_ID_PM8038_S5_1				= 126,
+	MSM_RPM_8930_ID_PM8038_S6_0				= 127,
+	MSM_RPM_8930_ID_PM8038_S6_1				= 128,
+	MSM_RPM_8930_ID_PM8038_L1_0				= 129,
+	MSM_RPM_8930_ID_PM8038_L1_1				= 130,
+	MSM_RPM_8930_ID_PM8038_L2_0				= 131,
+	MSM_RPM_8930_ID_PM8038_L2_1				= 132,
+	MSM_RPM_8930_ID_PM8038_L3_0				= 133,
+	MSM_RPM_8930_ID_PM8038_L3_1				= 134,
+	MSM_RPM_8930_ID_PM8038_L4_0				= 135,
+	MSM_RPM_8930_ID_PM8038_L4_1				= 136,
+	MSM_RPM_8930_ID_PM8038_L5_0				= 137,
+	MSM_RPM_8930_ID_PM8038_L5_1				= 138,
+	MSM_RPM_8930_ID_PM8038_L6_0				= 139,
+	MSM_RPM_8930_ID_PM8038_L6_1				= 140,
+	MSM_RPM_8930_ID_PM8038_L7_0				= 141,
+	MSM_RPM_8930_ID_PM8038_L7_1				= 142,
+	MSM_RPM_8930_ID_PM8038_L8_0				= 143,
+	MSM_RPM_8930_ID_PM8038_L8_1				= 144,
+	MSM_RPM_8930_ID_PM8038_L9_0				= 145,
+	MSM_RPM_8930_ID_PM8038_L9_1				= 146,
+	MSM_RPM_8930_ID_PM8038_L10_0				= 147,
+	MSM_RPM_8930_ID_PM8038_L10_1				= 148,
+	MSM_RPM_8930_ID_PM8038_L11_0				= 149,
+	MSM_RPM_8930_ID_PM8038_L11_1				= 150,
+	MSM_RPM_8930_ID_PM8038_L12_0				= 151,
+	MSM_RPM_8930_ID_PM8038_L12_1				= 152,
+	MSM_RPM_8930_ID_PM8038_L13_0				= 153,
+	MSM_RPM_8930_ID_PM8038_L13_1				= 154,
+	MSM_RPM_8930_ID_PM8038_L14_0				= 155,
+	MSM_RPM_8930_ID_PM8038_L14_1				= 156,
+	MSM_RPM_8930_ID_PM8038_L15_0				= 157,
+	MSM_RPM_8930_ID_PM8038_L15_1				= 158,
+	MSM_RPM_8930_ID_PM8038_L16_0				= 159,
+	MSM_RPM_8930_ID_PM8038_L16_1				= 160,
+	MSM_RPM_8930_ID_PM8038_L17_0				= 161,
+	MSM_RPM_8930_ID_PM8038_L17_1				= 162,
+	MSM_RPM_8930_ID_PM8038_L18_0				= 163,
+	MSM_RPM_8930_ID_PM8038_L18_1				= 164,
+	MSM_RPM_8930_ID_PM8038_L19_0				= 165,
+	MSM_RPM_8930_ID_PM8038_L19_1				= 166,
+	MSM_RPM_8930_ID_PM8038_L20_0				= 167,
+	MSM_RPM_8930_ID_PM8038_L20_1				= 168,
+	MSM_RPM_8930_ID_PM8038_L21_0				= 169,
+	MSM_RPM_8930_ID_PM8038_L21_1				= 170,
+	MSM_RPM_8930_ID_PM8038_L22_0				= 171,
+	MSM_RPM_8930_ID_PM8038_L22_1				= 172,
+	MSM_RPM_8930_ID_PM8038_L23_0				= 173,
+	MSM_RPM_8930_ID_PM8038_L23_1				= 174,
+	MSM_RPM_8930_ID_PM8038_L24_0				= 175,
+	MSM_RPM_8930_ID_PM8038_L24_1				= 176,
+	MSM_RPM_8930_ID_PM8038_L25_0				= 177,
+	MSM_RPM_8930_ID_PM8038_L25_1				= 178,
+	MSM_RPM_8930_ID_PM8038_L26_0				= 179,
+	MSM_RPM_8930_ID_PM8038_L26_1				= 180,
+	MSM_RPM_8930_ID_PM8038_L27_0				= 181,
+	MSM_RPM_8930_ID_PM8038_L27_1				= 182,
+	MSM_RPM_8930_ID_PM8038_CLK1_0				= 183,
+	MSM_RPM_8930_ID_PM8038_CLK1_1				= 184,
+	MSM_RPM_8930_ID_PM8038_CLK2_0				= 185,
+	MSM_RPM_8930_ID_PM8038_CLK2_1				= 186,
+	MSM_RPM_8930_ID_PM8038_LVS1				= 187,
+	MSM_RPM_8930_ID_PM8038_LVS2				= 188,
+	MSM_RPM_8930_ID_NCP_0					= 189,
+	MSM_RPM_8930_ID_NCP_1					= 190,
+	MSM_RPM_8930_ID_CXO_BUFFERS				= 191,
+	MSM_RPM_8930_ID_USB_OTG_SWITCH				= 192,
+	MSM_RPM_8930_ID_HDMI_SWITCH				= 193,
+	MSM_RPM_8930_ID_QDSS_CLK				= 194,
 	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_QDSS_CLK,
 };
 
@@ -284,10 +283,6 @@
 	MSM_RPM_8930_STATUS_ID_PM8038_S3_1			= 36,
 	MSM_RPM_8930_STATUS_ID_PM8038_S4_0			= 37,
 	MSM_RPM_8930_STATUS_ID_PM8038_S4_1			= 38,
-	MSM_RPM_8930_STATUS_ID_PM8038_S5_0			= 39,
-	MSM_RPM_8930_STATUS_ID_PM8038_S5_1			= 40,
-	MSM_RPM_8930_STATUS_ID_PM8038_S6_0			= 41,
-	MSM_RPM_8930_STATUS_ID_PM8038_S6_1			= 42,
 	MSM_RPM_8930_STATUS_ID_PM8038_L1_0			= 43,
 	MSM_RPM_8930_STATUS_ID_PM8038_L1_1			= 44,
 	MSM_RPM_8930_STATUS_ID_PM8038_L2_0			= 45,
@@ -353,7 +348,8 @@
 	MSM_RPM_8930_STATUS_ID_CXO_BUFFERS			= 105,
 	MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH			= 106,
 	MSM_RPM_8930_STATUS_ID_HDMI_SWITCH			= 107,
-	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_HDMI_SWITCH,
+	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 108,
+	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_QDSS_CLK,
 };
 
 #endif /* __ARCH_ARM_MACH_MSM_RPM_8930_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index 40a8c9b..80ec683 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -601,6 +601,7 @@
 	MSM_RPM_STATUS_ID_DDR_DMM_1,
 	MSM_RPM_STATUS_ID_EBI1_CH0_RANGE,
 	MSM_RPM_STATUS_ID_EBI1_CH1_RANGE,
+	MSM_RPM_STATUS_ID_QDSS_CLK,
 
 	/* 8660 Specific */
 	MSM_RPM_STATUS_ID_PLL_4,
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index bf4e6a4..5db8b40 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,7 +33,6 @@
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 #include <mach/mdm2.h>
-#include <mach/mdm-peripheral.h>
 #include <mach/restart.h>
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
@@ -46,38 +45,63 @@
 #define MDM_MODEM_TIMEOUT	6000
 #define MDM_HOLD_TIME		4000
 #define MDM_MODEM_DELTA		100
-#define IFLINE_UP			1
-#define IFLINE_DOWN			0
 
 static int mdm_debug_on;
-static struct mdm_callbacks mdm_cb;
+static int first_power_on = 1;
+static int hsic_peripheral_status = 1;
+static DEFINE_MUTEX(hsic_status_lock);
 
-#define MDM_DBG(...)	do { if (mdm_debug_on) \
-					pr_info(__VA_ARGS__); \
-			} while (0);
+static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
+{
+	mutex_lock(&hsic_status_lock);
+	if (hsic_peripheral_status)
+		goto out;
+	if (mdm_drv->pdata->peripheral_platform_device)
+		platform_device_add(mdm_drv->pdata->peripheral_platform_device);
+	hsic_peripheral_status = 1;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
+
+static void mdm_peripheral_disconnect(struct mdm_modem_drv *mdm_drv)
+{
+	mutex_lock(&hsic_status_lock);
+	if (!hsic_peripheral_status)
+		goto out;
+	if (mdm_drv->pdata->peripheral_platform_device)
+		platform_device_del(mdm_drv->pdata->peripheral_platform_device);
+	hsic_peripheral_status = 0;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
 
 static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
 {
-	peripheral_disconnect();
+	mdm_peripheral_disconnect(mdm_drv);
 
-	/* Pull both ERR_FATAL and RESET low */
-	MDM_DBG("Pulling PWR and RESET gpio's low\n");
+	/* Pull RESET gpio low and wait for it to settle. */
+	pr_debug("Pulling RESET gpio low\n");
 	gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
-	gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
-	/* Wait for them to settle. */
 	usleep(1000);
 
 	/* Deassert RESET first and wait for ir to settle. */
-	MDM_DBG("%s: Pulling RESET gpio high\n", __func__);
+	pr_debug("%s: Pulling RESET gpio high\n", __func__);
 	gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 1);
 	usleep(1000);
 
-	/* Pull PWR gpio high and wait for it to settle. */
-	MDM_DBG("%s: Powering on mdm modem\n", __func__);
-	gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
-	usleep(1000);
-
-	peripheral_connect();
+	/* Pull PWR gpio high and wait for it to settle, but only
+	 * the first time the mdm is powered up.
+	 * Some targets do not use ap2mdm_kpdpwr_n_gpio.
+	 */
+	if (first_power_on) {
+		if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
+			pr_debug("%s: Powering on mdm modem\n", __func__);
+			gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
+			usleep(1000);
+		}
+		first_power_on = 0;
+	}
+	mdm_peripheral_connect(mdm_drv);
 
 	msleep(200);
 }
@@ -92,7 +116,6 @@
 		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
 			break;
 	}
-
 	if (i <= 0) {
 		pr_err("%s: MDM2AP_STATUS never went low.\n",
 			 __func__);
@@ -103,12 +126,9 @@
 			msleep(MDM_MODEM_DELTA);
 		}
 	}
-
-	peripheral_disconnect();
-}
-
-static void normal_boot_done(struct mdm_modem_drv *mdm_drv)
-{
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
+	mdm_peripheral_disconnect(mdm_drv);
 }
 
 static void debug_state_changed(int value)
@@ -116,24 +136,25 @@
 	mdm_debug_on = value;
 }
 
-static void mdm_status_changed(int value)
+static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value)
 {
-	MDM_DBG("%s: value:%d\n", __func__, value);
+	pr_debug("%s: value:%d\n", __func__, value);
 
 	if (value) {
-		peripheral_disconnect();
-		peripheral_connect();
+		mdm_peripheral_disconnect(mdm_drv);
+		mdm_peripheral_connect(mdm_drv);
 	}
 }
 
+static struct mdm_ops mdm_cb = {
+	.power_on_mdm_cb = power_on_mdm,
+	.power_down_mdm_cb = power_down_mdm,
+	.debug_state_changed_cb = debug_state_changed,
+	.status_cb = mdm_status_changed,
+};
+
 static int __init mdm_modem_probe(struct platform_device *pdev)
 {
-	/* Instantiate driver object. */
-	mdm_cb.power_on_mdm_cb = power_on_mdm;
-	mdm_cb.power_down_mdm_cb = power_down_mdm;
-	mdm_cb.normal_boot_done_cb = normal_boot_done;
-	mdm_cb.debug_state_changed_cb = debug_state_changed;
-	mdm_cb.status_cb = mdm_status_changed;
 	return mdm_common_create(pdev, &mdm_cb);
 }
 
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 023df69..b672957 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -48,10 +48,6 @@
 
 #define EXTERNAL_MODEM "external_modem"
 
-#define MDM_DBG(...)	do { if (mdm_debug_on) \
-					pr_info(__VA_ARGS__); \
-			} while (0);
-
 static struct mdm_modem_drv *mdm_drv;
 
 DECLARE_COMPLETION(mdm_needs_reload);
@@ -70,11 +66,11 @@
 		return -EINVAL;
 	}
 
-	MDM_DBG("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+	pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
 	switch (cmd) {
 	case WAKE_CHARM:
-		MDM_DBG("%s: Powering on\n", __func__);
-		mdm_drv->power_on_mdm_cb(mdm_drv);
+		pr_info("%s: Powering on mdm\n", __func__);
+		mdm_drv->ops->power_on_mdm_cb(mdm_drv);
 		break;
 	case CHECK_FOR_BOOT:
 		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
@@ -83,16 +79,19 @@
 			put_user(0, (unsigned long __user *) arg);
 		break;
 	case NORMAL_BOOT_DONE:
-		MDM_DBG("%s: check if mdm is booted up\n", __func__);
+		pr_debug("%s: check if mdm is booted up\n", __func__);
 		get_user(status, (unsigned long __user *) arg);
-		if (status)
+		if (status) {
+			pr_debug("%s: normal boot failed\n", __func__);
 			mdm_drv->mdm_boot_status = -EIO;
-		else
+		} else {
+			pr_info("%s: normal boot done\n", __func__);
 			mdm_drv->mdm_boot_status = 0;
+		}
 		mdm_drv->mdm_ready = 1;
 
-		if (mdm_drv->normal_boot_done_cb != NULL)
-			mdm_drv->normal_boot_done_cb(mdm_drv);
+		if (mdm_drv->ops->normal_boot_done_cb != NULL)
+			mdm_drv->ops->normal_boot_done_cb(mdm_drv);
 
 		if (!first_boot)
 			complete(&mdm_boot);
@@ -100,16 +99,18 @@
 			first_boot = 0;
 		break;
 	case RAM_DUMP_DONE:
-		MDM_DBG("%s: mdm done collecting RAM dumps\n", __func__);
+		pr_debug("%s: mdm done collecting RAM dumps\n", __func__);
 		get_user(status, (unsigned long __user *) arg);
 		if (status)
 			mdm_drv->mdm_ram_dump_status = -EIO;
-		else
+		else {
+			pr_info("%s: ramdump collection completed\n", __func__);
 			mdm_drv->mdm_ram_dump_status = 0;
+		}
 		complete(&mdm_ram_dumps);
 		break;
 	case WAIT_FOR_RESTART:
-		MDM_DBG("%s: wait for mdm to need images reloaded\n",
+		pr_debug("%s: wait for mdm to need images reloaded\n",
 				__func__);
 		ret = wait_for_completion_interruptible(&mdm_needs_reload);
 		if (!ret)
@@ -128,7 +129,7 @@
 
 static void mdm_fatal_fn(struct work_struct *work)
 {
-	MDM_DBG("%s: Reseting the mdm due to an errfatal\n", __func__);
+	pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
 	subsystem_restart(EXTERNAL_MODEM);
 }
 
@@ -138,15 +139,15 @@
 {
 	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
 
-	mdm_drv->status_cb(value);
+	mdm_drv->ops->status_cb(mdm_drv, value);
 
-	MDM_DBG("%s: status:%d\n", __func__, value);
+	pr_debug("%s: status:%d\n", __func__, value);
 
 	if ((value == 0) && mdm_drv->mdm_ready) {
-		MDM_DBG("%s: scheduling work now\n", __func__);
+		pr_info("%s: unexpected reset external modem\n", __func__);
 		subsystem_restart(EXTERNAL_MODEM);
 	} else if (value == 1) {
-		MDM_DBG("%s: mdm is now ready\n", __func__);
+		pr_info("%s: status = 1: mdm is now ready\n", __func__);
 	}
 }
 
@@ -161,10 +162,10 @@
 
 static irqreturn_t mdm_errfatal(int irq, void *dev_id)
 {
-	MDM_DBG("%s: mdm got errfatal interrupt\n", __func__);
+	pr_debug("%s: mdm got errfatal interrupt\n", __func__);
 	if (mdm_drv->mdm_ready &&
 		(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
-		MDM_DBG("%s: scheduling work now\n", __func__);
+		pr_debug("%s: scheduling work now\n", __func__);
 		queue_work(mdm_queue, &mdm_fatal_work);
 	}
 	return IRQ_HANDLED;
@@ -193,7 +194,7 @@
 {
 	int i;
 
-	MDM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
+	pr_debug("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
 			 __func__);
 	mdm_disable_irqs();
 	gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
@@ -218,7 +219,7 @@
 
 static irqreturn_t mdm_status_change(int irq, void *dev_id)
 {
-	MDM_DBG("%s: mdm sent status change interrupt\n", __func__);
+	pr_debug("%s: mdm sent status change interrupt\n", __func__);
 
 	queue_work(mdm_queue, &mdm_status_work);
 
@@ -229,13 +230,19 @@
 {
 	mdm_drv->mdm_ready = 0;
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
-	mdm_drv->power_down_mdm_cb(mdm_drv);
+	if (mdm_drv->pdata->ramdump_delay_ms > 0) {
+		/* Wait for the external modem to complete
+		 * its preparation for ramdumps.
+		 */
+		mdelay(mdm_drv->pdata->ramdump_delay_ms);
+	}
+	mdm_drv->ops->power_down_mdm_cb(mdm_drv);
 	return 0;
 }
 
 static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
 {
-	mdm_drv->power_on_mdm_cb(mdm_drv);
+	mdm_drv->ops->power_on_mdm_cb(mdm_drv);
 	mdm_drv->boot_type = CHARM_NORMAL_BOOT;
 	complete(&mdm_needs_reload);
 	wait_for_completion(&mdm_boot);
@@ -254,7 +261,7 @@
 		wait_for_completion(&mdm_ram_dumps);
 		INIT_COMPLETION(mdm_ram_dumps);
 		gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
-		mdm_drv->power_down_mdm_cb(mdm_drv);
+		mdm_drv->ops->power_down_mdm_cb(mdm_drv);
 	}
 	return mdm_drv->mdm_ram_dump_status;
 }
@@ -269,8 +276,8 @@
 static int mdm_debug_on_set(void *data, u64 val)
 {
 	mdm_debug_on = val;
-	if (mdm_drv->debug_state_changed_cb)
-		mdm_drv->debug_state_changed_cb(mdm_debug_on);
+	if (mdm_drv->ops->debug_state_changed_cb)
+		mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
 	return 0;
 }
 
@@ -298,7 +305,7 @@
 }
 
 static void mdm_modem_initialize_data(struct platform_device  *pdev,
-				struct mdm_callbacks *p_mdm_cb)
+				struct mdm_ops *mdm_ops)
 {
 	struct resource *pres;
 
@@ -352,15 +359,12 @@
 
 	mdm_drv->boot_type                  = CHARM_NORMAL_BOOT;
 
-	mdm_drv->power_on_mdm_cb            = p_mdm_cb->power_on_mdm_cb;
-	mdm_drv->power_down_mdm_cb          = p_mdm_cb->power_down_mdm_cb;
-	mdm_drv->normal_boot_done_cb        = p_mdm_cb->normal_boot_done_cb;
-	mdm_drv->debug_state_changed_cb     = p_mdm_cb->debug_state_changed_cb;
-	mdm_drv->status_cb                  = p_mdm_cb->status_cb;
+	mdm_drv->ops      = mdm_ops;
+	mdm_drv->pdata    = pdev->dev.platform_data;
 }
 
 int mdm_common_create(struct platform_device  *pdev,
-					  struct mdm_callbacks *p_mdm_cb)
+					  struct mdm_ops *p_mdm_cb)
 {
 	int ret = -1, irq;
 
@@ -371,8 +375,8 @@
 	}
 
 	mdm_modem_initialize_data(pdev, p_mdm_cb);
-	if (mdm_drv->debug_state_changed_cb)
-		mdm_drv->debug_state_changed_cb(mdm_debug_on);
+	if (mdm_drv->ops->debug_state_changed_cb)
+		mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
 
 	gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
 	gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
@@ -494,7 +498,7 @@
 
 void mdm_common_modem_shutdown(struct platform_device *pdev)
 {
-	MDM_DBG("%s: setting AP2MDM_STATUS low for a graceful restart\n",
+	pr_debug("%s: setting AP2MDM_STATUS low for a graceful restart\n",
 		__func__);
 
 	mdm_disable_irqs();
@@ -504,7 +508,7 @@
 	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
 		gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
 
-	mdm_drv->power_down_mdm_cb(mdm_drv);
+	mdm_drv->ops->power_down_mdm_cb(mdm_drv);
 
 	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
 		gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 0);
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index bc8541e..206bd8b 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,14 @@
 
 struct mdm_modem_drv;
 
+struct mdm_ops {
+	void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*debug_state_changed_cb)(int value);
+	void (*status_cb)(struct mdm_modem_drv *mdm_drv, int value);
+};
+
 /* Private mdm2 data structure */
 struct mdm_modem_drv {
 	unsigned mdm2ap_errfatal_gpio;
@@ -34,23 +42,12 @@
 	enum charm_boot_type boot_type;
 	int mdm_debug_on;
 
-	void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
-	void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
-	void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
-	void (*debug_state_changed_cb)(int value);
-	void (*status_cb)(int value);
-};
-
-struct mdm_callbacks {
-	void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
-	void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
-	void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
-	void (*debug_state_changed_cb)(int value);
-	void (*status_cb)(int value);
+	struct mdm_ops *ops;
+	struct mdm_platform_data *pdata;
 };
 
 int mdm_common_create(struct platform_device  *pdev,
-					  struct mdm_callbacks *mdm_cb);
+					  struct mdm_ops *mdm_cb);
 int mdm_common_modem_remove(struct platform_device *pdev);
 void mdm_common_modem_shutdown(struct platform_device *pdev);
 void mdm_common_set_debug_state(int value);
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index f51286f..d1c474b 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -15,7 +15,7 @@
 
 #include <mach/cpuidle.h>
 #include "idle.h"
-#include <mach/pm.h>
+#include "pm.h"
 
 void arch_idle(void)
 { }
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
new file mode 100644
index 0000000..4c94b83
--- /dev/null
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define GSS_CSR_AHB_CLK_SEL	0x0
+#define GSS_CSR_RESET		0x4
+#define GSS_CSR_CLK_BLK_CONFIG	0x8
+#define GSS_CSR_CLK_ENABLE	0xC
+#define GSS_CSR_BOOT_REMAP	0x14
+#define GSS_CSR_POWER_UP_DOWN	0x18
+
+#define GSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60)
+#define GSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64)
+#define GSS_CLAMP_ENA		(MSM_CLK_CTL_BASE + 0x2C68)
+#define GSS_CXO_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2C74)
+
+#define PLL5_MODE		(MSM_CLK_CTL_BASE + 0x30E0)
+#define PLL5_L_VAL		(MSM_CLK_CTL_BASE + 0x30E4)
+#define PLL5_M_VAL		(MSM_CLK_CTL_BASE + 0x30E8)
+#define PLL5_N_VAL		(MSM_CLK_CTL_BASE + 0x30EC)
+#define PLL5_CONFIG		(MSM_CLK_CTL_BASE + 0x30F4)
+#define PLL5_STATUS		(MSM_CLK_CTL_BASE + 0x30F8)
+#define PLL_ENA_GSS		(MSM_CLK_CTL_BASE + 0x3480)
+#define PLL_ENA_RPM		(MSM_CLK_CTL_BASE + 0x34A0)
+
+#define PLL5_VOTE		BIT(5)
+#define PLL_STATUS		BIT(16)
+#define REMAP_ENABLE		BIT(16)
+#define A5_POWER_STATUS		BIT(4)
+#define A5_POWER_ENA		BIT(0)
+#define NAV_POWER_ENA		BIT(1)
+#define XO_CLK_BRANCH_ENA	BIT(0)
+#define SLP_CLK_BRANCH_ENA	BIT(4)
+#define A5_RESET		BIT(0)
+
+#define PROXY_VOTE_TIMEOUT	10000
+
+struct gss_data {
+	void __iomem *base;
+	unsigned long start_addr;
+	struct delayed_work work;
+	struct clk *xo;
+};
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+	return 0;
+}
+
+static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int make_gss_proxy_votes(struct device *dev)
+{
+	int ret;
+	struct gss_data *drv = dev_get_drvdata(dev);
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(dev, "Failed to enable XO\n");
+		return ret;
+	}
+	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+	return 0;
+}
+
+static void remove_gss_proxy_votes(struct work_struct *work)
+{
+	struct gss_data *drv = container_of(work, struct gss_data, work.work);
+	clk_disable_unprepare(drv->xo);
+}
+
+static void remove_gss_proxy_votes_now(struct gss_data *drv)
+{
+	flush_delayed_work(&drv->work);
+}
+
+static void gss_init(struct gss_data *drv)
+{
+	void __iomem *base = drv->base;
+
+	/* Supply clocks to GSS. */
+	writel_relaxed(XO_CLK_BRANCH_ENA, GSS_CXO_SRC_CTL);
+	writel_relaxed(SLP_CLK_BRANCH_ENA, GSS_SLP_CLK_CTL);
+
+	/* Deassert GSS reset and clamps. */
+	writel_relaxed(0x0, GSS_RESET);
+	writel_relaxed(0x0, GSS_CLAMP_ENA);
+	mb();
+
+	/*
+	 * Configure clock source and dividers for 288MHz core, 144MHz AXI and
+	 * 72MHz AHB, all derived from the 288MHz PLL.
+	 */
+	writel_relaxed(0x341, base + GSS_CSR_CLK_BLK_CONFIG);
+	writel_relaxed(0x1, base + GSS_CSR_AHB_CLK_SEL);
+
+	/* Assert all GSS resets. */
+	writel_relaxed(0x7F, base + GSS_CSR_RESET);
+
+	/* Enable all bus clocks and wait for resets to propagate. */
+	writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE);
+	mb();
+	udelay(1);
+
+	/* Release subsystem from reset, but leave A5 in reset. */
+	writel_relaxed(A5_RESET, base + GSS_CSR_RESET);
+}
+
+static int pil_gss_reset(struct pil_desc *pil)
+{
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *base = drv->base;
+	unsigned long start_addr = drv->start_addr;
+	int ret;
+
+	ret = make_gss_proxy_votes(pil->dev);
+	if (ret)
+		return ret;
+
+	/* Vote PLL on in GSS's voting register and wait for it to enable. */
+	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
+	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
+		cpu_relax();
+
+	/* Perform GSS initialization. */
+	gss_init(drv);
+
+	/* Configure boot address and enable remap. */
+	writel_relaxed(REMAP_ENABLE | (start_addr >> 16),
+			base + GSS_CSR_BOOT_REMAP);
+
+	/* Power up A5 core. */
+	writel_relaxed(A5_POWER_ENA, base + GSS_CSR_POWER_UP_DOWN);
+	while (!(readl_relaxed(base + GSS_CSR_POWER_UP_DOWN) & A5_POWER_STATUS))
+		cpu_relax();
+
+	/* Release A5 from reset. */
+	writel_relaxed(0x0, base + GSS_CSR_RESET);
+
+	return 0;
+}
+
+static int pil_gss_shutdown(struct pil_desc *pil)
+{
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *base = drv->base;
+	u32 regval;
+	int ret;
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+
+	/*
+	 * Vote PLL on in GSS's voting register and wait for it to enable.
+	 * The PLL must be enable to switch the GFMUX to a low-power source.
+	 */
+	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
+	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
+		cpu_relax();
+
+	/* Perform one-time GSS initialization. */
+	gss_init(drv);
+
+	/* Assert A5 reset. */
+	regval = readl_relaxed(base + GSS_CSR_RESET);
+	regval |= A5_RESET;
+	writel_relaxed(regval, base + GSS_CSR_RESET);
+
+	/* Power down A5 and NAV. */
+	regval = readl_relaxed(base + GSS_CSR_POWER_UP_DOWN);
+	regval &= ~(A5_POWER_ENA|NAV_POWER_ENA);
+	writel_relaxed(regval, base + GSS_CSR_POWER_UP_DOWN);
+
+	/* Select XO clock source and increase dividers to save power. */
+	regval = readl_relaxed(base + GSS_CSR_CLK_BLK_CONFIG);
+	regval |= 0x3FF;
+	writel_relaxed(regval, base + GSS_CSR_CLK_BLK_CONFIG);
+
+	/* Disable bus clocks. */
+	writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE);
+
+	/* Clear GSS PLL votes. */
+	writel_relaxed(0, PLL_ENA_GSS);
+	mb();
+
+	clk_disable_unprepare(drv->xo);
+	remove_gss_proxy_votes_now(drv);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_gss_ops = {
+	.init_image = pil_gss_init_image,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_gss_reset,
+	.shutdown = pil_gss_shutdown,
+};
+
+static void configure_gss_pll(struct gss_data *drv)
+{
+	u32 regval, is_pll_enabled;
+
+	/* Check if PLL5 is enabled by FSM. */
+	is_pll_enabled = readl_relaxed(PLL5_STATUS) & PLL_STATUS;
+	if (!is_pll_enabled) {
+		/* Enable XO reference for PLL5 */
+		clk_prepare_enable(drv->xo);
+
+		/*
+		 * Assert a vote to hold PLL5 on in RPM register until other
+		 * voters are in place.
+		 */
+		regval = readl_relaxed(PLL_ENA_RPM);
+		regval |= PLL5_VOTE;
+		writel_relaxed(regval, PLL_ENA_RPM);
+
+		/* Ref clk = 27MHz and program pll5 to 288MHz */
+		writel_relaxed(0xF, PLL5_L_VAL);
+		writel_relaxed(0x0, PLL5_M_VAL);
+		writel_relaxed(0x1, PLL5_N_VAL);
+
+		regval = readl_relaxed(PLL5_CONFIG);
+		/* Disable the MN accumulator and enable the main output. */
+		regval &= ~BIT(22);
+		regval |= BIT(23);
+
+		/* Set pre-divider and post-divider values to 1 and 1 */
+		regval &= ~BIT(19);
+		regval &= ~(BIT(21)|BIT(20));
+
+		/* Set VCO frequency */
+		regval &= ~(BIT(17)|BIT(16));
+		writel_relaxed(regval, PLL5_CONFIG);
+
+		regval = readl_relaxed(PLL5_MODE);
+		/* De-assert reset to FSM */
+		regval &= ~BIT(21);
+		writel_relaxed(regval, PLL5_MODE);
+
+		/* Program bias count */
+		regval &= ~(0x3F << 14);
+		regval |= (0x1 << 14);
+		writel_relaxed(regval, PLL5_MODE);
+
+		/* Program lock count */
+		regval &= ~(0x3F << 8);
+		regval |= (0x8 << 8);
+		writel_relaxed(regval, PLL5_MODE);
+
+		/* Enable PLL FSM voting */
+		regval |= BIT(20);
+		writel_relaxed(regval, PLL5_MODE);
+	}
+}
+
+static int __devinit pil_gss_probe(struct platform_device *pdev)
+{
+	struct gss_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	drv->xo = clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	desc->name = "gss";
+	desc->dev = &pdev->dev;
+
+	desc->ops = &pil_gss_ops;
+	dev_info(&pdev->dev, "using non-secure boot\n");
+
+	INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
+
+	/* FIXME: Remove when PLL is configured by bootloaders. */
+	configure_gss_pll(drv);
+
+	ret = msm_pil_register(desc);
+	if (ret) {
+		flush_delayed_work_sync(&drv->work);
+		clk_put(drv->xo);
+	}
+	return ret;
+}
+
+static int __devexit pil_gss_remove(struct platform_device *pdev)
+{
+	struct gss_data *drv = platform_get_drvdata(pdev);
+	flush_delayed_work_sync(&drv->work);
+	clk_put(drv->xo);
+	return 0;
+}
+
+static struct platform_driver pil_gss_driver = {
+	.probe = pil_gss_probe,
+	.remove = __devexit_p(pil_gss_remove),
+	.driver = {
+		.name = "pil_gss",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_gss_init(void)
+{
+	return platform_driver_register(&pil_gss_driver);
+}
+module_init(pil_gss_init);
+
+static void __exit pil_gss_exit(void)
+{
+	platform_driver_unregister(&pil_gss_driver);
+}
+module_exit(pil_gss_exit);
+
+MODULE_DESCRIPTION("Support for booting the GSS processor");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index f1c6c48..3c422009 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -25,7 +25,7 @@
 #include <mach/hardware.h>
 #include <mach/msm_iomap.h>
 
-#include <mach/pm.h>
+#include "pm.h"
 #include "scm-boot.h"
 #include "spm.h"
 
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 9bdc2b3..b3c6d1e 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -44,7 +44,7 @@
 #include "avs.h"
 #include <mach/cpuidle.h>
 #include "idle.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include "rpm_resources.h"
 #include "scm-boot.h"
 #include "spm.h"
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
index 3dcbfb3..d684a5a 100644
--- a/arch/arm/mach-msm/pm.c
+++ b/arch/arm/mach-msm/pm.c
@@ -44,7 +44,7 @@
 #include "irq.h"
 #include "gpio.h"
 #include "timer.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include "pm-boot.h"
 
 enum {
diff --git a/arch/arm/mach-msm/include/mach/pm.h b/arch/arm/mach-msm/pm.h
similarity index 88%
rename from arch/arm/mach-msm/include/mach/pm.h
rename to arch/arm/mach-msm/pm.h
index 689cd17..892472b 100644
--- a/arch/arm/mach-msm/include/mach/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/pm.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -64,10 +64,14 @@
 
 void __init msm_pm_init_sleep_status_data(
 		struct msm_pm_sleep_status_data *sleep_data);
-#ifdef CONFIG_PM
+#ifdef CONFIG_MSM_PM8X60
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
+int msm_pm_wait_cpu_shutdown(unsigned int cpu);
+bool msm_pm_verify_cpu_pc(unsigned int cpu);
 #else
 static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
+static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
+static inline bool msm_pm_verify_cpu_pc(unsigned int cpu) { return true; }
 #endif
 
 #ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 0518ea2..4cdd7ae 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -58,7 +58,7 @@
 #include "irq.h"
 #include "gpio.h"
 #include "timer.h"
-#include <mach/pm.h>
+#include "pm.h"
 #include "spm.h"
 #include "sirc.h"
 #include "pm-boot.h"
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
index 0ddba89..4b8b7a6 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
  *
@@ -196,8 +196,10 @@
 static void audplay_config_hostpcm(struct audio *audio);
 static void audplay_buffer_refresh(struct audio *audio);
 static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audadpcm_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
+#endif
 
 /* must be called with audio->lock held */
 static int audio_enable(struct audio *audio)
@@ -1433,6 +1435,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audadpcm_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload)
 {
@@ -1461,7 +1464,6 @@
 	wake_up(&audio->event_wait);
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audadpcm_suspend(struct early_suspend *h)
 {
 	struct audadpcm_suspend_ctl *ctl =
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
index 85a3daa..a09b71b 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
@@ -1,7 +1,7 @@
 /*
  * amrnb audio decoder device
  *
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -194,8 +194,10 @@
 static void audamrnb_config_hostpcm(struct audio *audio);
 static void audamrnb_buffer_refresh(struct audio *audio);
 static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audamrnb_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
+#endif
 
 /* must be called with audio->lock held */
 static int audamrnb_enable(struct audio *audio)
@@ -1330,6 +1332,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audamrnb_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload)
 {
@@ -1358,7 +1361,6 @@
 	wake_up(&audio->event_wait);
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audamrnb_suspend(struct early_suspend *h)
 {
 	struct audamrnb_suspend_ctl *ctl =
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
index d6cf21d..48e9a9f 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
@@ -1,6 +1,6 @@
 /* amrwb audio decoder device
  *
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
  *
@@ -195,8 +195,10 @@
 static void audamrwb_config_hostpcm(struct audio *audio);
 static void audamrwb_buffer_refresh(struct audio *audio);
 static void audamrwb_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audamrwb_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
+#endif
 
 /* must be called with audio->lock held */
 static int audamrwb_enable(struct audio *audio)
@@ -1414,6 +1416,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audamrwb_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload)
 {
@@ -1442,7 +1445,6 @@
 	wake_up(&audio->event_wait);
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audamrwb_suspend(struct early_suspend *h)
 {
 	struct audamrwb_suspend_ctl *ctl =
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
index e5261b5..9b5694d 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This code also borrows from audio_aac.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -189,8 +189,10 @@
 static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg);
 static void audevrc_config_hostpcm(struct audio *audio);
 static void audevrc_buffer_refresh(struct audio *audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audevrc_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
+#endif
 
 /* must be called with audio->lock held */
 static int audevrc_enable(struct audio *audio)
@@ -1324,6 +1326,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audevrc_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload)
 {
@@ -1352,7 +1355,6 @@
 	wake_up(&audio->event_wait);
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audevrc_suspend(struct early_suspend *h)
 {
 	struct audevrc_suspend_ctl *ctl =
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
index 0e61e84..c639833 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -112,6 +112,7 @@
 	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
 	res;							\
 })
+struct audio;
 
 struct buffer {
 	void *data;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
index 139c16c..b22820b 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -101,6 +101,8 @@
 	res;							\
 })
 
+struct audio;
+
 struct buffer {
 	void *data;
 	unsigned size;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
index f3f0619..ce5d421 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
@@ -1,7 +1,7 @@
 /*
  * qcelp 13k audio decoder device
  *
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on audio_mp3.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -184,8 +184,10 @@
 static void audqcelp_config_hostpcm(struct audio *audio);
 static void audqcelp_buffer_refresh(struct audio *audio);
 static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audqcelp_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
+#endif
 
 /* must be called with audio->lock held */
 static int audqcelp_enable(struct audio *audio)
@@ -1326,6 +1328,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audqcelp_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload)
 {
@@ -1354,7 +1357,6 @@
 	wake_up(&audio->event_wait);
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audqcelp_suspend(struct early_suspend *h)
 {
 	struct audqcelp_suspend_ctl *ctl =
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
index 464f66e..f29b078 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
  *
@@ -200,9 +200,10 @@
 static void audplay_config_hostpcm(struct audio *audio);
 static void audplay_buffer_refresh(struct audio *audio);
 static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audwma_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
-
+#endif
 /* must be called with audio->lock held */
 static int audio_enable(struct audio *audio)
 {
@@ -1472,6 +1473,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audwma_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload)
 {
@@ -1500,7 +1502,6 @@
 	wake_up(&audio->event_wait);
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audwma_suspend(struct early_suspend *h)
 {
 	struct audwma_suspend_ctl *ctl =
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
index 878237e..cf25359 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
  *
@@ -200,8 +200,10 @@
 static void audplay_config_hostpcm(struct audio *audio);
 static void audplay_buffer_refresh(struct audio *audio);
 static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audwmapro_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
+#endif
 
 /* must be called with audio->lock held */
 static int audio_enable(struct audio *audio)
@@ -1484,6 +1486,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audwmapro_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload)
 {
@@ -1512,7 +1515,6 @@
 	wake_up(&audio->event_wait);
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audwmapro_suspend(struct early_suspend *h)
 {
 	struct audwmapro_suspend_ctl *ctl =
diff --git a/arch/arm/mach-msm/rpm_resources.h b/arch/arm/mach-msm/rpm_resources.h
index da9d3ff..a5c61b2 100644
--- a/arch/arm/mach-msm/rpm_resources.h
+++ b/arch/arm/mach-msm/rpm_resources.h
@@ -15,7 +15,7 @@
 #define __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H
 
 #include <mach/rpm.h>
-#include <mach/pm.h>
+#include "pm.h"
 
 enum {
 	MSM_RPMRS_ID_PXO_CLK = 0,
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 326faef..0aa1358 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -167,23 +167,26 @@
 	uint32_t val = 0;
 	uint32_t timeout = 0;
 	void *reg = NULL;
+	void *saw_bases[] = {
+		0,
+		MSM_SAW1_BASE,
+		MSM_SAW2_BASE,
+		MSM_SAW3_BASE
+	};
 
-	if (cpu >= num_possible_cpus())
+	if (cpu == 0 || cpu >= num_possible_cpus())
 		return -EINVAL;
 
-	switch (cpu) {
-	case 1:
-		reg = MSM_SAW1_BASE;
-		break;
-	case 0:
-	default:
-		return -EFAULT;
-	}
+	reg = saw_bases[cpu];
 
 	if (cpu_is_msm8960() || cpu_is_msm8930()) {
 		val = 0xB0;
 		reg += 0x14;
 		timeout = 512;
+	} else if (cpu_is_apq8064()) {
+		val = 0xA4;
+		reg += 0x14;
+		timeout = 512;
 	} else {
 		return -ENOSYS;
 	}
diff --git a/drivers/media/video/msm/msm_io_8x60.c b/drivers/media/video/msm/msm_io_8x60.c
index bac650a..49ec461 100644
--- a/drivers/media/video/msm/msm_io_8x60.c
+++ b/drivers/media/video/msm/msm_io_8x60.c
@@ -460,10 +460,12 @@
 
 static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
 {
-	uint32_t irq;
-	irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS);
+	uint32_t irq = 0;
+	if (csibase != NULL)
+		irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS);
 	CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
-	msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
+	if (csibase != NULL)
+		msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
 	return IRQ_HANDLED;
 }
 
@@ -604,8 +606,10 @@
 
 csi_irq_fail:
 	iounmap(csibase);
+	csibase = NULL;
 csi_busy:
 	release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+	csibase = NULL;
 common_fail:
 	msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
 	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
@@ -625,27 +629,29 @@
 	uint32_t val;
 
 	val = 0x0;
-	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
-	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
-	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
-	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
-	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
-
-	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
-	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
-	msleep(10);
-
-	val = msm_io_r(csibase + MIPI_PHY_D1_CONTROL);
-	val &= ~((0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
-	(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT));
-	CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
-	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
-	usleep_range(5000, 6000);
-	msm_io_w(0x0, csibase + MIPI_INTERRUPT_MASK);
-	msm_io_w(0x0, csibase + MIPI_INTERRUPT_STATUS);
-	csi_free_irq();
-	iounmap(csibase);
-	release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+	if (csibase != NULL) {
+		CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+		CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+		msleep(20);
+		val = msm_io_r(csibase + MIPI_PHY_D1_CONTROL);
+		val &=
+		~((0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT)
+		|(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT));
+		CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
+		usleep_range(5000, 6000);
+		msm_io_w(0x0, csibase + MIPI_INTERRUPT_MASK);
+		msm_io_w(0x0, csibase + MIPI_INTERRUPT_STATUS);
+		csi_free_irq();
+		iounmap(csibase);
+		csibase = NULL;
+		release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+	}
 }
 void msm_camio_disable(struct platform_device *pdev)
 {
@@ -727,78 +733,82 @@
 	int i;
 
 	CDBG("msm_camio_csi_config\n");
+	if (csibase != NULL) {
+		/* SOT_ECC_EN enable error correction for SYNC (data-lane) */
+		msm_io_w(0x4, csibase + MIPI_PHY_CONTROL);
 
-	/* SOT_ECC_EN enable error correction for SYNC (data-lane) */
-	msm_io_w(0x4, csibase + MIPI_PHY_CONTROL);
-
-	/* SW_RST to the CSI core */
-	msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+		/* SW_RST to the CSI core */
+		msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
 		csibase + MIPI_PROTOCOL_CONTROL);
 
-	/* PROTOCOL CONTROL */
-	val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
-		MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
-		MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
-	val |= (uint32_t)(csi_params->data_format) <<
-		MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
-	val |= csi_params->dpcm_scheme <<
-		MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
-	CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
-	msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
+		/* PROTOCOL CONTROL */
+		val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
+			MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
+			MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
+		val |= (uint32_t)(csi_params->data_format) <<
+			MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
+		val |= csi_params->dpcm_scheme <<
+			MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
+		CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
 
-	/* settle_cnt is very sensitive to speed!
-	increase this value to run at higher speeds */
-	val = (csi_params->settle_cnt <<
-		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
-		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
-		(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
-		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
-	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
-	for (i = 0; i < csi_params->lane_cnt; i++)
-		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2 + i * 4);
+		/* settle_cnt is very sensitive to speed!
+		increase this value to run at higher speeds */
+		val = (csi_params->settle_cnt <<
+			MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+			(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+			(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+			(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+		CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+		for (i = 0; i < csi_params->lane_cnt; i++)
+			msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2 + i * 4);
 
-	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
-		(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
-	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
-	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+		val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+			(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+		CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
 
-	val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
-	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
+		val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
+		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
 
-	val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
-		(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
-	CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
-	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
+		val =
+		(0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT)
+		|(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
+		CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
 
-	msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
-	msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
+		msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
+		msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
 
-	/* halcyon only supports 1 or 2 lane */
-	switch (csi_params->lane_cnt) {
-	case 1:
-		msm_io_w(csi_params->lane_assign << 8 | 0x4,
-			csibase + MIPI_CAMERA_CNTL);
-		break;
-	case 2:
-		msm_io_w(csi_params->lane_assign << 8 | 0x5,
-			csibase + MIPI_CAMERA_CNTL);
-		break;
-	case 3:
-		msm_io_w(csi_params->lane_assign << 8 | 0x6,
-			csibase + MIPI_CAMERA_CNTL);
-		break;
-	case 4:
-		msm_io_w(csi_params->lane_assign << 8 | 0x7,
-			csibase + MIPI_CAMERA_CNTL);
-		break;
+		/* halcyon only supports 1 or 2 lane */
+		switch (csi_params->lane_cnt) {
+		case 1:
+			msm_io_w(csi_params->lane_assign << 8 | 0x4,
+				csibase + MIPI_CAMERA_CNTL);
+			break;
+		case 2:
+			msm_io_w(csi_params->lane_assign << 8 | 0x5,
+				csibase + MIPI_CAMERA_CNTL);
+			break;
+		case 3:
+			msm_io_w(csi_params->lane_assign << 8 | 0x6,
+				csibase + MIPI_CAMERA_CNTL);
+			break;
+		case 4:
+			msm_io_w(csi_params->lane_assign << 8 | 0x7,
+				csibase + MIPI_CAMERA_CNTL);
+			break;
+		}
+
+		/* mask out ID_ERROR[19], DATA_CMM_ERR[11]
+		and CLK_CMM_ERR[10] - de-featured */
+		msm_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_MASK);
+		/*clear IRQ bits*/
+		msm_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_STATUS);
+	} else {
+		pr_info("CSIBASE is NULL");
 	}
 
-	/* mask out ID_ERROR[19], DATA_CMM_ERR[11]
-	and CLK_CMM_ERR[10] - de-featured */
-	msm_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_MASK);
-	/*clear IRQ bits*/
-	msm_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_STATUS);
-
 	return rc;
 }
 
diff --git a/drivers/media/video/msm/wfd/Makefile b/drivers/media/video/msm/wfd/Makefile
index 7ea9db3..2b39e66 100644
--- a/drivers/media/video/msm/wfd/Makefile
+++ b/drivers/media/video/msm/wfd/Makefile
@@ -1,5 +1,4 @@
-#obj-$(CONFIG_MSM_WFD_V4L2) += wfd-ioctl.o
-#obj-$(CONFIG_MSM_WFD_V4L2) += enc-subdev.o
 obj-y += mdp-subdev.o
 obj-y += enc-subdev.o
+obj-y += vsg-subdev.o
 obj-y += wfd-ioctl.o
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index 00a688c..e3d9d2d 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -147,7 +147,6 @@
 	struct vb2_buffer *vbuf;
 	struct mem_region *mregion;
 	struct vcd_frame_data *frame_data = (struct vcd_frame_data *)info;
-	struct timespec ts;
 
 	if (!client_ctx) {
 		WFD_MSG_ERR("Client context is NULL\n");
@@ -190,9 +189,8 @@
 			break;
 		}
 
-		ktime_get_ts(&ts);
-		vbuf->v4l2_buf.timestamp.tv_sec = ts.tv_sec;
-		vbuf->v4l2_buf.timestamp.tv_usec = ts.tv_nsec/1000;
+		vbuf->v4l2_buf.timestamp =
+			ns_to_timeval(frame_data->time_stamp);
 
 		WFD_MSG_DBG("bytes used %d, ts: %d.%d, frame type is %d\n",
 				frame_data->data_len,
@@ -942,8 +940,9 @@
 	vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
 	vcd_property_hdr.sz =
 				sizeof(struct vcd_property_frame_rate);
-	vcd_frame_rate.fps_denominator = frate->denominator;
-	vcd_frame_rate.fps_numerator = frate->numerator;
+	/* v4l2 passes in "fps" as "spf", so take reciprocal*/
+	vcd_frame_rate.fps_denominator = frate->numerator;
+	vcd_frame_rate.fps_numerator = frate->denominator;
 	rc = vcd_set_property(client_ctx->vcd_handle,
 					&vcd_property_hdr, &vcd_frame_rate);
 	if (rc)
@@ -988,8 +987,9 @@
 					mregion->offset,
 					32,
 					mregion->size);
-	if (!rc) {
+	if (rc == (u32)false) {
 		WFD_MSG_ERR("Failed to insert outbuf in table\n");
+		rc = -EINVAL;
 		goto err;
 	}
 	WFD_MSG_DBG("size = %u, %p\n", mregion->size, mregion->kvaddr);
@@ -1040,14 +1040,15 @@
 	int rc = 0;
 	struct venc_inst *inst = sd->dev_priv;
 	struct video_client_ctx *client_ctx = &inst->venc_client;
-	struct mem_region *mregion = arg;
+	struct venc_buf_info *venc_buf = arg;
+	struct mem_region *mregion = venc_buf->mregion;
 	struct vcd_frame_data vcd_input_buffer = {0};
 
 	vcd_input_buffer.virtual = mregion->kvaddr;
 	vcd_input_buffer.frm_clnt_data = (u32)mregion;
 	vcd_input_buffer.ip_frm_tag = (u32)mregion;
 	vcd_input_buffer.data_len = mregion->size;
-	vcd_input_buffer.time_stamp = 0; /*TODO: Need to fix this*/
+	vcd_input_buffer.time_stamp = venc_buf->timestamp;
 	vcd_input_buffer.offset = 0;
 
 	rc = vcd_encode_frame(client_ctx->vcd_handle,
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm/wfd/enc-subdev.h
index 890c973..0f7ca5f 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.h
+++ b/drivers/media/video/msm/wfd/enc-subdev.h
@@ -11,6 +11,9 @@
 *
 */
 
+#ifndef _WFD_ENC_SUBDEV_
+#define _WFD_ENC_SUBDEV_
+
 #include <media/v4l2-subdev.h>
 #include <media/videobuf2-core.h>
 #define VENC_MAGIC_IOCTL 'V'
@@ -30,6 +33,12 @@
 	u32 width;
 	u32 size;
 };
+
+struct venc_buf_info {
+	u64 timestamp;
+	struct mem_region *mregion;
+};
+
 struct venc_msg_ops {
 	void *cookie;
 	void *cbdata;
@@ -42,7 +51,7 @@
 #define OPEN  _IOR('V', 1, void *)
 #define CLOSE  _IO('V', 2)
 #define ENCODE_START  _IO('V', 3)
-#define ENCODE_FRAME  _IO('V', 4)
+#define ENCODE_FRAME  _IOW('V', 4, struct venc_buf_info *)
 #define PAUSE  _IO('V', 5)
 #define RESUME  _IO('V', 6)
 #define FLUSH  _IO('V', 7)
@@ -66,3 +75,6 @@
 extern int venc_init(struct v4l2_subdev *sd, u32 val);
 extern int venc_load_fw(struct v4l2_subdev *sd);
 extern long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
+
+
+#endif /* _WFD_ENC_SUBDEV_ */
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.c b/drivers/media/video/msm/wfd/mdp-subdev.c
index 9fd8a8e..e519a4d 100644
--- a/drivers/media/video/msm/wfd/mdp-subdev.c
+++ b/drivers/media/video/msm/wfd/mdp-subdev.c
@@ -135,8 +135,9 @@
 	fbdata.priv = (uint32_t)binfo->cookie;
 
 	WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
-			"fd = %u, priv = %u\n",
-			fbdata.offset, fbdata.memory_id, fbdata.priv);
+			"fd = %u, priv = %p, iova = %p\n",
+			fbdata.offset, fbdata.memory_id,
+			(void *)fbdata.priv, (void *)fbdata.iova);
 	rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
 
 	if (rc)
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.h b/drivers/media/video/msm/wfd/mdp-subdev.h
index a6b3bc4..081fead 100644
--- a/drivers/media/video/msm/wfd/mdp-subdev.h
+++ b/drivers/media/video/msm/wfd/mdp-subdev.h
@@ -11,6 +11,9 @@
 *
 */
 
+#ifndef _WFD_MDP_SUBDEV_
+#define _WFD_MDP_SUBDEV_
+
 #include <linux/videodev2.h>
 #include <media/v4l2-subdev.h>
 
@@ -30,6 +33,17 @@
 	u32 height;
 	u32 width;
 };
+
+static inline bool mdp_buf_info_equals(struct mdp_buf_info *a,
+		struct mdp_buf_info *b)
+{
+	return a->inst == b->inst
+		&& a->fd == b->fd
+		&& a->offset == b->offset
+		&& a->kvaddr == b->kvaddr
+		&& a->paddr == b->paddr;
+}
+
 #define MDP_Q_BUFFER  _IOW(MDP_MAGIC_IOCTL, 1, struct mdp_buf_info *)
 #define MDP_DQ_BUFFER  _IOR(MDP_MAGIC_IOCTL, 2, struct mdp_out_buf *)
 #define MDP_OPEN  _IOR(MDP_MAGIC_IOCTL, 3, void **)
@@ -39,3 +53,6 @@
 #define MDP_STOP  _IOR(MDP_MAGIC_IOCTL, 7, void *)
 extern int mdp_init(struct v4l2_subdev *sd, u32 val);
 extern long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
+
+
+#endif /* _WFD_MDP_SUBDEV_ */
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.c b/drivers/media/video/msm/wfd/vsg-subdev.c
new file mode 100644
index 0000000..53b6e20
--- /dev/null
+++ b/drivers/media/video/msm/wfd/vsg-subdev.c
@@ -0,0 +1,693 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+#include <linux/hrtimer.h>
+#include <linux/time.h>
+#include <linux/list.h>
+#include <media/videobuf2-core.h>
+#include "enc-subdev.h"
+#include "vsg-subdev.h"
+#include "wfd-util.h"
+
+#define DEFAULT_FRAME_INTERVAL (66*NSEC_PER_MSEC)
+#define DEFAULT_MAX_FRAME_INTERVAL (1*NSEC_PER_SEC)
+#define DEFAULT_MODE ((enum vsg_modes)VSG_MODE_CFR)
+
+static int vsg_release_input_buffer(struct vsg_context *context,
+		struct vsg_buf_info *buf)
+{
+	WFD_MSG_DBG("Releasing frame with ts %lld ms, paddr %p\n",
+			timespec_to_ns(&buf->time),
+			(void *)buf->mdp_buf_info.paddr);
+
+	if (buf->flags & VSG_NEVER_RELEASE)
+		WFD_MSG_WARN("Warning releasing buffer that's"
+				"not supposed to be released\n");
+
+	return context->vmops.release_input_frame(context->vmops.cbdata,
+			buf);
+
+}
+
+static int vsg_encode_frame(struct vsg_context *context,
+		struct vsg_buf_info *buf)
+{
+	WFD_MSG_DBG("Encoding frame with ts %lld ms, paddr %p\n",
+			timespec_to_ns(&buf->time),
+			(void *)buf->mdp_buf_info.paddr);
+
+	return context->vmops.encode_frame(context->vmops.cbdata,
+			buf);
+}
+
+static void vsg_set_last_buffer(struct vsg_context *context,
+		struct vsg_buf_info *buf)
+{
+	if (buf->flags & VSG_NEVER_SET_LAST_BUFFER)
+		WFD_MSG_WARN("Shouldn't be setting this to last buffer\n");
+
+	/* Update the last buffer and memcpy the data into the back up buffer*/
+	context->last_buffer = buf;
+
+	WFD_MSG_DBG("Setting last buffer to paddr %p\n",
+			(void *)buf->mdp_buf_info.paddr);
+
+	if (context->regen_buffer) {
+		int buf_size;
+		void *cookie;
+
+		/*FIXME: Somewhat hacky, looking into cookie */
+		cookie = buf->mdp_buf_info.cookie;
+		buf_size = ((struct mem_region *)cookie)->size;
+
+		memcpy((void *)context->regen_buffer->mdp_buf_info.kvaddr,
+				(void *)buf->mdp_buf_info.kvaddr,
+				buf_size);
+		context->send_regen_buffer = false;
+	}
+}
+
+static void vsg_work_func(struct work_struct *task)
+{
+	struct vsg_work *work =
+		container_of(task, struct vsg_work, work);
+	struct vsg_context *context = work->context;
+	struct vsg_buf_info *buf_info = NULL, *temp = NULL;
+	int rc = 0;
+	mutex_lock(&context->mutex);
+
+	if (list_empty(&context->free_queue.node)) {
+		WFD_MSG_DBG("%s: queue empty doing nothing\n", __func__);
+		goto err_skip_encode;
+	} else if (context->stopped) {
+		WFD_MSG_DBG("%s: vsg is stopped doing nothing\n", __func__);
+		goto err_skip_encode;
+	}
+
+	buf_info = list_first_entry(&context->free_queue.node,
+			struct vsg_buf_info, node);
+	list_del(&buf_info->node);
+	INIT_LIST_HEAD(&buf_info->node);
+
+	ktime_get_ts(&buf_info->time);
+	mod_timer(&context->threshold_timer, jiffies +
+			nsecs_to_jiffies(context->max_frame_interval));
+
+	list_for_each_entry(temp, &context->busy_queue.node, node) {
+		if (mdp_buf_info_equals(&temp->mdp_buf_info,
+					&buf_info->mdp_buf_info)) {
+			WFD_MSG_DBG("Buffer %p already in queue "
+				"to be encoded, delaying encoding\n",
+				(void *)temp->mdp_buf_info.paddr);
+			list_add(&buf_info->node, &context->free_queue.node);
+			/* just skip the push to encoder*/
+			goto err_skip_encode;
+		}
+	}
+
+	mutex_unlock(&context->mutex);
+	rc = vsg_encode_frame(context, buf_info);
+	if (rc < 0) {
+		WFD_MSG_ERR("frame encode failed");
+		goto err_encode_fail;
+	}
+	mutex_lock(&context->mutex);
+
+	list_add_tail(&buf_info->node, &context->busy_queue.node);
+err_skip_encode:
+	mutex_unlock(&context->mutex);
+err_encode_fail:
+	kfree(work);
+}
+
+static void vsg_timer_helper_func(struct work_struct *task)
+{
+	struct vsg_work *work =
+		container_of(task, struct vsg_work, work);
+	struct vsg_work *new_work = NULL;
+	struct vsg_context *context = work->context;
+	int num_bufs_to_queue = 1, c = 0;
+
+	mutex_lock(&context->mutex);
+
+	if (context->stopped)
+		goto err_locked;
+
+	if (list_empty(&context->free_queue.node)
+		&& context->last_buffer) {
+		struct vsg_buf_info *info = NULL, *buf_to_encode = NULL;
+
+		if (context->mode == VSG_MODE_CFR)
+			num_bufs_to_queue = 1;
+		else if (context->mode == VSG_MODE_VFR)
+			num_bufs_to_queue = 2;
+
+		for (c = 0; c < num_bufs_to_queue; ++c) {
+			info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+			if (!info) {
+				WFD_MSG_ERR("Couldn't allocate memory in %s\n",
+					__func__);
+				goto err_locked;
+			}
+
+			if (context->regen_buffer) {
+				if (context->send_regen_buffer) {
+					buf_to_encode =
+						context->regen_buffer;
+				} else {
+					buf_to_encode = context->last_buffer;
+				}
+
+				context->send_regen_buffer =
+					!context->send_regen_buffer;
+			} else {
+				WFD_MSG_WARN("Have no regen buffer\n");
+				buf_to_encode = context->last_buffer;
+			}
+
+			info->mdp_buf_info = buf_to_encode->mdp_buf_info;
+			info->flags = buf_to_encode->flags;
+			INIT_LIST_HEAD(&info->node);
+			list_add_tail(&info->node, &context->free_queue.node);
+			WFD_MSG_DBG("Regenerated frame with paddr %p\n",
+				(void *)info->mdp_buf_info.paddr);
+		}
+	}
+
+	for (c = 0; c < num_bufs_to_queue; ++c) {
+		new_work = kzalloc(sizeof(*new_work), GFP_KERNEL);
+		if (!new_work) {
+			WFD_MSG_ERR("Unable to allocate memory"
+					"to queue buffer\n");
+			goto err_locked;
+		}
+
+		INIT_WORK(&new_work->work, vsg_work_func);
+		new_work->context = context;
+		queue_work(context->work_queue, &new_work->work);
+	}
+
+err_locked:
+	mutex_unlock(&context->mutex);
+	kfree(work);
+}
+
+static void vsg_threshold_timeout_func(unsigned long data)
+{
+	struct vsg_context *context = (struct vsg_context *)data;
+	struct vsg_work *task = kzalloc(sizeof(*task), GFP_ATOMIC);
+
+	if (!task) {
+		WFD_MSG_ERR("Out of memory in %s", __func__);
+		goto threshold_err_bad_param;
+	} else if (!context) {
+		WFD_MSG_ERR("Context not proper in %s", __func__);
+		goto threshold_err_bad_param;
+	}
+
+	mod_timer(&context->threshold_timer, jiffies +
+			nsecs_to_jiffies(context->max_frame_interval));
+
+	INIT_WORK(&task->work, vsg_timer_helper_func);
+	task->context = context;
+
+	queue_work(context->work_queue, &task->work);
+threshold_err_bad_param:
+	return;
+}
+
+int vsg_init(struct v4l2_subdev *sd, u32 val)
+{
+	return 0;
+}
+
+static int vsg_open(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+
+	if (!arg || !sd)
+		return -EINVAL;
+
+	context = kzalloc(sizeof(*context), GFP_KERNEL);
+	INIT_LIST_HEAD(&context->free_queue.node);
+	INIT_LIST_HEAD(&context->busy_queue.node);
+
+	context->vmops = *(struct vsg_msg_ops *)arg;
+	context->work_queue = create_singlethread_workqueue("v4l-vsg");
+
+	context->frame_interval = DEFAULT_FRAME_INTERVAL;
+	context->max_frame_interval = DEFAULT_MAX_FRAME_INTERVAL;
+
+	context->threshold_timer = (struct timer_list)
+		TIMER_INITIALIZER(vsg_threshold_timeout_func,
+				context->max_frame_interval,
+				(unsigned long)context);
+
+	context->last_buffer = context->regen_buffer = NULL;
+	context->send_regen_buffer = false;
+	context->mode = DEFAULT_MODE;
+	context->stopped = false;
+	mutex_init(&context->mutex);
+
+	sd->dev_priv = context;
+	return 0;
+}
+
+static int vsg_close(struct v4l2_subdev *sd)
+{
+	struct vsg_context *context = NULL;
+
+	if (!sd)
+		return -EINVAL;
+
+	context = (struct vsg_context *)sd->dev_priv;
+	destroy_workqueue(context->work_queue);
+	kfree(context->regen_buffer);
+	kfree(context);
+	return 0;
+}
+
+static int vsg_start(struct v4l2_subdev *sd)
+{
+	struct vsg_context *context = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		return -EINVAL;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	mod_timer(&context->threshold_timer, jiffies +
+			nsecs_to_jiffies(context->max_frame_interval));
+	return 0;
+}
+
+static int vsg_stop(struct v4l2_subdev *sd)
+{
+	struct vsg_context *context = NULL;
+
+	if (!sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		return -EINVAL;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+
+	mutex_lock(&context->mutex);
+	context->stopped = true;
+	{ /*delete pending buffers as we're not going to encode them*/
+		struct list_head *pos, *next;
+		list_for_each_safe(pos, next, &context->free_queue.node) {
+			struct vsg_buf_info *temp =
+				list_entry(pos, struct vsg_buf_info, node);
+			list_del(&temp->node);
+			kfree(temp);
+		}
+	}
+
+	del_timer_sync(&context->threshold_timer);
+
+	mutex_unlock(&context->mutex);
+
+	flush_workqueue(context->work_queue);
+	return 0;
+}
+
+static long vsg_queue_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+	struct vsg_buf_info *buf_info = kzalloc(sizeof(*buf_info), GFP_KERNEL);
+	int rc = 0;
+	bool push = false;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		rc = -EINVAL;
+		goto queue_err_bad_param;
+	} else if (!buf_info) {
+		WFD_MSG_ERR("ERROR, out of memory in %s\n", __func__);
+		rc = -ENOMEM;
+		goto queue_err_bad_param;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	mutex_lock(&context->mutex);
+
+	*buf_info = *(struct vsg_buf_info *)arg;
+	INIT_LIST_HEAD(&buf_info->node);
+	buf_info->flags = 0;
+	ktime_get_ts(&buf_info->time);
+
+	WFD_MSG_DBG("Queue frame with paddr %p\n",
+			(void *)buf_info->mdp_buf_info.paddr);
+
+	{ /*return pending buffers as we're not going to encode them*/
+		struct list_head *pos, *next;
+		list_for_each_safe(pos, next, &context->free_queue.node) {
+			struct vsg_buf_info *temp =
+				list_entry(pos, struct vsg_buf_info, node);
+			bool is_last_buffer, is_regen_buffer;
+
+			is_last_buffer = context->last_buffer &&
+				mdp_buf_info_equals(
+					&context->last_buffer->mdp_buf_info,
+					&temp->mdp_buf_info);
+
+			is_regen_buffer = context->regen_buffer &&
+				mdp_buf_info_equals(
+					&context->regen_buffer->mdp_buf_info,
+					&temp->mdp_buf_info);
+
+			if (!is_last_buffer && !is_regen_buffer &&
+				!(temp->flags & VSG_NEVER_RELEASE)) {
+				vsg_release_input_buffer(context, temp);
+			}
+
+			list_del(&temp->node);
+			kfree(temp);
+		}
+	}
+
+	list_add_tail(&buf_info->node, &context->free_queue.node);
+
+	if (context->mode == VSG_MODE_VFR) {
+		if (!context->last_buffer)
+			push = true;
+		else {
+			struct timespec diff = timespec_sub(buf_info->time,
+					context->last_buffer->time);
+			struct timespec temp = ns_to_timespec(
+						context->frame_interval);
+
+			if (timespec_compare(&diff, &temp) >= 0)
+				push = true;
+		}
+	}
+
+	if (push) {
+		struct vsg_work *new_work =
+			kzalloc(sizeof(*new_work), GFP_KERNEL);
+
+		INIT_WORK(&new_work->work, vsg_work_func);
+		new_work->context = context;
+		queue_work(context->work_queue, &new_work->work);
+	}
+
+	mutex_unlock(&context->mutex);
+queue_err_bad_param:
+	if (rc < 0)
+		kfree(buf_info);
+
+	return rc;
+}
+
+static long vsg_return_ip_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+	struct vsg_buf_info *buf_info, *last_buffer,
+			*regen_buffer, *expected_buffer;
+	int rc = 0;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		rc = -EINVAL;
+		goto return_ip_buf_err_bad_param;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	mutex_lock(&context->mutex);
+	buf_info = (struct vsg_buf_info *)arg;
+	last_buffer = context->last_buffer;
+	regen_buffer = context->regen_buffer;
+
+	expected_buffer = list_first_entry(&context->busy_queue.node,
+			struct vsg_buf_info, node);
+
+	WFD_MSG_DBG("Return frame with paddr %p\n",
+			(void *)buf_info->mdp_buf_info.paddr);
+
+	if (mdp_buf_info_equals(&expected_buffer->mdp_buf_info,
+				&buf_info->mdp_buf_info)) {
+		list_del(&expected_buffer->node);
+
+		if (!(expected_buffer->flags & VSG_NEVER_SET_LAST_BUFFER)) {
+			bool is_same_buffer = context->last_buffer &&
+				mdp_buf_info_equals(
+					&context->last_buffer->mdp_buf_info,
+					&expected_buffer->mdp_buf_info);
+
+			if (!context->last_buffer || !is_same_buffer) {
+				struct vsg_buf_info *old_last_buffer =
+					context->last_buffer;
+				if (context->last_buffer)
+					vsg_release_input_buffer(context,
+							context->last_buffer);
+				vsg_set_last_buffer(context, expected_buffer);
+				kfree(old_last_buffer);
+			}
+		} else
+			WFD_MSG_WARN("Couldn't set the last buffer\n");
+	} else {
+		WFD_MSG_ERR("Returned buffer %p is not latest buffer, "
+				"expected %p\n",
+				(void *)buf_info->mdp_buf_info.paddr,
+				(void *)expected_buffer->mdp_buf_info.paddr);
+		rc = -EINVAL;
+		goto return_ip_buf_bad_buf;
+	}
+
+return_ip_buf_bad_buf:
+	mutex_unlock(&context->mutex);
+return_ip_buf_err_bad_param:
+	return rc;
+}
+
+static long vsg_set_scratch_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+	struct vsg_buf_info *buf_info;
+	struct vsg_buf_info *regen_buffer =
+		kzalloc(sizeof(*regen_buffer), GFP_KERNEL);
+	int rc = 0;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		rc = -EINVAL;
+		goto set_scratch_buf_err_bad_param;
+	} else if (!regen_buffer) {
+		WFD_MSG_ERR("ERROR, out of memory in %s\n", __func__);
+		rc = -ENOMEM;
+		goto set_scratch_buf_err_bad_param;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	buf_info = (struct vsg_buf_info *)arg;
+
+	mutex_lock(&context->mutex);
+	*regen_buffer = *buf_info;
+	regen_buffer->flags = VSG_NEVER_RELEASE | VSG_NEVER_SET_LAST_BUFFER;
+	context->regen_buffer = regen_buffer;
+	WFD_MSG_ERR("setting buffer with paddr %p as scratch buffer\n",
+			(void *)regen_buffer->mdp_buf_info.paddr);
+	mutex_unlock(&context->mutex);
+set_scratch_buf_err_bad_param:
+	return rc;
+}
+
+static long vsg_set_frame_interval(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+	int64_t interval;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		return -EINVAL;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	interval = *(int64_t *)arg;
+
+	if (interval <= 0) {
+		WFD_MSG_ERR("ERROR, invalid interval %lld into %s\n",
+				interval, __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&context->mutex);
+
+	context->frame_interval = interval;
+	if (interval > context->max_frame_interval) {
+		WFD_MSG_WARN("Changing max frame interval from %lld to %lld\n",
+				context->max_frame_interval, interval);
+		context->max_frame_interval = interval;
+	}
+
+	mutex_unlock(&context->mutex);
+	return 0;
+}
+
+static long vsg_get_frame_interval(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		return -EINVAL;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	mutex_lock(&context->mutex);
+	*(int64_t *)arg = context->frame_interval;
+	mutex_unlock(&context->mutex);
+
+	return 0;
+}
+
+static long vsg_set_max_frame_interval(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+	int64_t interval;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		return -EINVAL;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	interval = *(int64_t *)arg;
+
+	if (interval <= 0) {
+		WFD_MSG_ERR("ERROR, invalid interval %lld into %s\n",
+				interval, __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&context->mutex);
+
+	context->max_frame_interval = interval;
+	if (interval < context->frame_interval) {
+		WFD_MSG_WARN("Changing frame interval from %lld to %lld\n",
+				context->frame_interval, interval);
+		context->frame_interval = interval;
+	}
+
+	mutex_unlock(&context->mutex);
+
+	return 0;
+}
+
+static long vsg_get_max_frame_interval(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		return -EINVAL;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	mutex_lock(&context->mutex);
+	*(int64_t *)arg = context->max_frame_interval;
+	mutex_unlock(&context->mutex);
+
+	return 0;
+}
+
+static long vsg_set_mode(struct v4l2_subdev *sd, void *arg)
+{
+	struct vsg_context *context = NULL;
+	enum vsg_modes *mode = NULL;
+	int rc = 0;
+
+	if (!arg || !sd) {
+		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+		rc = -EINVAL;
+		goto set_mode_err_bad_parm;
+	}
+
+	context = (struct vsg_context *)sd->dev_priv;
+	mutex_lock(&context->mutex);
+	mode = arg;
+
+	switch (*mode) {
+	case VSG_MODE_CFR:
+		context->max_frame_interval = context->frame_interval;
+		/*fall through*/
+	case VSG_MODE_VFR:
+		context->mode = *mode;
+		break;
+	default:
+		context->mode = DEFAULT_MODE;
+		rc = -EINVAL;
+		goto set_mode_err_bad_mode;
+		break;
+	}
+
+set_mode_err_bad_mode:
+	mutex_unlock(&context->mutex);
+set_mode_err_bad_parm:
+	return rc;
+}
+
+long vsg_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	int rc = 0;
+
+	WFD_MSG_DBG("VSG ioctl: %d\n", cmd);
+	if (sd == NULL)
+		return -EINVAL;
+
+	switch (cmd) {
+	case VSG_OPEN:
+		rc = vsg_open(sd, arg);
+		break;
+	case VSG_CLOSE:
+		rc = vsg_close(sd);
+		break;
+	case VSG_START:
+		rc = vsg_start(sd);
+		break;
+	case VSG_STOP:
+		rc = vsg_stop(sd);
+		break;
+	case VSG_Q_BUFFER:
+		rc = vsg_queue_buffer(sd, arg);
+		break;
+	case VSG_RETURN_IP_BUFFER:
+		rc = vsg_return_ip_buffer(sd, arg);
+		break;
+	case VSG_SET_SCRATCH_BUFFER:
+		rc = vsg_set_scratch_buffer(sd, arg);
+		break;
+	case VSG_GET_FRAME_INTERVAL:
+		rc = vsg_get_frame_interval(sd, arg);
+		break;
+	case VSG_SET_FRAME_INTERVAL:
+		rc = vsg_set_frame_interval(sd, arg);
+		break;
+	case VSG_GET_MAX_FRAME_INTERVAL:
+		rc = vsg_get_max_frame_interval(sd, arg);
+		break;
+	case VSG_SET_MAX_FRAME_INTERVAL:
+		rc = vsg_set_max_frame_interval(sd, arg);
+		break;
+	case VSG_SET_MODE:
+		rc = vsg_set_mode(sd, arg);
+		break;
+	default:
+		rc = -ENOTSUPP;
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.h b/drivers/media/video/msm/wfd/vsg-subdev.h
new file mode 100644
index 0000000..1db45e8
--- /dev/null
+++ b/drivers/media/video/msm/wfd/vsg-subdev.h
@@ -0,0 +1,88 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#ifndef _WFD_VSG_SUBDEV_
+#define _WFD_VSG_SUBDEV_
+
+#include <linux/videodev2.h>
+#include <linux/list.h>
+#include <linux/ktime.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-subdev.h>
+#include "mdp-subdev.h"
+
+#define VSG_MAGIC_IOCTL 'V'
+
+enum vsg_flags {
+	VSG_NEVER_RELEASE = 1<<0,
+	VSG_NEVER_SET_LAST_BUFFER = 1<<1,
+};
+
+enum vsg_modes {
+	VSG_MODE_CFR,
+	VSG_MODE_VFR,
+};
+
+struct vsg_buf_info {
+	struct mdp_buf_info mdp_buf_info;
+	struct timespec time;
+	/* Internal */
+	struct list_head node;
+	uint32_t flags;
+};
+
+struct vsg_msg_ops {
+	void *cbdata;
+	int (*encode_frame)(void *cbdata, struct vsg_buf_info *buffer);
+	int (*release_input_frame)(void *cbdata, struct vsg_buf_info *buffer);
+};
+
+struct vsg_context {
+	struct vsg_buf_info	free_queue, busy_queue;
+	struct vsg_msg_ops vmops;
+	/* All time related values below in nanosecs */
+	int64_t frame_interval, max_frame_interval;
+	struct workqueue_struct *work_queue;
+	struct timer_list threshold_timer;
+	struct mutex mutex;
+	struct vsg_buf_info *last_buffer, *regen_buffer;
+	bool send_regen_buffer;
+	int mode;
+	bool stopped;
+};
+
+struct vsg_work {
+	struct vsg_context *context;
+	struct work_struct work;
+};
+
+#define VSG_OPEN  _IO(VSG_MAGIC_IOCTL, 1)
+#define VSG_CLOSE  _IO(VSG_MAGIC_IOCTL, 2)
+#define VSG_START  _IO(VSG_MAGIC_IOCTL, 3)
+#define VSG_STOP  _IO(VSG_MAGIC_IOCTL, 4)
+#define VSG_Q_BUFFER  _IOW(VSG_MAGIC_IOCTL, 5, struct vsg_buf_info *)
+#define VSG_DQ_BUFFER  _IOR(VSG_MAGIC_IOCTL, 6, struct vsg_out_buf *)
+#define VSG_RETURN_IP_BUFFER _IOW(VSG_MAGIC_IOCTL, 7, struct vsg_buf_info *)
+#define VSG_ENCODE_DONE _IO(VSG_MAGIC_IOCTL, 8)
+#define VSG_SET_SCRATCH_BUFFER _IOW(VSG_MAGIC_IOCTL, 9, struct vsg_buf_info *)
+/* Time related arguments for frame interval ioctls are always in nanosecs*/
+#define VSG_SET_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 10, int64_t *)
+#define VSG_GET_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 11, int64_t *)
+#define VSG_SET_MAX_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 12, int64_t *)
+#define VSG_GET_MAX_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 13, int64_t *)
+#define VSG_SET_MODE _IOW(VSG_MAGIC_IOCTL, 14, enum vsg_modes *)
+
+extern int vsg_init(struct v4l2_subdev *sd, u32 val);
+extern long vsg_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
+
+#endif /* _WFD_VSG_SUBDEV_ */
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 93dd367..315705c 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -21,6 +21,7 @@
 #include <linux/android_pmem.h>
 #include <linux/sched.h>
 #include <linux/kthread.h>
+#include <linux/time.h>
 
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
@@ -31,12 +32,14 @@
 #include "wfd-util.h"
 #include "mdp-subdev.h"
 #include "enc-subdev.h"
+#include "vsg-subdev.h"
 
 #define WFD_VERSION KERNEL_VERSION(0, 0, 1)
 #define DEFAULT_WFD_WIDTH 640
 #define DEFAULT_WFD_HEIGHT 480
-#define MIN_BUF_COUNT 2
-#define VENC_INPUT_BUFFERS 3
+#define VSG_SCRATCH_BUFFERS 1
+#define MDP_WRITEBACK_BUFFERS 3
+#define VENC_INPUT_BUFFERS (VSG_SCRATCH_BUFFERS + MDP_WRITEBACK_BUFFERS)
 
 struct wfd_device {
 	struct platform_device *pdev;
@@ -44,6 +47,7 @@
 	struct video_device *pvdev;
 	struct v4l2_subdev mdp_sdev;
 	struct v4l2_subdev enc_sdev;
+	struct v4l2_subdev vsg_sdev;
 };
 
 struct mem_info {
@@ -116,7 +120,8 @@
 	struct mem_region *mregion;
 	int rc;
 	unsigned long flags;
-	struct mdp_buf_info buf = {0};
+	struct mdp_buf_info mdp_buf = {0};
+	struct vsg_buf_info vsg_buf = {};
 	spin_lock_irqsave(&inst->inst_lock, flags);
 	if (inst->input_bufs_allocated) {
 		spin_unlock_irqrestore(&inst->inst_lock, flags);
@@ -133,27 +138,44 @@
 		if (rc) {
 			WFD_MSG_ERR("Failed to allocate input memory."
 				" This error causes memory leak!!!\n");
-			break;
+			goto alloc_fail;
 		}
 		WFD_MSG_DBG("NOTE: paddr = %p, kvaddr = %p\n", mregion->paddr,
 					mregion->kvaddr);
 		list_add_tail(&mregion->list, &inst->input_mem_list);
-		buf.inst = inst->mdp_inst;
-		buf.cookie = mregion;
-		buf.kvaddr = (u32) mregion->kvaddr;
-		buf.paddr = (u32) mregion->paddr;
-		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
-				MDP_Q_BUFFER, (void *)&buf);
-		if (rc) {
-			WFD_MSG_ERR("Unable to queue the buffer to mdp\n");
-			break;
+
+		mdp_buf.inst = inst->mdp_inst;
+		mdp_buf.cookie = mregion;
+		mdp_buf.kvaddr = (u32) mregion->kvaddr;
+		mdp_buf.paddr = (u32) mregion->paddr;
+		vsg_buf.mdp_buf_info = mdp_buf;
+
+		if (i < MDP_WRITEBACK_BUFFERS) {
+			rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+					MDP_Q_BUFFER, (void *)&mdp_buf);
+			if (rc) {
+				WFD_MSG_ERR("Unable to queue the"
+						" buffer to mdp\n");
+				break;
+			}
+		} else /*if (i < VSG_SCRATCH_BUFFERS*/ {
+			rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
+					VSG_SET_SCRATCH_BUFFER,
+					(void *)&vsg_buf);
+			if (rc) {
+				WFD_MSG_ERR("Unable to set scratch"
+						" buffer to vsg\n");
+				break;
+			}
 		}
 	}
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 			ALLOC_RECON_BUFFERS, NULL);
-	if (rc)
+	if (rc) {
 		WFD_MSG_ERR("Failed to allocate recon buffers\n");
-
+		goto alloc_fail;
+	}
+alloc_fail:
 	return rc;
 }
 void wfd_free_input_buffers(struct wfd_device *wfd_dev,
@@ -258,7 +280,7 @@
 		rc = wfd_allocate_input_buffers(wfd_dev, inst);
 		if (rc) {
 			WFD_MSG_ERR("Failed to allocate input buffers\n");
-			goto err;
+			goto free_input_bufs;
 		}
 		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 				SET_OUTPUT_BUFFER, (void *)&mregion);
@@ -270,7 +292,6 @@
 	return rc;
 free_input_bufs:
 	wfd_free_input_buffers(wfd_dev, inst);
-err:
 	return rc;
 }
 
@@ -294,6 +315,12 @@
 	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
 	struct mem_info *minfo = vb2_plane_cookie(vb, 0);
 	struct mem_region mregion;
+
+	if (minfo == NULL) {
+		WFD_MSG_ERR("not freeing buffers since allocation failed");
+		return;
+	}
+
 	mregion.fd = minfo->fd;
 	mregion.offset = minfo->offset;
 	mregion.cookie = (u32)vb;
@@ -306,6 +333,7 @@
 	wfd_unregister_out_buf(inst, minfo);
 	wfd_free_input_buffers(wfd_dev, inst);
 }
+
 static int mdp_output_thread(void *data)
 {
 	int rc = 0;
@@ -313,11 +341,13 @@
 	struct wfd_inst *inst = filp->private_data;
 	struct wfd_device *wfd_dev =
 		(struct wfd_device *)video_drvdata(filp);
-	struct mdp_buf_info obuf = {inst->mdp_inst, 0, 0, 0};
+	struct mdp_buf_info obuf_mdp = {inst->mdp_inst, 0, 0, 0};
+	struct mem_region *mregion;
+	struct vsg_buf_info ibuf_vsg;
 	while (!kthread_should_stop()) {
 		WFD_MSG_DBG("waiting for mdp output\n");
 		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
-			core, ioctl, MDP_DQ_BUFFER, (void *)&obuf);
+			core, ioctl, MDP_DQ_BUFFER, (void *)&obuf_mdp);
 
 		if (rc) {
 			WFD_MSG_ERR("Either streamoff called or"
@@ -325,8 +355,21 @@
 			break;
 		}
 
-		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
-			ENCODE_FRAME, obuf.cookie);
+		mregion = obuf_mdp.cookie;
+		if (!mregion) {
+			WFD_MSG_ERR("mdp cookie is null\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		ibuf_vsg.mdp_buf_info = obuf_mdp;
+		ibuf_vsg.mdp_buf_info.inst = inst->mdp_inst;
+		ibuf_vsg.mdp_buf_info.cookie = mregion;
+		ibuf_vsg.mdp_buf_info.kvaddr = (u32) mregion->kvaddr;
+		ibuf_vsg.mdp_buf_info.paddr = (u32) mregion->paddr;
+		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev,
+			core, ioctl, VSG_Q_BUFFER, (void *)&ibuf_vsg);
+
 		if (rc) {
 			WFD_MSG_ERR("Failed to encode frame\n");
 			break;
@@ -348,20 +391,27 @@
 			ENCODE_START, (void *)inst->venc_inst);
 	if (rc) {
 		WFD_MSG_ERR("Failed to start encoder\n");
-		goto err;
+		goto subdev_start_fail;
+	}
+
+	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
+			VSG_START, NULL);
+	if (rc) {
+		WFD_MSG_ERR("Failed to start vsg\n");
+		goto subdev_start_fail;
 	}
 
 	inst->mdp_task = kthread_run(mdp_output_thread, priv_data,
 				"mdp_output_thread");
 	if (IS_ERR(inst->mdp_task)) {
 		rc = PTR_ERR(inst->mdp_task);
-		goto err;
+		goto subdev_start_fail;
 	}
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 			 MDP_START, (void *)inst->mdp_inst);
 	if (rc)
 		WFD_MSG_ERR("Failed to start MDP\n");
-err:
+subdev_start_fail:
 	return rc;
 }
 
@@ -377,6 +427,11 @@
 	if (rc)
 		WFD_MSG_ERR("Failed to stop MDP\n");
 
+	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
+			 VSG_STOP, NULL);
+	if (rc)
+		WFD_MSG_ERR("Failed to stop VSG\n");
+
 	kthread_stop(inst->mdp_task);
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 			ENCODE_STOP, (void *)inst->venc_inst);
@@ -441,8 +496,17 @@
 
 static const struct v4l2_subdev_ops enc_subdev_ops = {
 	.core = &enc_subdev_core_ops,
-}
-;
+};
+
+static const struct v4l2_subdev_core_ops vsg_subdev_core_ops = {
+	.init = vsg_init,
+	.ioctl = vsg_ioctl,
+};
+
+static const struct v4l2_subdev_ops vsg_subdev_ops = {
+	.core = &vsg_subdev_core_ops,
+};
+
 static int wfdioc_querycap(struct file *filp, void *fh,
 		struct v4l2_capability *cap) {
 	WFD_MSG_DBG("wfdioc_querycap: E\n");
@@ -476,6 +540,7 @@
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 	return 0;
 }
+
 static int wfdioc_s_fmt(struct file *filp, void *fh,
 			struct v4l2_format *fmt)
 {
@@ -499,7 +564,7 @@
 				(void *)fmt);
 	if (rc) {
 		WFD_MSG_ERR("Failed to set format on encoder, rc = %d\n", rc);
-		goto err;
+		return rc;
 	}
 	breq.count = VENC_INPUT_BUFFERS;
 	breq.height = fmt->fmt.pix.height;
@@ -508,7 +573,7 @@
 			SET_BUFFER_REQ, (void *)&breq);
 	if (rc) {
 		WFD_MSG_ERR("Failed to set buffer reqs on encoder\n");
-		goto err;
+		return rc;
 	}
 	spin_lock_irqsave(&inst->inst_lock, flags);
 	inst->input_buf_size = breq.size;
@@ -521,7 +586,6 @@
 				(void *)&prop);
 	if (rc)
 		WFD_MSG_ERR("Failed to set height/width property on mdp\n");
-err:
 	return rc;
 }
 static int wfdioc_reqbufs(struct file *filp, void *fh,
@@ -542,13 +606,12 @@
 			GET_BUFFER_REQ, (void *)b);
 	if (rc) {
 		WFD_MSG_ERR("Failed to get buf reqs from encoder\n");
-		goto err;
+		return rc;
 	}
 	spin_lock_irqsave(&inst->inst_lock, flags);
 	inst->buf_count = b->count;
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 	rc = vb2_reqbufs(&inst->vid_bufq, b);
-err:
 	return rc;
 }
 static int wfd_register_out_buf(struct wfd_inst *inst,
@@ -593,12 +656,11 @@
 	rc = wfd_register_out_buf(inst, b);
 	if (rc) {
 		WFD_MSG_ERR("Failed to register buffer\n");
-		goto err;
+		return rc;
 	}
 	rc = vb2_qbuf(&inst->vid_bufq, b);
 	if (rc)
 		WFD_MSG_ERR("Failed to queue buffer\n");
-err:
 	return rc;
 }
 
@@ -634,6 +696,13 @@
 {
 	struct wfd_inst *inst = filp->private_data;
 	unsigned long flags;
+
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		WFD_MSG_ERR("stream off for buffer type = %d is not "
+			"supported.\n", i);
+		return -EINVAL;
+	}
+
 	spin_lock_irqsave(&inst->inst_lock, flags);
 	if (inst->streamoff) {
 		WFD_MSG_ERR("Module is already in streamoff state\n");
@@ -642,11 +711,6 @@
 	}
 	inst->streamoff = true;
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
-	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		WFD_MSG_ERR("stream off for buffer type = %d is not "
-			"supported.\n", i);
-		return -EINVAL;
-	}
 	WFD_MSG_DBG("Calling videobuf_streamoff\n");
 	vb2_streamoff(&inst->vid_bufq, i);
 	return 0;
@@ -680,6 +744,148 @@
 		WFD_MSG_ERR("Failed to set encoder property\n");
 	return rc;
 }
+
+static int wfdioc_g_parm(struct file *filp, void *fh,
+		struct v4l2_streamparm *a)
+{
+	int rc = 0;
+	struct wfd_device *wfd_dev = video_drvdata(filp);
+	struct wfd_inst *inst = filp->private_data;
+	int64_t frame_interval = 0,
+		max_frame_interval = 0; /* both in nsecs*/
+	struct v4l2_qcom_frameskip frameskip, *usr_frameskip;
+
+	usr_frameskip = (struct v4l2_qcom_frameskip *)
+			a->parm.capture.extendedmode;
+
+	if (!usr_frameskip) {
+		rc = -EINVAL;
+		goto get_parm_fail;
+	}
+	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+			ioctl, VSG_GET_FRAME_INTERVAL, &frame_interval);
+
+	if (rc < 0)
+		goto get_parm_fail;
+
+	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+			ioctl, VSG_GET_MAX_FRAME_INTERVAL, &max_frame_interval);
+
+	if (rc < 0)
+		goto get_parm_fail;
+
+	frameskip = (struct v4l2_qcom_frameskip) {
+		.maxframeinterval = max_frame_interval,
+	};
+
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->parm.capture = (struct v4l2_captureparm) {
+		.capability = V4L2_CAP_TIMEPERFRAME,
+		.capturemode = 0,
+		.timeperframe = (struct v4l2_fract) {
+			.numerator = frame_interval,
+			.denominator = NSEC_PER_SEC,
+		},
+		.readbuffers = inst->buf_count,
+		.extendedmode = (__u32)usr_frameskip,
+		.reserved = {0}
+	};
+
+	rc = copy_to_user((void *)a->parm.capture.extendedmode,
+			&frameskip, sizeof(frameskip));
+	if (rc < 0)
+		goto get_parm_fail;
+
+get_parm_fail:
+	return rc;
+}
+
+static int wfdioc_s_parm(struct file *filp, void *fh,
+		struct v4l2_streamparm *a)
+{
+	int rc = 0;
+	struct wfd_device *wfd_dev = video_drvdata(filp);
+	struct wfd_inst *inst = filp->private_data;
+	struct v4l2_qcom_frameskip frameskip;
+	int64_t frame_interval, max_frame_interval;
+	void *extendedmode = NULL;
+	enum vsg_modes mode = VSG_MODE_VFR;
+
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		rc = -ENOTSUPP;
+		goto set_parm_fail;
+	}
+
+	if (a->parm.capture.readbuffers == 0 ||
+		a->parm.capture.readbuffers == inst->buf_count) {
+		a->parm.capture.readbuffers = inst->buf_count;
+	} else {
+		rc = -EINVAL;
+		goto set_parm_fail;
+	}
+
+	extendedmode = (void *)a->parm.capture.extendedmode;
+	if (a->parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
+		if (a->parm.capture.timeperframe.denominator == 0) {
+			rc = -EINVAL;
+			goto set_parm_fail;
+		}
+		frame_interval =
+			a->parm.capture.timeperframe.numerator * NSEC_PER_SEC /
+			a->parm.capture.timeperframe.denominator;
+
+		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+				ioctl, VSG_SET_FRAME_INTERVAL,
+				&frame_interval);
+
+		if (rc)
+			goto set_parm_fail;
+
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+				ioctl, SET_FRAMERATE,
+				&a->parm.capture.timeperframe);
+
+		if (rc)
+			goto set_parm_fail;
+	}
+
+	if (a->parm.capture.capability & V4L2_CAP_QCOM_FRAMESKIP &&
+		extendedmode) {
+		rc = copy_from_user(&frameskip,
+				extendedmode, sizeof(frameskip));
+
+		if (rc)
+			goto set_parm_fail;
+
+		max_frame_interval = (int64_t)frameskip.maxframeinterval;
+		mode = VSG_MODE_VFR;
+
+		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+				ioctl, VSG_SET_MAX_FRAME_INTERVAL,
+				&max_frame_interval);
+
+		if (rc)
+			goto set_parm_fail;
+
+		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+				ioctl, VSG_SET_MODE, &mode);
+
+		if (rc)
+			goto set_parm_fail;
+	} else {
+		mode = VSG_MODE_CFR;
+		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+				ioctl, VSG_SET_MODE, &mode);
+
+		if (rc)
+			goto set_parm_fail;
+	}
+
+set_parm_fail:
+	return rc;
+}
+
 static const struct v4l2_ioctl_ops g_wfd_ioctl_ops = {
 	.vidioc_querycap = wfdioc_querycap,
 	.vidioc_s_fmt_vid_cap = wfdioc_s_fmt,
@@ -691,7 +897,8 @@
 	.vidioc_dqbuf = wfdioc_dqbuf,
 	.vidioc_g_ctrl = wfdioc_g_ctrl,
 	.vidioc_s_ctrl = wfdioc_s_ctrl,
-
+	.vidioc_g_parm = wfdioc_g_parm,
+	.vidioc_s_parm = wfdioc_s_parm,
 };
 static int wfd_set_default_properties(struct file *filp)
 {
@@ -712,32 +919,69 @@
 	wfdioc_s_fmt(filp, filp->private_data, &fmt);
 	return 0;
 }
-void venc_op_buffer_done(void *cookie, u32 status,
+static void venc_op_buffer_done(void *cookie, u32 status,
 			struct vb2_buffer *buf)
 {
 	WFD_MSG_DBG("yay!! got callback\n");
 	vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
 }
-void venc_ip_buffer_done(void *cookie, u32 status,
+
+static void venc_ip_buffer_done(void *cookie, u32 status,
 			struct mem_region *mregion)
 {
 	struct file *filp = cookie;
 	struct wfd_inst *inst = filp->private_data;
-	struct mdp_buf_info buf = {0};
+	struct vsg_buf_info buf;
+	struct mdp_buf_info mdp_buf = {0};
 	struct wfd_device *wfd_dev =
 		(struct wfd_device *)video_drvdata(filp);
 	int rc = 0;
 	WFD_MSG_DBG("yay!! got ip callback\n");
-	buf.inst = inst->mdp_inst;
-	buf.cookie = mregion;
-	buf.kvaddr = (u32) mregion->kvaddr;
-	buf.paddr = (u32) mregion->paddr;
+	mdp_buf.inst = inst->mdp_inst;
+	mdp_buf.cookie = mregion;
+	mdp_buf.kvaddr = (u32) mregion->kvaddr;
+	mdp_buf.paddr = (u32) mregion->paddr;
+	buf.mdp_buf_info = mdp_buf;
+	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+			ioctl, VSG_RETURN_IP_BUFFER, (void *)&buf);
+	if (rc)
+		WFD_MSG_ERR("Failed to return buffer to vsg\n");
+}
+
+static int vsg_release_input_frame(void *cookie, struct vsg_buf_info *buf)
+{
+	struct file *filp = cookie;
+	struct wfd_device *wfd_dev =
+		(struct wfd_device *)video_drvdata(filp);
+	int rc = 0;
+
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
-			ioctl, MDP_Q_BUFFER, (void *)&buf);
+			ioctl, MDP_Q_BUFFER, buf);
 	if (rc)
 		WFD_MSG_ERR("Failed to Q buffer to mdp\n");
 
+	return rc;
 }
+
+static int vsg_encode_frame(void *cookie, struct vsg_buf_info *buf)
+{
+	struct file *filp = cookie;
+	struct wfd_device *wfd_dev =
+		(struct wfd_device *)video_drvdata(filp);
+	struct venc_buf_info venc_buf;
+
+	if (!buf)
+		return -EINVAL;
+
+	venc_buf = (struct venc_buf_info){
+		.timestamp = timespec_to_ns(&buf->time),
+		.mregion = buf->mdp_buf_info.cookie
+	};
+
+	return v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			ENCODE_FRAME, &venc_buf);
+}
+
 void *wfd_vb2_mem_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
 					unsigned long size, int write)
 {
@@ -776,14 +1020,17 @@
 	int rc = 0;
 	struct wfd_inst *inst;
 	struct wfd_device *wfd_dev;
-	struct venc_msg_ops vmops;
+	struct venc_msg_ops enc_mops;
+	struct vsg_msg_ops vsg_mops;
+
 	WFD_MSG_DBG("wfd_open: E\n");
 	wfd_dev = video_drvdata(filp);
 	inst = kzalloc(sizeof(struct wfd_inst), GFP_KERNEL);
 	if (!inst || !wfd_dev) {
 		WFD_MSG_ERR("Could not allocate memory for "
 			"wfd instance\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto err_mdp_open;
 	}
 	filp->private_data = inst;
 	spin_lock_init(&inst->inst_lock);
@@ -801,21 +1048,34 @@
 		WFD_MSG_ERR("Failed to load video encoder firmware: %d\n", rc);
 		goto err_venc;
 	}
-	vmops.op_buffer_done = venc_op_buffer_done;
-	vmops.ip_buffer_done = venc_ip_buffer_done;
-	vmops.cbdata = filp;
+	enc_mops.op_buffer_done = venc_op_buffer_done;
+	enc_mops.ip_buffer_done = venc_ip_buffer_done;
+	enc_mops.cbdata = filp;
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
-				(void *)&vmops);
-	if (rc || !vmops.cookie) {
+				(void *)&enc_mops);
+	if (rc || !enc_mops.cookie) {
 		WFD_MSG_ERR("Failed to open encoder subdevice: %d\n", rc);
 		goto err_venc;
 	}
-	inst->venc_inst = vmops.cookie;
+	inst->venc_inst = enc_mops.cookie;
+
+	vsg_mops.encode_frame = vsg_encode_frame;
+	vsg_mops.release_input_frame = vsg_release_input_frame;
+	vsg_mops.cbdata = filp;
+	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl, VSG_OPEN,
+				&vsg_mops);
+	if (rc) {
+		WFD_MSG_ERR("Failed to open vsg subdevice: %d\n", rc);
+		goto err_vsg_open;
+	}
 
 	wfd_initialize_vb2_queue(&inst->vid_bufq, filp);
 	wfd_set_default_properties(filp);
 	WFD_MSG_DBG("wfd_open: X\n");
 	return rc;
+
+err_vsg_open:
+	v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, CLOSE, NULL);
 err_venc:
 	v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 				MDP_CLOSE, (void *)inst->mdp_inst);
@@ -842,9 +1102,16 @@
 
 		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 				CLOSE, (void *)inst->venc_inst);
+
 		if (rc)
 			WFD_MSG_ERR("Failed to CLOSE enc subdev: %d\n", rc);
 
+		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
+				VSG_CLOSE, NULL);
+
+		if (rc)
+			WFD_MSG_ERR("Failed to CLOSE vsg subdev: %d\n", rc);
+
 		kfree(inst);
 	}
 	WFD_MSG_DBG("wfd_close: X\n");
@@ -869,7 +1136,8 @@
 	if (!wfd_dev) {
 		WFD_MSG_ERR("Could not allocate memory for "
 				"wfd device\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto err_v4l2_registration;
 	}
 	pdev->dev.platform_data = (void *) wfd_dev;
 	rc = v4l2_device_register(&pdev->dev, &wfd_dev->v4l2_dev);
@@ -917,6 +1185,15 @@
 		goto err_venc_init;
 	}
 
+	v4l2_subdev_init(&wfd_dev->vsg_sdev, &vsg_subdev_ops);
+	strncpy(wfd_dev->vsg_sdev.name, "wfd-vsg", V4L2_SUBDEV_NAME_SIZE);
+	rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
+						&wfd_dev->vsg_sdev);
+	if (rc) {
+		WFD_MSG_ERR("Failed to register vsg subdevice: %d\n", rc);
+		goto err_venc_init;
+	}
+
 	WFD_MSG_DBG("__wfd_probe: X\n");
 	return rc;
 
diff --git a/drivers/media/video/msm/wfd/wfd-util.h b/drivers/media/video/msm/wfd/wfd-util.h
index 038a2cb..3fe03e6 100644
--- a/drivers/media/video/msm/wfd/wfd-util.h
+++ b/drivers/media/video/msm/wfd/wfd-util.h
@@ -16,15 +16,16 @@
 
 /*#define DEBUG_WFD*/
 
+#define WFD_TAG "wfd: "
 #ifdef DEBUG_WFD
-	#define WFD_MSG_INFO(fmt...) pr_info(fmt)
-	#define WFD_MSG_WARN(fmt...) pr_warning(fmt)
-	#define WFD_MSG_DBG(fmt...) pr_debug(fmt)
+	#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
+	#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
+	#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
 #else
 	#define WFD_MSG_INFO(fmt...)
 	#define WFD_MSG_WARN(fmt...)
 	#define WFD_MSG_DBG(fmt...)
 #endif
-	#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR fmt)
-	#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT fmt)
+	#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
+	#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
 #endif
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index 8a556bd..ffcef99 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -29,7 +29,7 @@
 #define REG_IRQ_BASE		0x1BB
 
 #define PM8821_VERSION_MASK	0xFFF0
-#define PM8821_VERSION_VALUE	0x07F0
+#define PM8821_VERSION_VALUE	0x0BF0
 #define PM8821_REVISION_MASK	0x000F
 
 #define SINGLE_IRQ_RESOURCE(_name, _irq) \
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
index f6997ac..0939dd8 100644
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ b/drivers/net/wireless/wcnss/wcnss_riva.c
@@ -61,11 +61,11 @@
 };
 
 static struct vregs_info iris_vregs[] = {
-	{"iris_vddio",  VREG_NULL_CONFIG, 0000000, 0, 0000000, 0,      NULL},
+	{"iris_vddio",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 4000,   NULL},
 	{"iris_vddxo",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000,  NULL},
 	{"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
-	{"iris_vddpa",  VREG_NULL_CONFIG, 3000000, 0, 3000000, 515000, NULL},
-	{"iris_vdddig", VREG_NULL_CONFIG, 0000000, 0, 0000000, 0,      NULL},
+	{"iris_vddpa",  VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
+	{"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1200000, 10000,  NULL},
 };
 
 static struct vregs_info riva_vregs[] = {
@@ -220,7 +220,7 @@
 static int wcnss_vregs_on(struct device *dev,
 		struct vregs_info regulators[], uint size)
 {
-	int i, rc = 0;
+	int i, rc = 0, reg_cnt;
 
 	for (i = 0; i < size; i++) {
 			/* Get regulator source */
@@ -233,9 +233,10 @@
 				goto fail;
 		}
 		regulators[i].state |= VREG_GET_REGULATOR_MASK;
-
+		reg_cnt = regulator_count_voltages(regulators[i].regulator);
 		/* Set voltage to nominal. Exclude swtiches e.g. LVS */
-		if (regulators[i].nominal_min || regulators[i].max_voltage) {
+		if ((regulators[i].nominal_min || regulators[i].max_voltage)
+				&& (reg_cnt > 0)) {
 			rc = regulator_set_voltage(regulators[i].regulator,
 					regulators[i].nominal_min,
 					regulators[i].max_voltage);
@@ -248,7 +249,7 @@
 		}
 
 		/* Vote for PWM/PFM mode if needed */
-		if (regulators[i].uA_load) {
+		if (regulators[i].uA_load && (reg_cnt > 0)) {
 			rc = regulator_set_optimum_mode(regulators[i].regulator,
 					regulators[i].uA_load);
 			if (rc < 0) {
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e24c700..fa8f866 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -293,6 +293,24 @@
 	return 0;
 }
 
+static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
+{
+	return pm8xxx_read_irq_stat(chip->dev->parent,
+					chip->pmic_chg_irq[irq_id]);
+}
+
+/* Treat OverVoltage/UnderVoltage as source missing */
+static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
+{
+	return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
+}
+
+/* Treat OverVoltage/UnderVoltage as source missing */
+static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
+{
+	return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
+}
+
 #define CAPTURE_FSM_STATE_CMD	0xC2
 #define READ_BANK_7		0x70
 #define READ_BANK_4		0x40
@@ -407,21 +425,25 @@
 
 #define PM8921_CHG_V_MIN_MV	3240
 #define PM8921_CHG_V_STEP_MV	20
+#define PM8921_CHG_V_STEP_10_MV_BIT	BIT(7)
 #define PM8921_CHG_VDDMAX_MAX	4500
 #define PM8921_CHG_VDDMAX_MIN	3400
 #define PM8921_CHG_V_MASK	0x7F
-static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
+static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
 {
-	u8 temp;
+	int remainder, voltage_20_step;
+	u8 temp = 0;
 
-	if (voltage < PM8921_CHG_VDDMAX_MIN
-			|| voltage > PM8921_CHG_VDDMAX_MAX) {
-		pr_err("bad mV=%d asked to set\n", voltage);
-		return -EINVAL;
+	voltage_20_step = voltage;
+	remainder = voltage % 20;
+	if (remainder >= 10) {
+		voltage_20_step += 10;
+		temp = PM8921_CHG_V_STEP_10_MV_BIT;
 	}
-	temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
+
+	temp |= (voltage_20_step - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
 	pr_debug("voltage=%d setting %02x\n", voltage, temp);
-	return pm_chg_masked_write(chip, CHG_VDD_MAX, PM8921_CHG_V_MASK, temp);
+	return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
 }
 
 static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
@@ -437,9 +459,53 @@
 	}
 	temp &= PM8921_CHG_V_MASK;
 	*voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
+	if (temp & PM8921_CHG_V_STEP_10_MV_BIT)
+		*voltage = *voltage - 10;
 	return 0;
 }
 
+static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
+{
+	int current_mv, ret, steps, i;
+	bool increase;
+
+	ret = 0;
+
+	if (voltage < PM8921_CHG_VDDMAX_MIN
+		|| voltage > PM8921_CHG_VDDMAX_MAX) {
+		pr_err("bad mV=%d asked to set\n", voltage);
+		return -EINVAL;
+	}
+
+	ret = pm_chg_vddmax_get(chip, &current_mv);
+	if (ret) {
+		pr_err("Failed to read vddmax rc=%d\n", ret);
+		return -EINVAL;
+	}
+	if (current_mv == voltage)
+		return 0;
+
+	/* Only change in increments when USB is present */
+	if (is_usb_chg_plugged_in(chip)) {
+		if (current_mv < voltage) {
+			steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
+			increase = true;
+		} else {
+			steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
+			increase = false;
+		}
+		for (i = 0; i < steps; i++) {
+			if (increase)
+				current_mv += PM8921_CHG_V_STEP_MV;
+			else
+				current_mv -= PM8921_CHG_V_STEP_MV;
+			ret |= __pm_chg_vddmax_set(chip, current_mv);
+		}
+	}
+	ret |= __pm_chg_vddmax_set(chip, voltage);
+	return ret;
+}
+
 #define PM8921_CHG_VDDSAFE_MIN	3400
 #define PM8921_CHG_VDDSAFE_MAX	4500
 static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
@@ -860,24 +926,6 @@
 	return test_bit(interrupt, chip->enabled_irqs);
 }
 
-static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
-{
-	return pm8xxx_read_irq_stat(chip->dev->parent,
-					chip->pmic_chg_irq[irq_id]);
-}
-
-/* Treat OverVoltage/UnderVoltage as source missing */
-static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
-{
-	return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
-}
-
-/* Treat OverVoltage/UnderVoltage as source missing */
-static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
-{
-	return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
-}
-
 static bool is_ext_charging(struct pm8921_chg_chip *chip)
 {
 	union power_supply_propval ret = {0,};