Merge "arm/dt: msmcopper-sim: Add support for SDC2 slot" into msm-3.4
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index 745a3a4..0bdb0f1 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -59,8 +59,7 @@
  */
 struct msm_mmc_slot_reg_data {
 	struct msm_mmc_reg_data *vdd_data; /* keeps VDD/VCC regulator info */
-	struct msm_mmc_reg_data *vccq_data; /* keeps VCCQ regulator info */
-	struct msm_mmc_reg_data *vddp_data; /* keeps VDD Pad regulator info */
+	struct msm_mmc_reg_data *vdd_io_data; /* keeps VDD IO regulator info */
 };
 
 struct msm_mmc_gpio {
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index cbdb51a..a2cba84 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -227,7 +227,7 @@
 config ARCH_MSMCOPPER
 	bool "MSM Copper"
 	select ARCH_MSM_KRAITMP
-	select GPIO_MSM_V2
+	select GPIO_MSM_V3
 	select ARM_GIC
 	select CPU_V7
 	select MSM_SCM if SMP
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 40222b8..08dacea 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -54,7 +54,7 @@
 };
 VREG_CONSUMERS(L7) = {
 	REGULATOR_SUPPLY("8921_l7",		NULL),
-	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.3"),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.3"),
 };
 VREG_CONSUMERS(L8) = {
 	REGULATOR_SUPPLY("8921_l8",		NULL),
@@ -162,7 +162,7 @@
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8921_s4",		NULL),
-	REGULATOR_SUPPLY("sdc_vccq",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.1"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
 	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla-slim"),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 193fc4a..fb507c7 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -56,23 +56,19 @@
 	}
 };
 
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+/* SDCC controllers may require voting for VDD IO voltage */
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
 	/* SDCC1 : eMMC card connected */
 	[SDCC1] = {
-		.name = "sdc_vccq",
+		.name = "sdc_vdd_io",
 		.always_on = 1,
 		.high_vol_level = 1800000,
 		.low_vol_level = 1800000,
 		.hpm_uA = 200000, /* 200mA */
-	}
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
-		.name = "sdc_vddp",
+		.name = "sdc_vdd_io",
 		.high_vol_level = 2950000,
 		.low_vol_level = 1850000,
 		.always_on = 1,
@@ -92,12 +88,12 @@
 	/* SDCC1 : eMMC card connected */
 	[SDCC1] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC1],
-		.vccq_data = &mmc_vccq_reg_data[SDCC1],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
 	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC3],
-		.vddp_data = &mmc_vddp_reg_data[SDCC3],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC3],
 	}
 };
 
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 2f24c95..cb8903c 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -80,7 +80,7 @@
 	REGULATOR_SUPPLY("vdd_dig",		"3-004a"),
 	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
-	REGULATOR_SUPPLY("sdc_vccq",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.1"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar-slim"),
 	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar-slim"),
@@ -129,7 +129,7 @@
 };
 VREG_CONSUMERS(L22) = {
 	REGULATOR_SUPPLY("8038_l22",		NULL),
-	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.3"),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.3"),
 };
 VREG_CONSUMERS(L23) = {
 	REGULATOR_SUPPLY("8038_l23",		NULL),
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 52a11bc..87143ff 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -57,23 +57,19 @@
 	}
 };
 
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
 	/* SDCC1 : eMMC card connected */
 	[SDCC1] = {
-		.name = "sdc_vccq",
+		.name = "sdc_vdd_io",
 		.always_on = 1,
 		.high_vol_level = 1800000,
 		.low_vol_level = 1800000,
 		.hpm_uA = 200000, /* 200mA */
-	}
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
-		.name = "sdc_vddp",
+		.name = "sdc_vdd_io",
 		.high_vol_level = 2950000,
 		.low_vol_level = 1850000,
 		.always_on = 1,
@@ -93,12 +89,12 @@
 	/* SDCC1 : eMMC card connected */
 	[SDCC1] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC1],
-		.vccq_data = &mmc_vccq_reg_data[SDCC1],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
 	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC3],
-		.vddp_data = &mmc_vddp_reg_data[SDCC3],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC3],
 	}
 };
 
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 93c72ea..bc5a892 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -53,7 +53,7 @@
 };
 VREG_CONSUMERS(L7) = {
 	REGULATOR_SUPPLY("8921_l7",		NULL),
-	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.3"),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.3"),
 };
 VREG_CONSUMERS(L8) = {
 	REGULATOR_SUPPLY("8921_l8",		NULL),
@@ -162,9 +162,9 @@
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8921_s4",		NULL),
-	REGULATOR_SUPPLY("sdc_vccq",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.1"),
 	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.2"),
-	REGULATOR_SUPPLY("sdc_vddp",            "msm_sdcc.4"),
+	REGULATOR_SUPPLY("sdc_vdd_io",            "msm_sdcc.4"),
 	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index 1279b75..85785fc 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -65,23 +65,19 @@
 	}
 };
 
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+/* SDCC controllers may require voting for IO operating voltage */
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
 	/* SDCC1 : eMMC card connected */
 	[SDCC1] = {
-		.name = "sdc_vccq",
+		.name = "sdc_vdd_io",
 		.always_on = 1,
 		.high_vol_level = 1800000,
 		.low_vol_level = 1800000,
 		.hpm_uA = 200000, /* 200mA */
-	}
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
-		.name = "sdc_vddp",
+		.name = "sdc_vdd_io",
 		.high_vol_level = 2950000,
 		.low_vol_level = 1850000,
 		.always_on = 1,
@@ -97,7 +93,7 @@
 	},
 	/* SDCC4 : SDIO slot connected */
 	[SDCC4] = {
-		.name = "sdc_vddp",
+		.name = "sdc_vdd_io",
 		.high_vol_level = 1800000,
 		.low_vol_level = 1800000,
 		.always_on = 1,
@@ -111,7 +107,7 @@
 	/* SDCC1 : eMMC card connected */
 	[SDCC1] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC1],
-		.vccq_data = &mmc_vccq_reg_data[SDCC1],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
 	},
 	/* SDCC2 : SDIO card slot connected */
 	[SDCC2] = {
@@ -120,11 +116,11 @@
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC3],
-		.vddp_data = &mmc_vddp_reg_data[SDCC3],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC3],
 	},
 	/* SDCC4 : SDIO card slot connected */
 	[SDCC4] = {
-		.vddp_data = &mmc_vddp_reg_data[SDCC4],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC4],
 	},
 };
 
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 7ed350d..b771386 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -61,7 +61,7 @@
 };
 VREG_CONSUMERS(L13) = {
 	REGULATOR_SUPPLY("8018_l13",		NULL),
-	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("sdc_vdd_io",		"msm_sdcc.1"),
 };
 VREG_CONSUMERS(L14) = {
 	REGULATOR_SUPPLY("8018_l14",		NULL),
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
index 5bdeb94..51e2432 100644
--- a/arch/arm/mach-msm/board-9615-storage.c
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -54,10 +54,10 @@
 };
 
 /* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
 	/* SDCC1 : External card slot connected */
 	[SDCC1] = {
-		.name = "sdc_vddp",
+		.name = "sdc_vdd_io",
 		.high_vol_level = 2950000,
 		.low_vol_level = 1850000,
 		.always_on = true,
@@ -77,7 +77,7 @@
 	/* SDCC1 : External card slot connected */
 	[SDCC1] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC1],
-		.vddp_data = &mmc_vddp_reg_data[SDCC1],
+		.vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
 	}
 };
 
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index df114a3..bada29c 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -471,14 +471,6 @@
 	},
 };
 
-static struct i2c_registry msm9615_i2c_devices[] __initdata = {
-	{
-		I2C_SURF | I2C_FFA | I2C_FLUID,
-		MSM_9615_GSBI5_QUP_I2C_BUS_ID,
-		wcd9xxx_device_info,
-		ARRAY_SIZE(wcd9xxx_device_info),
-	},
-};
 /*
  * MDM9x15 I2S.
  */
@@ -561,6 +553,17 @@
 };
 #endif
 
+static struct i2c_registry msm9615_i2c_devices[] __initdata = {
+#ifdef CONFIG_WCD9310_CODEC
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_9615_GSBI5_QUP_I2C_BUS_ID,
+		wcd9xxx_device_info,
+		ARRAY_SIZE(wcd9xxx_device_info),
+	},
+#endif
+};
+
 static struct slim_boardinfo msm_slim_devices[] = {
 	/* add slimbus slaves as needed */
 #ifdef CONFIG_WCD9310_CODEC
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index a8094e1..94d2543 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -481,6 +481,8 @@
 			"msm_serial_hsl.0", NULL),
 	OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
 			"msm_otg", NULL),
+	OF_DEV_AUXDATA("qcom,dwc-usb3-msm", 0xF9200000, \
+			"msm_dwc3", NULL),
 	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
 			"spi_qsd.1", NULL),
 	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index fc0b0af..dd7967d 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -4650,14 +4650,14 @@
 	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
 	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
 
-	CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_usb30_mock_utmi_clk.c, ""),
-	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_otg"),
-	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, ""),
-	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_usb_hsic_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_usb_hsic_io_cal_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c,    "msm_dwc3"),
+	CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c,     "msm_otg"),
+	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c,   "msm_otg"),
+	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c,	  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c,	  "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
 
 	/* Multimedia clocks */
 	CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
@@ -4782,8 +4782,6 @@
 	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
 
 	/* TODO: Remove dummy clocks as soon as they become unnecessary */
-	CLK_DUMMY("phy_clk",       NULL,    "msm_otg", OFF),
-	CLK_DUMMY("core_clk",      NULL,    "msm_otg", OFF),
 	CLK_DUMMY("dfab_clk",  DFAB_CLK,    "msm_sps", OFF),
 	CLK_DUMMY("mem_clk",       NULL,    "msm_sps", OFF),
 	CLK_DUMMY("bus_clk",       NULL,        "scm", OFF),
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 4f365fa..02e103d 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -464,10 +464,7 @@
 	if (nf->freq_hz == FREQ_END)
 		return -EINVAL;
 
-	/* Check if frequency is actually changed. */
 	cf = clk->current_freq;
-	if (nf == cf)
-		return 0;
 
 	if (clk->enabled) {
 		/* Enable source clock dependency for the new freq. */
@@ -881,9 +878,6 @@
 
 	if (rate > clk->max_div)
 		return -EINVAL;
-	/* Check if frequency is actually changed. */
-	if (rate == clk->cur_div)
-		return 0;
 
 	spin_lock(&local_clock_reg_lock);
 	reg_val = readl_relaxed(clk->ns_reg);
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index cf45e63..c84cfb8 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -166,10 +166,7 @@
 	if (nf->freq_hz == FREQ_END)
 		return -EINVAL;
 
-	/* Check if frequency is actually changed. */
 	cf = rcg->current_freq;
-	if (nf == cf)
-		return 0;
 
 	if (rcg->c.count) {
 		/* TODO: Modify to use the prepare API */
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index ae87bb7..4539828 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -116,10 +116,6 @@
 
 	spin_lock_irqsave(&rpm_clock_lock, flags);
 
-	/* Ignore duplicate requests. */
-	if (r->last_set_khz == this_khz)
-		goto out;
-
 	/* Active-only clocks don't care what the rate is during sleep. So,
 	 * they vote for zero. */
 	if (r->active_only)
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index fb5b580..8a1c6eb 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -320,7 +320,7 @@
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	unsigned long start_rate, flags;
-	int rc;
+	int rc = 0;
 
 	if (IS_ERR_OR_NULL(clk))
 		return -EINVAL;
@@ -329,6 +329,11 @@
 		return -ENOSYS;
 
 	spin_lock_irqsave(&clk->lock, flags);
+
+	/* Return early if the rate isn't going to change */
+	if (clk->rate == rate)
+		goto out;
+
 	trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
 	if (clk->count) {
 		start_rate = clk->rate;
@@ -347,7 +352,7 @@
 
 	if (!rc)
 		clk->rate = rate;
-
+out:
 	spin_unlock_irqrestore(&clk->lock, flags);
 	return rc;
 
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 2c4687f..c480bba 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -127,7 +127,6 @@
 		MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
 		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
 		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
-		MSM_RPM_MAP(8930, DDR_DMM_0, DDR_DMM, 2),
 		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
 		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
 	},
@@ -232,8 +231,6 @@
 		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, DDR_DMM_0),
-		MSM_RPM_STATUS_ID_MAP(8930, DDR_DMM_1),
 		MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
 		MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
 	},
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 8aed079..1d32003 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -178,7 +178,7 @@
 	TLMM_PULL_SDC1_DATA,
 };
 
-#ifdef CONFIG_GPIO_MSM_V2
+#if defined(CONFIG_GPIO_MSM_V2) || defined(CONFIG_GPIO_MSM_V3)
 void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str);
 void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull);
 
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
index 6d27d69..8cd8620 100644
--- a/arch/arm/mach-msm/include/mach/irqs-copper.h
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.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
@@ -35,7 +35,7 @@
 #define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 105)
 
 #define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
-#define NR_GPIO_IRQS 156
+#define NR_GPIO_IRQS 146
 #define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
 #define NR_BOARD_IRQS NR_QPNP_IRQS
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 5ec3a74..6fd9cf4 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -240,10 +240,8 @@
 	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_DDR_DMM_0		= 167,
-	MSM_RPM_8930_ID_DDR_DMM_1		= 168,
-	MSM_RPM_8930_ID_QDSS_CLK	= 168,
-	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 169,
+	MSM_RPM_8930_ID_QDSS_CLK	= 167,
+	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 168,
 	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
 };
 
@@ -353,10 +351,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_DDR_DMM_0			= 108,
-	MSM_RPM_8930_STATUS_ID_DDR_DMM_1			= 109,
-	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 110,
-	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 111,
+	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 108,
+	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 109,
 	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
 };
 
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index b9cba8c..8d567f8 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -76,6 +76,7 @@
 	struct wake_lock pa_wake_lock;		/* Packet Arrival Wake lock*/
 	struct work_struct packet_arrival_work;
 	struct spinlock pa_spinlock;
+	int wakelock_locked;
 } *smd_pkt_devp[NUM_SMD_PKT_PORTS];
 
 struct class *smd_pkt_classp;
@@ -233,16 +234,19 @@
 static void packet_arrival_worker(struct work_struct *work)
 {
 	struct smd_pkt_dev *smd_pkt_devp;
+	unsigned long flags;
 
 	smd_pkt_devp = container_of(work, struct smd_pkt_dev,
 				    packet_arrival_work);
 	mutex_lock(&smd_pkt_devp->ch_lock);
-	if (smd_pkt_devp->ch) {
+	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+	if (smd_pkt_devp->ch && smd_pkt_devp->wakelock_locked) {
 		D_READ("%s locking smd_pkt_dev id:%d wakelock\n",
 			__func__, smd_pkt_devp->i);
 		wake_lock_timeout(&smd_pkt_devp->pa_wake_lock,
 				  WAKELOCK_TIMEOUT);
 	}
+	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
 	mutex_unlock(&smd_pkt_devp->ch_lock);
 }
 
@@ -398,6 +402,7 @@
 	if (smd_pkt_devp->poll_mode &&
 	    !smd_cur_packet_size(smd_pkt_devp->ch)) {
 		wake_unlock(&smd_pkt_devp->pa_wake_lock);
+		smd_pkt_devp->wakelock_locked = 0;
 		smd_pkt_devp->poll_mode = 0;
 		D_READ("%s unlocked smd_pkt_dev id:%d wakelock\n",
 			__func__, smd_pkt_devp->i);
@@ -570,10 +575,11 @@
 	}
 
 	/* here we have a packet of size sz ready */
-	wake_up(&smd_pkt_devp->ch_read_wait_queue);
 	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
 	wake_lock(&smd_pkt_devp->pa_wake_lock);
+	smd_pkt_devp->wakelock_locked = 1;
 	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
+	wake_up(&smd_pkt_devp->ch_read_wait_queue);
 	schedule_work(&smd_pkt_devp->packet_arrival_work);
 	D_READ("%s: wake_up smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
 }
@@ -907,6 +913,7 @@
 
 	smd_pkt_devp->has_reset = 0;
 	smd_pkt_devp->do_reset_notification = 0;
+	smd_pkt_devp->wakelock_locked = 0;
 	wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
 	D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
 		 __func__, smd_pkt_devp->i);
@@ -962,6 +969,7 @@
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_write_wait_queue);
 		smd_pkt_devp[i]->is_open = 0;
 		smd_pkt_devp[i]->poll_mode = 0;
+		smd_pkt_devp[i]->wakelock_locked = 0;
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
 
 		spin_lock_init(&smd_pkt_devp[i]->pa_spinlock);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ef077a5..0dcf1a4 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -124,6 +124,15 @@
 	  Qualcomm MSM chips.  Most of the pins on the MSM can be
 	  selected for GPIO, and are controlled by this driver.
 
+config GPIO_MSM_V3
+	tristate "Qualcomm MSM GPIO v3"
+	depends on GPIOLIB && ARCH_MSM
+	help
+	  Say yes here to support the GPIO interface on ARM v7 based
+	  Qualcomm MSM chips for v3 version of the interface. Most of
+	  the pins on the MSM can be selected for GPIO, and are
+	  controlled by this driver.
+
 config GPIO_FSM9XXX
 	tristate "Qualcomm FSM GPIO"
 	depends on GPIOLIB && ARCH_MSM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index babd44d..d15b628 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -33,7 +33,8 @@
 obj-$(CONFIG_GPIO_MPC5200)	+= gpio-mpc5200.o
 obj-$(CONFIG_GPIO_MPC8XXX)	+= gpio-mpc8xxx.o
 obj-$(CONFIG_GPIO_MSM_V1)	+= gpio-msm-v1.o
-obj-$(CONFIG_GPIO_MSM_V2)	+= gpio-msm-v2.o
+obj-$(CONFIG_GPIO_MSM_V2)	+= gpio-msm-common.o gpio-msm-v2.o
+obj-$(CONFIG_GPIO_MSM_V3)	+= gpio-msm-common.o gpio-msm-v3.o
 obj-$(CONFIG_GPIO_FSM9XXX)	+= gpio-fsm9xxx.o
 obj-$(CONFIG_GPIO_MXC)		+= gpio-mxc.o
 obj-$(CONFIG_GPIO_MXS)		+= gpio-mxs.o
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
new file mode 100644
index 0000000..9a9a783
--- /dev/null
+++ b/drivers/gpio/gpio-msm-common.c
@@ -0,0 +1,629 @@
+/* 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/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/err.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/gpiomux.h>
+#include <mach/mpm.h>
+#include "gpio-msm-common.h"
+
+enum msm_tlmm_register {
+	SDC4_HDRV_PULL_CTL = 0x20a0,
+	SDC3_HDRV_PULL_CTL = 0x20a4,
+	SDC1_HDRV_PULL_CTL = 0x20a0,
+};
+
+struct tlmm_field_cfg {
+	enum msm_tlmm_register reg;
+	u8                     off;
+};
+
+static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
+	{SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK  */
+	{SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD  */
+	{SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
+	{SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK  */
+	{SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD  */
+	{SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
+	{SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK  */
+	{SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD  */
+	{SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
+};
+
+static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
+	{SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD  */
+	{SDC4_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC4_DATA */
+	{SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK  */
+	{SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD  */
+	{SDC3_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC3_DATA */
+	{SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK  */
+	{SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD  */
+	{SDC1_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC1_DATA */
+};
+
+/*
+ * Supported arch specific irq extension.
+ * Default make them NULL.
+ */
+struct irq_chip msm_gpio_irq_extn = {
+	.irq_eoi	= NULL,
+	.irq_mask	= NULL,
+	.irq_unmask	= NULL,
+	.irq_retrigger	= NULL,
+	.irq_set_type	= NULL,
+	.irq_set_wake	= NULL,
+	.irq_disable	= NULL,
+};
+
+/**
+ * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
+ *
+ * @enabled_irqs: a bitmap used to optimize the summary-irq handler.  By
+ * keeping track of which gpios are unmasked as irq sources, we avoid
+ * having to do __raw_readl calls on hundreds of iomapped registers each time
+ * the summary interrupt fires in order to locate the active interrupts.
+ *
+ * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
+ * as wakeup sources.  When the device is suspended, interrupts which are
+ * not wakeup sources are disabled.
+ *
+ * @dual_edge_irqs: a bitmap used to track which irqs are configured
+ * as dual-edge, as this is not supported by the hardware and requires
+ * some special handling in the driver.
+ */
+struct msm_gpio_dev {
+	struct gpio_chip gpio_chip;
+	DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
+	DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
+	DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
+	struct irq_domain domain;
+};
+
+static DEFINE_SPINLOCK(tlmm_lock);
+
+static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
+{
+	return container_of(chip, struct msm_gpio_dev, gpio_chip);
+}
+
+static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	int rc;
+	rc = __msm_gpio_get_inout(offset);
+	mb();
+	return rc;
+}
+
+static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	__msm_gpio_set_inout(offset, val);
+	mb();
+}
+
+static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	__msm_gpio_set_config_direction(offset, 1, 0);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+	return 0;
+}
+
+static int msm_gpio_direction_output(struct gpio_chip *chip,
+				unsigned offset,
+				int val)
+{
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	__msm_gpio_set_config_direction(offset, 0, val);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
+	struct irq_domain *domain = &g_dev->domain;
+	return domain->irq_base + (offset - chip->base);
+}
+
+static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
+{
+	struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
+	struct irq_domain *domain = &g_dev->domain;
+	return irq - domain->irq_base;
+}
+#else
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	return MSM_GPIO_TO_INT(offset - chip->base);
+}
+
+static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
+{
+	return irq - MSM_GPIO_TO_INT(chip->base);
+}
+#endif
+
+static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	return msm_gpiomux_get(chip->base + offset);
+}
+
+static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	msm_gpiomux_put(chip->base + offset);
+}
+
+static struct msm_gpio_dev msm_gpio = {
+	.gpio_chip = {
+		.label		  = "msmgpio",
+		.base             = 0,
+		.ngpio            = NR_MSM_GPIOS,
+		.direction_input  = msm_gpio_direction_input,
+		.direction_output = msm_gpio_direction_output,
+		.get              = msm_gpio_get,
+		.set              = msm_gpio_set,
+		.to_irq           = msm_gpio_to_irq,
+		.request          = msm_gpio_request,
+		.free             = msm_gpio_free,
+	},
+};
+
+static void switch_mpm_config(struct irq_data *d, unsigned val)
+{
+	/* switch the configuration in the mpm as well */
+	if (!msm_gpio_irq_extn.irq_set_type)
+		return;
+
+	if (val)
+		msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
+	else
+		msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
+}
+
+/* For dual-edge interrupts in software, since the hardware has no
+ * such support:
+ *
+ * At appropriate moments, this function may be called to flip the polarity
+ * settings of both-edge irq lines to try and catch the next edge.
+ *
+ * The attempt is considered successful if:
+ * - the status bit goes high, indicating that an edge was caught, or
+ * - the input value of the gpio doesn't change during the attempt.
+ * If the value changes twice during the process, that would cause the first
+ * test to fail but would force the second, as two opposite
+ * transitions would cause a detection no matter the polarity setting.
+ *
+ * The do-loop tries to sledge-hammer closed the timing hole between
+ * the initial value-read and the polarity-write - if the line value changes
+ * during that window, an interrupt is lost, the new polarity setting is
+ * incorrect, and the first success test will fail, causing a retry.
+ *
+ * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
+ */
+static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
+{
+	int loop_limit = 100;
+	unsigned val, val2, intstat;
+
+	do {
+		val = __msm_gpio_get_inout(gpio);
+		__msm_gpio_set_polarity(gpio, val);
+		val2 = __msm_gpio_get_inout(gpio);
+		intstat = __msm_gpio_get_intr_status(gpio);
+		if (intstat || val == val2) {
+			switch_mpm_config(d, val);
+			return;
+		}
+	} while (loop_limit-- > 0);
+	pr_err("%s: dual-edge irq failed to stabilize, %#08x != %#08x\n",
+	       __func__, val, val2);
+}
+
+static void msm_gpio_irq_ack(struct irq_data *d)
+{
+	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+
+	__msm_gpio_set_intr_status(gpio);
+	if (test_bit(gpio, msm_gpio.dual_edge_irqs))
+		msm_gpio_update_dual_edge_pos(d, gpio);
+	mb();
+}
+
+static void msm_gpio_irq_mask(struct irq_data *d)
+{
+	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	__msm_gpio_set_intr_cfg_enable(gpio, 0);
+	__clear_bit(gpio, msm_gpio.enabled_irqs);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+	if (msm_gpio_irq_extn.irq_mask)
+		msm_gpio_irq_extn.irq_mask(d);
+
+}
+
+static void msm_gpio_irq_unmask(struct irq_data *d)
+{
+	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	__set_bit(gpio, msm_gpio.enabled_irqs);
+	__msm_gpio_set_intr_cfg_enable(gpio, 1);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+	if (msm_gpio_irq_extn.irq_mask)
+		msm_gpio_irq_extn.irq_unmask(d);
+}
+
+static void msm_gpio_irq_disable(struct irq_data *d)
+{
+	if (msm_gpio_irq_extn.irq_disable)
+		msm_gpio_irq_extn.irq_disable(d);
+}
+
+static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+
+	if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+		__irq_set_handler_locked(d->irq, handle_edge_irq);
+		if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+			__set_bit(gpio, msm_gpio.dual_edge_irqs);
+		else
+			__clear_bit(gpio, msm_gpio.dual_edge_irqs);
+	} else {
+		__irq_set_handler_locked(d->irq, handle_level_irq);
+		__clear_bit(gpio, msm_gpio.dual_edge_irqs);
+	}
+
+	__msm_gpio_set_intr_cfg_type(gpio, flow_type);
+
+	if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+		msm_gpio_update_dual_edge_pos(d, gpio);
+
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+	if (msm_gpio_irq_extn.irq_set_type)
+		msm_gpio_irq_extn.irq_set_type(d, flow_type);
+
+	return 0;
+}
+
+/*
+ * When the summary IRQ is raised, any number of GPIO lines may be high.
+ * It is the job of the summary handler to find all those GPIO lines
+ * which have been set as summary IRQ lines and which are triggered,
+ * and to call their interrupt handlers.
+ */
+static irqreturn_t msm_summary_irq_handler(int irq, void *data)
+{
+	unsigned long i;
+	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	chained_irq_enter(chip, desc);
+
+	for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
+	     i < NR_MSM_GPIOS;
+	     i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
+		if (__msm_gpio_get_intr_status(i))
+			generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
+							   i));
+	}
+
+	chained_irq_exit(chip, desc);
+	return IRQ_HANDLED;
+}
+
+static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+
+	if (on) {
+		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
+			irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
+		set_bit(gpio, msm_gpio.wake_irqs);
+	} else {
+		clear_bit(gpio, msm_gpio.wake_irqs);
+		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
+			irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
+	}
+
+	if (msm_gpio_irq_extn.irq_set_wake)
+		msm_gpio_irq_extn.irq_set_wake(d, on);
+
+	return 0;
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+	.name		= "msmgpio",
+	.irq_mask	= msm_gpio_irq_mask,
+	.irq_unmask	= msm_gpio_irq_unmask,
+	.irq_ack	= msm_gpio_irq_ack,
+	.irq_set_type	= msm_gpio_irq_set_type,
+	.irq_set_wake	= msm_gpio_irq_set_wake,
+	.irq_disable	= msm_gpio_irq_disable,
+};
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parent, so it won't report false recursion.
+ */
+static struct lock_class_key msm_gpio_lock_class;
+
+static int __devinit msm_gpio_probe(void)
+{
+	int i, irq, ret;
+
+	spin_lock_init(&tlmm_lock);
+	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
+	bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
+	bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
+	ret = gpiochip_add(&msm_gpio.gpio_chip);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
+		irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+		irq_set_lockdep_class(irq, &msm_gpio_lock_class);
+		irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+					 handle_level_irq);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+
+	ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
+			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
+	if (ret) {
+		pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
+				ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int __devexit msm_gpio_remove(void)
+{
+	int ret = gpiochip_remove(&msm_gpio.gpio_chip);
+
+	if (ret < 0)
+		return ret;
+
+	irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int msm_gpio_suspend(void)
+{
+	unsigned long irq_flags;
+	unsigned long i;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
+		__msm_gpio_set_intr_cfg_enable(i, 0);
+
+	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
+		__msm_gpio_set_intr_cfg_enable(i, 1);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+	return 0;
+}
+
+void msm_gpio_show_resume_irq(void)
+{
+	unsigned long irq_flags;
+	int i, irq, intstat;
+
+	if (!msm_show_resume_irq_mask)
+		return;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
+		intstat = __msm_gpio_get_intr_status(i);
+		if (intstat) {
+			irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+			pr_warning("%s: %d triggered\n",
+				__func__, irq);
+		}
+	}
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+}
+
+static void msm_gpio_resume(void)
+{
+	unsigned long irq_flags;
+	unsigned long i;
+
+	msm_gpio_show_resume_irq();
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
+		__msm_gpio_set_intr_cfg_enable(i, 0);
+
+	for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
+		__msm_gpio_set_intr_cfg_enable(i, 1);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+}
+#else
+#define msm_gpio_suspend NULL
+#define msm_gpio_resume NULL
+#endif
+
+static struct syscore_ops msm_gpio_syscore_ops = {
+	.suspend = msm_gpio_suspend,
+	.resume = msm_gpio_resume,
+};
+
+static int __init msm_gpio_init(void)
+{
+	msm_gpio_probe();
+	register_syscore_ops(&msm_gpio_syscore_ops);
+	return 0;
+}
+
+static void __exit msm_gpio_exit(void)
+{
+	unregister_syscore_ops(&msm_gpio_syscore_ops);
+	msm_gpio_remove();
+}
+
+postcore_initcall(msm_gpio_init);
+module_exit(msm_gpio_exit);
+
+static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
+			       unsigned id, unsigned width, unsigned val)
+{
+	unsigned long irqflags;
+	u32 mask = (1 << width) - 1;
+	u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
+	u32 reg_val;
+
+	spin_lock_irqsave(&tlmm_lock, irqflags);
+	reg_val = __raw_readl(reg);
+	reg_val &= ~(mask << configs[id].off);
+	reg_val |= (val & mask) << configs[id].off;
+	__raw_writel(reg_val, reg);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irqflags);
+}
+
+void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
+{
+	msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
+}
+EXPORT_SYMBOL(msm_tlmm_set_hdrive);
+
+void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
+{
+	msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
+}
+EXPORT_SYMBOL(msm_tlmm_set_pull);
+
+int gpio_tlmm_config(unsigned config, unsigned disable)
+{
+	unsigned gpio = GPIO_PIN(config);
+
+	if (gpio > NR_MSM_GPIOS)
+		return -EINVAL;
+
+	__gpio_tlmm_config(config);
+	mb();
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_tlmm_config);
+
+int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+					unsigned int input_polarity)
+{
+	unsigned long irq_flags;
+
+	if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tlmm_lock, irq_flags);
+	__msm_gpio_install_direct_irq(gpio, irq, input_polarity);
+	mb();
+	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_gpio_install_direct_irq);
+
+#ifdef CONFIG_OF
+static int msm_gpio_domain_dt_translate(struct irq_domain *d,
+					struct device_node *controller,
+					const u32 *intspec,
+					unsigned int intsize,
+					unsigned long *out_hwirq,
+					unsigned int *out_type)
+{
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize != 2)
+		return -EINVAL;
+
+	/* hwirq value */
+	*out_hwirq = intspec[0];
+
+	/* irq flags */
+	*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+	return 0;
+}
+
+static struct irq_domain_ops msm_gpio_irq_domain_ops = {
+	.dt_translate = msm_gpio_domain_dt_translate,
+};
+
+int __init msm_gpio_of_init(struct device_node *node,
+			    struct device_node *parent)
+{
+	struct irq_domain *domain = &msm_gpio.domain;
+	int start;
+
+	start = irq_domain_find_free_range(0, NR_MSM_GPIOS);
+	domain->irq_base = irq_alloc_descs(start, 0, NR_MSM_GPIOS,
+							numa_node_id());
+	if (IS_ERR_VALUE(domain->irq_base)) {
+		WARN(1, "Cannot allocate irq_descs @ IRQ%d\n", start);
+		return domain->irq_base;
+	}
+
+	domain->nr_irq = NR_MSM_GPIOS;
+	domain->of_node = of_node_get(node);
+	domain->priv = &msm_gpio;
+	domain->ops = &msm_gpio_irq_domain_ops;
+	irq_domain_add(domain);
+	msm_gpio.gpio_chip.of_node = of_node_get(node);
+	pr_debug("%s: irq_base = %u\n", __func__, domain->irq_base);
+
+	return 0;
+}
+#endif
+
+MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
+MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("sysdev:msmgpio");
diff --git a/drivers/gpio/gpio-msm-common.h b/drivers/gpio/gpio-msm-common.h
new file mode 100644
index 0000000..c9ea3da
--- /dev/null
+++ b/drivers/gpio/gpio-msm-common.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_COMMON_H
+#define __ARCH_ARM_MACH_MSM_GPIO_COMMON_H
+
+extern int msm_show_resume_irq_mask;
+
+unsigned __msm_gpio_get_inout(unsigned gpio);
+void __msm_gpio_set_inout(unsigned gpio, unsigned val);
+void __msm_gpio_set_config_direction(unsigned gpio, int input, int val);
+void __msm_gpio_set_polarity(unsigned gpio, unsigned val);
+unsigned __msm_gpio_get_intr_status(unsigned gpio);
+void __msm_gpio_set_intr_status(unsigned gpio);
+unsigned __msm_gpio_get_intr_config(unsigned gpio);
+void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val);
+void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type);
+void __gpio_tlmm_config(unsigned config);
+void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+					unsigned int input_polarity);
+#endif
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index ad436e0..fb43562 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -14,21 +14,12 @@
 #include <linux/bitops.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/syscore_ops.h>
-#include <linux/irqdomain.h>
-#include <linux/of.h>
-#include <linux/err.h>
-
-#include <asm/mach/irq.h>
+#include <linux/irq.h>
 
 #include <mach/msm_iomap.h>
 #include <mach/gpiomux.h>
-#include <mach/mpm.h>
+#include "gpio-msm-common.h"
 
 /* Bits of interest in the GPIO_IN_OUT register.
  */
@@ -75,54 +66,6 @@
 	DC_IRQ_ENABLE	= BIT(3),
 };
 
-enum msm_tlmm_register {
-	SDC4_HDRV_PULL_CTL = 0x20a0,
-	SDC3_HDRV_PULL_CTL = 0x20a4,
-	SDC1_HDRV_PULL_CTL = 0x20a0,
-};
-
-struct tlmm_field_cfg {
-	enum msm_tlmm_register reg;
-	u8                     off;
-};
-
-static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
-	{SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK  */
-	{SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD  */
-	{SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
-	{SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK  */
-	{SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD  */
-	{SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
-	{SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK  */
-	{SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD  */
-	{SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
-};
-
-static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
-	{SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD  */
-	{SDC4_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC4_DATA */
-	{SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK  */
-	{SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD  */
-	{SDC3_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC3_DATA */
-	{SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK  */
-	{SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD  */
-	{SDC1_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC1_DATA */
-};
-
-/*
- * Supported arch specific irq extension.
- * Default make them NULL.
- */
-struct irq_chip msm_gpio_irq_extn = {
-	.irq_eoi	= NULL,
-	.irq_mask	= NULL,
-	.irq_unmask	= NULL,
-	.irq_retrigger	= NULL,
-	.irq_set_type	= NULL,
-	.irq_set_wake	= NULL,
-	.irq_disable	= NULL,
-};
-
 /*
  * When a GPIO triggers, two separate decisions are made, controlled
  * by two separate flags.
@@ -147,37 +90,6 @@
 #define GPIO_INTR_CFG(gpio)       (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
 #define GPIO_INTR_STATUS(gpio)    (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
 
-/**
- * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
- *
- * @enabled_irqs: a bitmap used to optimize the summary-irq handler.  By
- * keeping track of which gpios are unmasked as irq sources, we avoid
- * having to do __raw_readl calls on hundreds of iomapped registers each time
- * the summary interrupt fires in order to locate the active interrupts.
- *
- * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
- * as wakeup sources.  When the device is suspended, interrupts which are
- * not wakeup sources are disabled.
- *
- * @dual_edge_irqs: a bitmap used to track which irqs are configured
- * as dual-edge, as this is not supported by the hardware and requires
- * some special handling in the driver.
- */
-struct msm_gpio_dev {
-	struct gpio_chip gpio_chip;
-	DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
-	DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
-	DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
-	struct irq_domain domain;
-};
-
-static DEFINE_SPINLOCK(tlmm_lock);
-
-static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
-{
-	return container_of(chip, struct msm_gpio_dev, gpio_chip);
-}
-
 static inline void set_gpio_bits(unsigned n, void __iomem *reg)
 {
 	__raw_writel(__raw_readl(reg) | n, reg);
@@ -188,498 +100,99 @@
 	__raw_writel(__raw_readl(reg) & ~n, reg);
 }
 
-static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+unsigned __msm_gpio_get_inout(unsigned gpio)
 {
-	int rc;
-	rc = __raw_readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN_BIT);
-	mb();
-	return rc;
+	return __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
 }
 
-static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+void __msm_gpio_set_inout(unsigned gpio, unsigned val)
 {
-	__raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(offset));
-	mb();
+	__raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(gpio));
 }
 
-static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+void __msm_gpio_set_config_direction(unsigned gpio, int input, int val)
 {
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-	return 0;
+	if (input)
+		clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	else {
+		__msm_gpio_set_inout(gpio, val);
+		set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	}
 }
 
-static int msm_gpio_direction_output(struct gpio_chip *chip,
-				unsigned offset,
-				int val)
+void __msm_gpio_set_polarity(unsigned gpio, unsigned val)
 {
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	msm_gpio_set(chip, offset, val);
-	set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-	return 0;
-}
-
-#ifdef CONFIG_OF
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
-	struct irq_domain *domain = &g_dev->domain;
-	return domain->irq_base + (offset - chip->base);
-}
-
-static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
-{
-	struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
-	struct irq_domain *domain = &g_dev->domain;
-	return irq - domain->irq_base;
-}
-#else
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	return MSM_GPIO_TO_INT(offset - chip->base);
-}
-
-static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
-{
-	return irq - MSM_GPIO_TO_INT(chip->base);
-}
-#endif
-
-static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-	return msm_gpiomux_get(chip->base + offset);
-}
-
-static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-	msm_gpiomux_put(chip->base + offset);
-}
-
-static struct msm_gpio_dev msm_gpio = {
-	.gpio_chip = {
-		.label		  = "msmgpio",
-		.base             = 0,
-		.ngpio            = NR_MSM_GPIOS,
-		.direction_input  = msm_gpio_direction_input,
-		.direction_output = msm_gpio_direction_output,
-		.get              = msm_gpio_get,
-		.set              = msm_gpio_set,
-		.to_irq           = msm_gpio_to_irq,
-		.request          = msm_gpio_request,
-		.free             = msm_gpio_free,
-	},
-};
-
-static void switch_mpm_config(struct irq_data *d, unsigned val)
-{
-	/* switch the configuration in the mpm as well */
-	if (!msm_gpio_irq_extn.irq_set_type)
-		return;
-
 	if (val)
-		msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
+		clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
 	else
-		msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
+		set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
 }
 
-/* For dual-edge interrupts in software, since the hardware has no
- * such support:
- *
- * At appropriate moments, this function may be called to flip the polarity
- * settings of both-edge irq lines to try and catch the next edge.
- *
- * The attempt is considered successful if:
- * - the status bit goes high, indicating that an edge was caught, or
- * - the input value of the gpio doesn't change during the attempt.
- * If the value changes twice during the process, that would cause the first
- * test to fail but would force the second, as two opposite
- * transitions would cause a detection no matter the polarity setting.
- *
- * The do-loop tries to sledge-hammer closed the timing hole between
- * the initial value-read and the polarity-write - if the line value changes
- * during that window, an interrupt is lost, the new polarity setting is
- * incorrect, and the first success test will fail, causing a retry.
- *
- * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
- */
-static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
+unsigned __msm_gpio_get_intr_status(unsigned gpio)
 {
-	int loop_limit = 100;
-	unsigned val, val2, intstat;
-
-	do {
-		val = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
-		if (val)
-			clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
-		else
-			set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
-		val2 = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
-		intstat = __raw_readl(GPIO_INTR_STATUS(gpio)) &
+	return __raw_readl(GPIO_INTR_STATUS(gpio)) &
 					BIT(INTR_STATUS_BIT);
-		if (intstat || val == val2) {
-			switch_mpm_config(d, val);
-			return;
-		}
-	} while (loop_limit-- > 0);
-	pr_err("%s: dual-edge irq failed to stabilize, "
-	       "interrupts dropped. %#08x != %#08x\n",
-	       __func__, val, val2);
 }
 
-static void msm_gpio_irq_ack(struct irq_data *d)
+void __msm_gpio_set_intr_status(unsigned gpio)
 {
-	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-
 	__raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
-	if (test_bit(gpio, msm_gpio.dual_edge_irqs))
-		msm_gpio_update_dual_edge_pos(d, gpio);
-	mb();
 }
 
-static void __msm_gpio_irq_mask(unsigned int gpio)
+unsigned __msm_gpio_get_intr_config(unsigned gpio)
 {
-	__raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
-	clr_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
+	return __raw_readl(GPIO_INTR_CFG(gpio));
 }
 
-static void msm_gpio_irq_mask(struct irq_data *d)
+void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val)
 {
-	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-	unsigned long irq_flags;
+	if (val) {
+		set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE,
+				GPIO_INTR_CFG(gpio));
+		__raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
 
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	__msm_gpio_irq_mask(gpio);
-	__clear_bit(gpio, msm_gpio.enabled_irqs);
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
-	if (msm_gpio_irq_extn.irq_mask)
-		msm_gpio_irq_extn.irq_mask(d);
-
-}
-
-static void __msm_gpio_irq_unmask(unsigned int gpio)
-{
-	set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
-	__raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
-}
-
-static void msm_gpio_irq_unmask(struct irq_data *d)
-{
-	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	__set_bit(gpio, msm_gpio.enabled_irqs);
-	__msm_gpio_irq_unmask(gpio);
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
-	if (msm_gpio_irq_extn.irq_mask)
-		msm_gpio_irq_extn.irq_unmask(d);
-}
-
-static void msm_gpio_irq_disable(struct irq_data *d)
-{
-	if (msm_gpio_irq_extn.irq_disable)
-		msm_gpio_irq_extn.irq_disable(d);
-}
-
-static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
-	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-	unsigned long irq_flags;
-	uint32_t bits;
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-
-	bits = __raw_readl(GPIO_INTR_CFG(gpio));
-
-	if (flow_type & IRQ_TYPE_EDGE_BOTH) {
-		bits |= INTR_DECT_CTL_EDGE;
-		__irq_set_handler_locked(d->irq, handle_edge_irq);
-		if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
-			__set_bit(gpio, msm_gpio.dual_edge_irqs);
-		else
-			__clear_bit(gpio, msm_gpio.dual_edge_irqs);
 	} else {
-		bits &= ~INTR_DECT_CTL_EDGE;
-		__irq_set_handler_locked(d->irq, handle_level_irq);
-		__clear_bit(gpio, msm_gpio.dual_edge_irqs);
+		__raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
+		clr_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE,
+				GPIO_INTR_CFG(gpio));
 	}
+}
 
-	if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
-		bits |= INTR_POL_CTL_HI;
+void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
+{
+	unsigned cfg;
+
+	cfg  = __msm_gpio_get_intr_config(gpio);
+	if (type & IRQ_TYPE_EDGE_BOTH)
+		cfg |= INTR_DECT_CTL_EDGE;
 	else
-		bits &= ~INTR_POL_CTL_HI;
+		cfg &= ~INTR_DECT_CTL_EDGE;
 
-	__raw_writel(bits, GPIO_INTR_CFG(gpio));
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+		cfg |= INTR_POL_CTL_HI;
+	else
+		cfg &= ~INTR_POL_CTL_HI;
 
-	if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
-		msm_gpio_update_dual_edge_pos(d, gpio);
-
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
-	if (msm_gpio_irq_extn.irq_set_type)
-		msm_gpio_irq_extn.irq_set_type(d, flow_type);
-
-	return 0;
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
 }
 
-/*
- * When the summary IRQ is raised, any number of GPIO lines may be high.
- * It is the job of the summary handler to find all those GPIO lines
- * which have been set as summary IRQ lines and which are triggered,
- * and to call their interrupt handlers.
- */
-static irqreturn_t msm_summary_irq_handler(int irq, void *data)
-{
-	unsigned long i;
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-
-	chained_irq_enter(chip, desc);
-
-	for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
-	     i < NR_MSM_GPIOS;
-	     i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
-		if (__raw_readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS_BIT))
-			generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
-							   i));
-	}
-
-	chained_irq_exit(chip, desc);
-	return IRQ_HANDLED;
-}
-
-static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
-{
-	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-
-	if (on) {
-		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
-			irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
-		set_bit(gpio, msm_gpio.wake_irqs);
-	} else {
-		clear_bit(gpio, msm_gpio.wake_irqs);
-		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
-			irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
-	}
-
-	if (msm_gpio_irq_extn.irq_set_wake)
-		msm_gpio_irq_extn.irq_set_wake(d, on);
-
-	return 0;
-}
-
-static struct irq_chip msm_gpio_irq_chip = {
-	.name		= "msmgpio",
-	.irq_mask	= msm_gpio_irq_mask,
-	.irq_unmask	= msm_gpio_irq_unmask,
-	.irq_ack	= msm_gpio_irq_ack,
-	.irq_set_type	= msm_gpio_irq_set_type,
-	.irq_set_wake	= msm_gpio_irq_set_wake,
-	.irq_disable	= msm_gpio_irq_disable,
-};
-
-/*
- * This lock class tells lockdep that GPIO irqs are in a different
- * category than their parent, so it won't report false recursion.
- */
-static struct lock_class_key msm_gpio_lock_class;
-
-static int __devinit msm_gpio_probe(void)
-{
-	int i, irq, ret;
-
-	spin_lock_init(&tlmm_lock);
-	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
-	ret = gpiochip_add(&msm_gpio.gpio_chip);
-	if (ret < 0)
-		return ret;
-
-	for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
-		irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
-		irq_set_lockdep_class(irq, &msm_gpio_lock_class);
-		irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-
-	ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
-			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
-	if (ret) {
-		pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
-				ret);
-		return ret;
-	}
-	return 0;
-}
-
-static int __devexit msm_gpio_remove(void)
-{
-	int ret = gpiochip_remove(&msm_gpio.gpio_chip);
-
-	if (ret < 0)
-		return ret;
-
-	irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int msm_gpio_suspend(void)
-{
-	unsigned long irq_flags;
-	unsigned long i;
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
-			__msm_gpio_irq_mask(i);
-
-	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
-		__msm_gpio_irq_unmask(i);
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-	return 0;
-}
-
-extern int msm_show_resume_irq_mask;
-
-void msm_gpio_show_resume_irq(void)
-{
-	unsigned long irq_flags;
-	int i, irq, intstat;
-
-	if (!msm_show_resume_irq_mask)
-		return;
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
-		intstat = __raw_readl(GPIO_INTR_STATUS(i)) &
-					BIT(INTR_STATUS_BIT);
-		if (intstat) {
-			irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
-			pr_warning("%s: %d triggered\n",
-				__func__, irq);
-		}
-	}
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-}
-
-static void msm_gpio_resume(void)
-{
-	unsigned long irq_flags;
-	unsigned long i;
-
-	msm_gpio_show_resume_irq();
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-	for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
-		__msm_gpio_irq_mask(i);
-
-	for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
-		__msm_gpio_irq_unmask(i);
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-}
-#else
-#define msm_gpio_suspend NULL
-#define msm_gpio_resume NULL
-#endif
-
-static struct syscore_ops msm_gpio_syscore_ops = {
-	.suspend = msm_gpio_suspend,
-	.resume = msm_gpio_resume,
-};
-
-static int __init msm_gpio_init(void)
-{
-	msm_gpio_probe();
-	register_syscore_ops(&msm_gpio_syscore_ops);
-	return 0;
-}
-
-static void __exit msm_gpio_exit(void)
-{
-	unregister_syscore_ops(&msm_gpio_syscore_ops);
-	msm_gpio_remove();
-}
-
-postcore_initcall(msm_gpio_init);
-module_exit(msm_gpio_exit);
-
-static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
-			       unsigned id, unsigned width, unsigned val)
-{
-	unsigned long irqflags;
-	u32 mask = (1 << width) - 1;
-	u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
-	u32 reg_val;
-
-	spin_lock_irqsave(&tlmm_lock, irqflags);
-	reg_val = __raw_readl(reg);
-	reg_val &= ~(mask << configs[id].off);
-	reg_val |= (val & mask) << configs[id].off;
-	__raw_writel(reg_val, reg);
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irqflags);
-}
-
-void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
-{
-	msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
-}
-EXPORT_SYMBOL(msm_tlmm_set_hdrive);
-
-void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
-{
-	msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
-}
-EXPORT_SYMBOL(msm_tlmm_set_pull);
-
-int gpio_tlmm_config(unsigned config, unsigned disable)
+void __gpio_tlmm_config(unsigned config)
 {
 	uint32_t flags;
 	unsigned gpio = GPIO_PIN(config);
 
-	if (gpio > NR_MSM_GPIOS)
-		return -EINVAL;
-
 	flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
 		((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
 		((GPIO_FUNC(config) << 2) & (0xf << 2)) |
 		((GPIO_PULL(config) & 0x3));
 	__raw_writel(flags, GPIO_CONFIG(gpio));
-	mb();
-
-	return 0;
 }
-EXPORT_SYMBOL(gpio_tlmm_config);
 
-int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
 					unsigned int input_polarity)
 {
-	unsigned long irq_flags;
 	uint32_t bits;
 
-	if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
-		return -EINVAL;
-
-	spin_lock_irqsave(&tlmm_lock, irq_flags);
-
 	__raw_writel(__raw_readl(GPIO_CONFIG(gpio)) | BIT(GPIO_OE_BIT),
 		GPIO_CONFIG(gpio));
 	__raw_writel(__raw_readl(GPIO_INTR_CFG(gpio)) &
@@ -692,66 +205,4 @@
 	if (input_polarity)
 		bits |= DC_POLARITY_HI;
 	__raw_writel(bits, DIR_CONN_INTR_CFG_SU(irq));
-
-	mb();
-	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
-	return 0;
 }
-EXPORT_SYMBOL(msm_gpio_install_direct_irq);
-
-#ifdef CONFIG_OF
-static int msm_gpio_domain_dt_translate(struct irq_domain *d,
-					struct device_node *controller,
-					const u32 *intspec,
-					unsigned int intsize,
-					unsigned long *out_hwirq,
-					unsigned int *out_type)
-{
-	if (d->of_node != controller)
-		return -EINVAL;
-	if (intsize != 2)
-		return -EINVAL;
-
-	/* hwirq value */
-	*out_hwirq = intspec[0];
-
-	/* irq flags */
-	*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
-	return 0;
-}
-
-static struct irq_domain_ops msm_gpio_irq_domain_ops = {
-	.dt_translate = msm_gpio_domain_dt_translate,
-};
-
-int __init msm_gpio_of_init(struct device_node *node,
-			    struct device_node *parent)
-{
-	struct irq_domain *domain = &msm_gpio.domain;
-	int start;
-
-	start = irq_domain_find_free_range(0, NR_MSM_GPIOS);
-	domain->irq_base = irq_alloc_descs(start, 0, NR_MSM_GPIOS,
-							numa_node_id());
-	if (IS_ERR_VALUE(domain->irq_base)) {
-		WARN(1, "Cannot allocate irq_descs @ IRQ%d\n", start);
-		return domain->irq_base;
-	}
-
-	domain->irq_base = irq_domain_find_free_range(0, NR_MSM_GPIOS);
-	domain->nr_irq = NR_MSM_GPIOS;
-	domain->of_node = of_node_get(node);
-	domain->priv = &msm_gpio;
-	domain->ops = &msm_gpio_irq_domain_ops;
-	irq_domain_add(domain);
-	pr_debug("%s: irq_base = %u\n", __func__, domain->irq_base);
-
-	return 0;
-}
-#endif
-
-MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
-MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("sysdev:msmgpio");
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
new file mode 100644
index 0000000..49ad517
--- /dev/null
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/gpiomux.h>
+#include "gpio-msm-common.h"
+
+/* Bits of interest in the GPIO_IN_OUT register.
+ */
+enum {
+	GPIO_IN_BIT  = 0,
+	GPIO_OUT_BIT = 1
+};
+
+/* Bits of interest in the GPIO_INTR_STATUS register.
+ */
+enum {
+	INTR_STATUS_BIT = 0,
+};
+
+/* Bits of interest in the GPIO_CFG register.
+ */
+enum {
+	GPIO_OE_BIT = 9,
+};
+
+/* Bits of interest in the GPIO_INTR_CFG register.
+ */
+enum {
+	INTR_ENABLE_BIT        = 0,
+	INTR_POL_CTL_BIT       = 1,
+	INTR_DECT_CTL_BIT      = 2,
+	INTR_RAW_STATUS_EN_BIT = 4,
+	INTR_TARGET_PROC_BIT   = 5,
+	INTR_DIR_CONN_EN_BIT   = 8,
+};
+
+/*
+ * There is no 'DC_POLARITY_LO' because the GIC is incapable
+ * of asserting on falling edge or level-low conditions.  Even though
+ * the registers allow for low-polarity inputs, the case can never arise.
+ */
+enum {
+	DC_GPIO_SEL_BIT = 0,
+	DC_POLARITY_BIT	= 8,
+};
+
+/*
+ * When a GPIO triggers, two separate decisions are made, controlled
+ * by two separate flags.
+ *
+ * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
+ * register for that GPIO will be updated to reflect the triggering of that
+ * gpio.  If this bit is 0, this register will not be updated.
+ * - Second, INTR_ENABLE controls whether an interrupt is triggered.
+ *
+ * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
+ * can be triggered but the status register will not reflect it.
+ */
+#define INTR_RAW_STATUS_EN BIT(INTR_RAW_STATUS_EN_BIT)
+#define INTR_ENABLE        BIT(INTR_ENABLE_BIT)
+#define INTR_POL_CTL_HI    BIT(INTR_POL_CTL_BIT)
+#define INTR_DIR_CONN_EN   BIT(INTR_DIR_CONN_EN_BIT)
+#define DC_POLARITY_HI     BIT(DC_POLARITY_BIT)
+
+#define INTR_TARGET_PROC_APPS    (4 << INTR_TARGET_PROC_BIT)
+#define INTR_TARGET_PROC_NONE    (7 << INTR_TARGET_PROC_BIT)
+
+#define INTR_DECT_CTL_LEVEL      (0 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_POS_EDGE   (1 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_NEG_EDGE   (2 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_DUAL_EDGE  (3 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_MASK       (3 << INTR_DECT_CTL_BIT)
+
+#define GPIO_CONFIG(gpio)        (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
+#define GPIO_IN_OUT(gpio)        (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
+#define GPIO_INTR_CFG(gpio)      (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
+#define GPIO_INTR_STATUS(gpio)   (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
+#define GPIO_DIR_CONN_INTR(intr) (MSM_TLMM_BASE + 0x2800 + (0x04 * (intr)))
+
+static inline void set_gpio_bits(unsigned n, void __iomem *reg)
+{
+	__raw_writel(__raw_readl(reg) | n, reg);
+}
+
+static inline void clr_gpio_bits(unsigned n, void __iomem *reg)
+{
+	__raw_writel(__raw_readl(reg) & ~n, reg);
+}
+
+unsigned __msm_gpio_get_inout(unsigned gpio)
+{
+	return __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
+}
+
+void __msm_gpio_set_inout(unsigned gpio, unsigned val)
+{
+	__raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(gpio));
+}
+
+void __msm_gpio_set_config_direction(unsigned gpio, int input, int val)
+{
+	if (input) {
+		clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	} else {
+		__msm_gpio_set_inout(gpio, val);
+		set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	}
+}
+
+void __msm_gpio_set_polarity(unsigned gpio, unsigned val)
+{
+	if (val)
+		clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
+	else
+		set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
+}
+
+unsigned __msm_gpio_get_intr_status(unsigned gpio)
+{
+	return __raw_readl(GPIO_INTR_STATUS(gpio)) &
+					BIT(INTR_STATUS_BIT);
+}
+
+void __msm_gpio_set_intr_status(unsigned gpio)
+{
+	__raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
+}
+
+unsigned __msm_gpio_get_intr_config(unsigned gpio)
+{
+	return __raw_readl(GPIO_INTR_CFG(gpio));
+}
+
+void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val)
+{
+	unsigned cfg;
+
+	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+	if (val) {
+		cfg &= ~(INTR_TARGET_PROC_NONE | INTR_DIR_CONN_EN);
+		cfg |= INTR_RAW_STATUS_EN | INTR_ENABLE | INTR_TARGET_PROC_APPS;
+	} else {
+		cfg &= ~(INTR_TARGET_PROC_APPS | INTR_RAW_STATUS_EN |
+			INTR_ENABLE);
+		cfg |= INTR_TARGET_PROC_NONE;
+	}
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+}
+
+void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
+{
+	unsigned cfg;
+
+	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+	cfg &= ~INTR_DECT_CTL_MASK;
+	if (type == IRQ_TYPE_EDGE_RISING)
+		cfg |= INTR_DECT_CTL_POS_EDGE;
+	else if (type == IRQ_TYPE_EDGE_FALLING)
+		cfg |= INTR_DECT_CTL_NEG_EDGE;
+	else if (type == IRQ_TYPE_EDGE_BOTH)
+		cfg |= INTR_DECT_CTL_DUAL_EDGE;
+	else
+		cfg |= INTR_DECT_CTL_LEVEL;
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+		cfg |= INTR_POL_CTL_HI;
+	else
+		cfg &= ~INTR_POL_CTL_HI;
+
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+}
+
+void __gpio_tlmm_config(unsigned config)
+{
+	unsigned flags;
+	unsigned gpio = GPIO_PIN(config);
+
+	flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
+		((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
+		((GPIO_FUNC(config) << 2) & (0xf << 2)) |
+		((GPIO_PULL(config) & 0x3));
+	__raw_writel(flags, GPIO_CONFIG(gpio));
+}
+
+void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+					unsigned int input_polarity)
+{
+	unsigned cfg;
+
+	set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+	cfg &= ~(INTR_TARGET_PROC_NONE | INTR_RAW_STATUS_EN | INTR_ENABLE);
+	cfg |= INTR_TARGET_PROC_APPS | INTR_DIR_CONN_EN;
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+
+	cfg = gpio;
+	if (input_polarity)
+		cfg |= DC_POLARITY_HI;
+	__raw_writel(cfg, GPIO_DIR_CONN_INTR(irq));
+}
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index debda88..1d7da0d 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -80,7 +80,7 @@
 	{0x0202, 0x06}, /* coarse_integration_time */
 	{0x0203, 0x00}, /* coarse_integration_time */
 	{0x0340, 0x09}, /* frame_length_lines */
-	{0x0341, 0x98}, /* frame_length_lines */
+	{0x0341, 0x6C}, /* frame_length_lines */
 	{0x0342, 0x11}, /* line_length_pck */
 	{0x0343, 0x80}, /* line_length_pck */
 	{0x0344, 0x00}, /* x_addr_start */
@@ -489,7 +489,7 @@
 		.x_output = 1984,
 		.y_output = 1508,
 		.line_length_pclk = 4480,
-		.frame_length_lines = 2456,
+		.frame_length_lines = 2412,
 		.vt_pixel_clk = 330000000,
 		.op_pixel_clk = 320000000,
 		.binning_factor = 1,
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 990faeb..5e0d669 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -918,9 +918,7 @@
 		goto retry;
 	if (!err)
 		mmc_blk_reset_success(md, type);
-	spin_lock_irq(&md->lock);
-	__blk_end_request(req, err, blk_rq_bytes(req));
-	spin_unlock_irq(&md->lock);
+	blk_end_request(req, err, blk_rq_bytes(req));
 
 	return err ? 0 : 1;
 }
@@ -989,9 +987,7 @@
 	if (!err)
 		mmc_blk_reset_success(md, type);
 out:
-	spin_lock_irq(&md->lock);
-	__blk_end_request(req, err, blk_rq_bytes(req));
-	spin_unlock_irq(&md->lock);
+	blk_end_request(req, err, blk_rq_bytes(req));
 
 	return err ? 0 : 1;
 }
@@ -1030,9 +1026,7 @@
 					     __func__);
 
 out:
-	spin_lock_irq(&md->lock);
-	__blk_end_request(req, err, blk_rq_bytes(req));
-	spin_unlock_irq(&md->lock);
+	blk_end_request(req, err, blk_rq_bytes(req));
 
 	return err ? 0 : 1;
 }
@@ -1047,9 +1041,7 @@
 	if (ret)
 		ret = -EIO;
 
-	spin_lock_irq(&md->lock);
-	__blk_end_request_all(req, ret);
-	spin_unlock_irq(&md->lock);
+	blk_end_request_all(req, ret);
 
 	return ret ? 0 : 1;
 }
@@ -1672,15 +1664,11 @@
 
 		blocks = mmc_sd_num_wr_blocks(card);
 		if (blocks != (u32)-1) {
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, 0, blocks << 9);
-			spin_unlock_irq(&md->lock);
+			ret = blk_end_request(req, 0, blocks << 9);
 		}
 	} else {
 		if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
-			spin_unlock_irq(&md->lock);
+			ret = blk_end_request(req, 0, brq->data.bytes_xfered);
 		}
 	}
 	return ret;
@@ -1689,7 +1677,6 @@
 static int mmc_blk_end_packed_req(struct mmc_queue *mq,
 				  struct mmc_queue_req *mq_rq)
 {
-	struct mmc_blk_data *md = mq->data;
 	struct request *prq;
 	int idx = mq_rq->packed_fail_idx, i = 0;
 	int ret = 0;
@@ -1709,9 +1696,7 @@
 			return ret;
 		}
 		list_del_init(&prq->queuelist);
-		spin_lock_irq(&md->lock);
-		__blk_end_request(prq, 0, blk_rq_bytes(prq));
-		spin_unlock_irq(&md->lock);
+		blk_end_request(prq, 0, blk_rq_bytes(prq));
 		i++;
 	}
 
@@ -1777,10 +1762,8 @@
 				ret = mmc_blk_end_packed_req(mq, mq_rq);
 				break;
 			} else {
-				spin_lock_irq(&md->lock);
-				ret = __blk_end_request(req, 0,
+				ret = blk_end_request(req, 0,
 						brq->data.bytes_xfered);
-				spin_unlock_irq(&md->lock);
 			}
 
 			/*
@@ -1833,10 +1816,8 @@
 			 * time, so we only reach here after trying to
 			 * read a single sector.
 			 */
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, -EIO,
+			ret = blk_end_request(req, -EIO,
 						brq->data.blksz);
-			spin_unlock_irq(&md->lock);
 			if (!ret)
 				goto start_new_req;
 			break;
@@ -1866,20 +1847,16 @@
 
  cmd_abort:
 	if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
-		spin_lock_irq(&md->lock);
 		if (mmc_card_removed(card))
 			req->cmd_flags |= REQ_QUIET;
 		while (ret)
-			ret = __blk_end_request(req, -EIO,
+			ret = blk_end_request(req, -EIO,
 					blk_rq_cur_bytes(req));
-		spin_unlock_irq(&md->lock);
 	} else {
 		while (!list_empty(&mq_rq->packed_list)) {
 			prq = list_entry_rq(mq_rq->packed_list.next);
 			list_del_init(&prq->queuelist);
-			spin_lock_irq(&md->lock);
-			__blk_end_request(prq, -EIO, blk_rq_bytes(prq));
-			spin_unlock_irq(&md->lock);
+			blk_end_request(prq, -EIO, blk_rq_bytes(prq));
 		}
 		mmc_blk_clear_packed(mq_rq);
 	}
@@ -1932,9 +1909,7 @@
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
 		if (req) {
-			spin_lock_irq(&md->lock);
-			__blk_end_request_all(req, -EIO);
-			spin_unlock_irq(&md->lock);
+			blk_end_request_all(req, -EIO);
 		}
 		ret = 0;
 		goto out;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3438bc91..a21b39d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -235,6 +235,36 @@
 	return err;
 }
 
+static void mmc_select_card_type(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	unsigned int caps = host->caps, caps2 = host->caps2;
+	unsigned int hs_max_dtr = 0;
+
+	if (card_type & EXT_CSD_CARD_TYPE_26)
+		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+			card_type & EXT_CSD_CARD_TYPE_52)
+		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+
+	if ((caps & MMC_CAP_1_8V_DDR &&
+			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
+	    (caps & MMC_CAP_1_2V_DDR &&
+			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+
+	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
+	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+
+	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.card_type = card_type;
+}
+
 /*
  * Decode extended CSD.
  */
@@ -284,56 +314,9 @@
 		if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
 			mmc_card_set_blockaddr(card);
 	}
+
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
-	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
-	case EXT_CSD_CARD_TYPE_SDR_ALL:
-	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
-	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
-	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
-		card->ext_csd.hs_max_dtr = 200000000;
-		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
-		break;
-	case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
-	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
-	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
-	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
-		card->ext_csd.hs_max_dtr = 200000000;
-		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
-		break;
-	case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
-	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
-	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
-	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
-		card->ext_csd.hs_max_dtr = 200000000;
-		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
-		break;
-	case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
-	     EXT_CSD_CARD_TYPE_26:
-		card->ext_csd.hs_max_dtr = 52000000;
-		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
-		break;
-	case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
-	     EXT_CSD_CARD_TYPE_26:
-		card->ext_csd.hs_max_dtr = 52000000;
-		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
-		break;
-	case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
-	     EXT_CSD_CARD_TYPE_26:
-		card->ext_csd.hs_max_dtr = 52000000;
-		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
-		break;
-	case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
-		card->ext_csd.hs_max_dtr = 52000000;
-		break;
-	case EXT_CSD_CARD_TYPE_26:
-		card->ext_csd.hs_max_dtr = 26000000;
-		break;
-	default:
-		/* MMC v4 spec says this cannot happen */
-		pr_warning("%s: card is mmc v4 but doesn't "
-			"support any high-speed modes.\n",
-			mmc_hostname(card->host));
-	}
+	mmc_select_card_type(card);
 
 	card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
 	card->ext_csd.raw_erase_timeout_mult =
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index ac8b164..02d1581 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -2136,7 +2136,7 @@
 {
 	int rc = 0;
 	struct msm_mmc_slot_reg_data *curr_slot;
-	struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
+	struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
 	struct device *dev = mmc_dev(host->mmc);
 
 	curr_slot = host->plat->vreg_data;
@@ -2144,8 +2144,7 @@
 		goto out;
 
 	curr_vdd_reg = curr_slot->vdd_data;
-	curr_vccq_reg = curr_slot->vccq_data;
-	curr_vddp_reg = curr_slot->vddp_data;
+	curr_vdd_io_reg = curr_slot->vdd_io_data;
 
 	if (is_init) {
 		/*
@@ -2157,16 +2156,11 @@
 			if (rc)
 				goto out;
 		}
-		if (curr_vccq_reg) {
-			rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
+		if (curr_vdd_io_reg) {
+			rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
 			if (rc)
 				goto vdd_reg_deinit;
 		}
-		if (curr_vddp_reg) {
-			rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
-			if (rc)
-				goto vccq_reg_deinit;
-		}
 		rc = msmsdcc_vreg_reset(host);
 		if (rc)
 			pr_err("msmsdcc.%d vreg reset failed (%d)\n",
@@ -2174,14 +2168,11 @@
 		goto out;
 	} else {
 		/* Deregister all regulators from regulator framework */
-		goto vddp_reg_deinit;
+		goto vdd_io_reg_deinit;
 	}
-vddp_reg_deinit:
-	if (curr_vddp_reg)
-		msmsdcc_vreg_deinit_reg(curr_vddp_reg);
-vccq_reg_deinit:
-	if (curr_vccq_reg)
-		msmsdcc_vreg_deinit_reg(curr_vccq_reg);
+vdd_io_reg_deinit:
+	if (curr_vdd_io_reg)
+		msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
 vdd_reg_deinit:
 	if (curr_vdd_reg)
 		msmsdcc_vreg_deinit_reg(curr_vdd_reg);
@@ -2254,16 +2245,14 @@
 {
 	int rc = 0, i;
 	struct msm_mmc_slot_reg_data *curr_slot;
-	struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
-	struct msm_mmc_reg_data *vreg_table[3];
+	struct msm_mmc_reg_data *vreg_table[2];
 
 	curr_slot = host->plat->vreg_data;
 	if (!curr_slot)
 		goto out;
 
-	curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
-	curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
-	curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
+	vreg_table[0] = curr_slot->vdd_data;
+	vreg_table[1] = curr_slot->vdd_io_data;
 
 	for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
 		if (vreg_table[i]) {
@@ -2294,70 +2283,53 @@
 	return rc;
 }
 
-static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
+enum vdd_io_level {
+	/* set vdd_io_data->low_vol_level */
+	VDD_IO_LOW,
+	/* set vdd_io_data->high_vol_level */
+	VDD_IO_HIGH,
+	/*
+	 * set whatever there in voltage_level (third argument) of
+	 * msmsdcc_set_vdd_io_vol() function.
+	 */
+	VDD_IO_SET_LEVEL,
+};
+
+static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
+				  enum vdd_io_level level,
+				  unsigned int voltage_level)
 {
 	int rc = 0;
+	int set_level;
 
 	if (host->plat->vreg_data) {
-		struct msm_mmc_reg_data *vddp_reg =
-			host->plat->vreg_data->vddp_data;
+		struct msm_mmc_reg_data *vdd_io_reg =
+			host->plat->vreg_data->vdd_io_data;
 
-		if (vddp_reg && vddp_reg->is_enabled)
-			rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
+		if (vdd_io_reg && vdd_io_reg->is_enabled) {
+			switch (level) {
+			case VDD_IO_LOW:
+				set_level = vdd_io_reg->low_vol_level;
+				break;
+			case VDD_IO_HIGH:
+				set_level = vdd_io_reg->high_vol_level;
+				break;
+			case VDD_IO_SET_LEVEL:
+				set_level = voltage_level;
+				break;
+			default:
+				pr_err("%s: %s: invalid argument level = %d",
+				       mmc_hostname(host->mmc), __func__,
+				       level);
+				rc = -EINVAL;
+				goto out;
+			}
+			rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
+						      set_level, set_level);
+		}
 	}
 
-	return rc;
-}
-
-static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
-{
-	struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
-	int rc = 0;
-
-	if (curr_slot && curr_slot->vddp_data) {
-		rc = msmsdcc_set_vddp_level(host,
-			curr_slot->vddp_data->low_vol_level);
-
-		if (rc)
-			pr_err("%s: %s: failed to change vddp level to %d",
-				mmc_hostname(host->mmc), __func__,
-				curr_slot->vddp_data->low_vol_level);
-	}
-
-	return rc;
-}
-
-static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
-{
-	struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
-	int rc = 0;
-
-	if (curr_slot && curr_slot->vddp_data) {
-		rc = msmsdcc_set_vddp_level(host,
-			curr_slot->vddp_data->high_vol_level);
-
-		if (rc)
-			pr_err("%s: %s: failed to change vddp level to %d",
-				mmc_hostname(host->mmc), __func__,
-				curr_slot->vddp_data->high_vol_level);
-	}
-
-	return rc;
-}
-
-static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
-{
-	struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
-	int rc = 0;
-
-	if (curr_slot && curr_slot->vccq_data) {
-		rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
-				level, level);
-		if (rc)
-			pr_err("%s: %s: failed to change vccq level to %d",
-				mmc_hostname(host->mmc), __func__, level);
-	}
-
+out:
 	return rc;
 }
 
@@ -2582,11 +2554,11 @@
 		pwr = MCI_PWR_OFF;
 		msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
 		/*
-		 * As VDD pad rail is always on, set low voltage for VDD
-		 * pad rail when slot is unused (when card is not present
-		 * or during system suspend).
+		 * If VDD IO rail is always on, set low voltage for VDD
+		 * IO rail when slot is not in use (like when card is not
+		 * present or during system suspend).
 		 */
-		msmsdcc_set_vddp_low_vol(host);
+		msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
 		msmsdcc_setup_pins(host, false);
 		break;
 	case MMC_POWER_UP:
@@ -2594,7 +2566,7 @@
 		pwr = MCI_PWR_UP;
 		msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
 
-		msmsdcc_set_vddp_high_vol(host);
+		msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
 		msmsdcc_setup_pins(host, true);
 		break;
 	case MMC_POWER_ON:
@@ -3298,8 +3270,8 @@
 }
 #endif
 
-static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
-						struct mmc_ios *ios)
+static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
+				     struct mmc_ios *ios)
 {
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	unsigned long flags;
@@ -3309,31 +3281,32 @@
 	host->io_pad_pwr_switch = 0;
 	spin_unlock_irqrestore(&host->lock, flags);
 
-	/*
-	 * For eMMC cards, VccQ voltage range must be changed
-	 * only if it operates in HS200 SDR 1.2V mode or in
-	 * DDR 1.2V mode.
-	 */
-	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
-		rc = msmsdcc_set_vccq_vol(host, 1200000);
+	switch (ios->signal_voltage) {
+	case MMC_SIGNAL_VOLTAGE_330:
+		/* Set VDD IO to high voltage range (2.7v - 3.6v) */
+		rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
 		goto out;
-	 }
-
-	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
-		/* Change voltage level of VDDPX to high voltage */
-		rc = msmsdcc_set_vddp_high_vol(host);
+	case MMC_SIGNAL_VOLTAGE_180:
+		break;
+	case MMC_SIGNAL_VOLTAGE_120:
+		/*
+		 * For eMMC cards, VDD_IO voltage range must be changed
+		 * only if it operates in HS200 SDR 1.2V mode or in
+		 * DDR 1.2V mode.
+		 */
+		rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
 		goto out;
-	} else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
+	default:
 		/* invalid selection. don't do anything */
 		rc = -EINVAL;
 		goto out;
 	}
 
-	spin_lock_irqsave(&host->lock, flags);
 	/*
 	 * If we are here means voltage switch from high voltage to
 	 * low voltage is required
 	 */
+	spin_lock_irqsave(&host->lock, flags);
 
 	/*
 	 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
@@ -3353,10 +3326,10 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	/*
-	 * Switch VDDPX from high voltage to low voltage
-	 * to change the VDD of the SD IO pads.
+	 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
+	 * low voltage range (1.7v - 1.95v).
 	 */
-	rc = msmsdcc_set_vddp_low_vol(host);
+	rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
 	if (rc)
 		goto out;
 
@@ -3855,7 +3828,7 @@
 	.set_ios	= msmsdcc_set_ios,
 	.get_ro		= msmsdcc_get_ro,
 	.enable_sdio_irq = msmsdcc_enable_sdio_irq,
-	.start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
+	.start_signal_voltage_switch = msmsdcc_switch_io_voltage,
 	.execute_tuning = msmsdcc_execute_tuning
 };
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 81b1436..d5b195d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -473,8 +473,7 @@
 	u32 vcd_status = VCD_S_SUCCESS;
 	struct vcd_transc *transc;
 	transc = (struct vcd_transc *)(ddl->client_data);
-	DDL_MSG_LOW("%s: transc = 0x%x, in_use = %u",
-		__func__, (u32)ddl->client_data, transc->in_use);
+	DDL_MSG_LOW("%s: transc = 0x%x", __func__, (u32)ddl->client_data);
 	if (encoder->slice_delivery_info.enable) {
 		return ddl_encode_frame_batch(ddl_handle,
 					input_frame,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index ac1ff24..3c082e4 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -228,6 +228,7 @@
 			[DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH];
 	u32 num_output_frames;
 	u32 out_frm_next_frmindex;
+	u32  first_output_frame_tag;
 };
 struct ddl_encoder_data{
 	struct ddl_codec_data_hdr   hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index e2c0a2a..3487f53 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1774,6 +1774,27 @@
 		vidc_sm_get_frame_tags(&ddl->shared_mem
 			[ddl->command_channel],
 			&output_frame->ip_frm_tag, &bottom_frame_tag);
+
+		if (start_bfr_idx == 0) {
+			encoder->batch_frame.first_output_frame_tag =
+				output_frame->ip_frm_tag;
+			DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
+				__func__, output_frame->ip_frm_tag);
+			if (!output_frame->ip_frm_tag) {
+				DDL_MSG_ERROR("%s: first_output_frame_tag "\
+					"is zero", __func__);
+			}
+		}
+		if (output_frame->ip_frm_tag !=
+			encoder->batch_frame.first_output_frame_tag) {
+			DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
+				"not equal to the first_output_frame_tag[0x%x]\n",
+				__func__, output_frame->ip_frm_tag,
+				encoder->batch_frame.first_output_frame_tag);
+			output_frame->ip_frm_tag =
+				encoder->batch_frame.first_output_frame_tag;
+		}
+
 		ddl_get_encoded_frame(output_frame,
 				encoder->codec.codec,
 				encoder->enc_frame_info.enc_frame);
@@ -1856,6 +1877,27 @@
 		vidc_sm_get_frame_tags(&ddl->shared_mem
 			[ddl->command_channel],
 			&output_frame->ip_frm_tag, &bottom_frame_tag);
+
+		if (start_bfr_idx == 0) {
+			encoder->batch_frame.first_output_frame_tag =
+				output_frame->ip_frm_tag;
+			DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
+				__func__, output_frame->ip_frm_tag);
+			if (!output_frame->ip_frm_tag) {
+				DDL_MSG_ERROR("%s: first_output_frame_tag "\
+					"is zero", __func__);
+			}
+		}
+		if (output_frame->ip_frm_tag !=
+			encoder->batch_frame.first_output_frame_tag) {
+			DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
+				"not equal to the first_output_frame_tag[0x%x]\n",
+				__func__, output_frame->ip_frm_tag,
+				encoder->batch_frame.first_output_frame_tag);
+			output_frame->ip_frm_tag =
+				encoder->batch_frame.first_output_frame_tag;
+		}
+
 		ddl_get_encoded_frame(output_frame,
 				encoder->codec.codec,
 				encoder->enc_frame_info.enc_frame);
@@ -1925,6 +1967,10 @@
 				&ddl->shared_mem[ddl->command_channel],
 				&output_frame->ip_frm_tag,
 				&bottom_frame_tag);
+		if (!output_frame->ip_frm_tag) {
+			DDL_MSG_ERROR("%s: output frame tag is zero",
+				__func__);
+		}
 		ddl_get_encoded_frame(
 				output_frame,
 				encoder->codec.codec,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index d0cf4e8..14e1331 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -867,6 +867,7 @@
 	DDL_MEMSET(encoder->batch_frame.slice_batch_in.align_virtual_addr, 0,
 		sizeof(struct vidc_1080p_enc_slice_batch_in_param));
 	encoder->batch_frame.out_frm_next_frmindex = 0;
+	encoder->batch_frame.first_output_frame_tag = 0;
 	bitstream_size = encoder->batch_frame.output_frame[0].vcd_frm.alloc_len;
 	encoder->output_buf_req.sz = bitstream_size;
 	y_addr = DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6ca4dbe..b71212c 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -2067,8 +2067,8 @@
 		rc = VCD_ERR_CLIENT_FATAL;
 
 	if (VCD_FAILED(rc)) {
-		VCD_MSG_FATAL(
-			"vcd_validate_io_done_pyld: invalid transaction");
+		VCD_MSG_FATAL("vcd_validate_io_done_pyld: "\
+			"invalid transaction 0x%x", (u32)transc);
 	} else if (!frame->vcd_frm.virtual &&
 		status != VCD_ERR_INTRLCD_FIELD_DROP)
 		rc = VCD_ERR_BAD_POINTER;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 3f6d994..19ca831 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -61,6 +61,10 @@
 	unsigned int		generic_cmd6_time;	/* Units: 10ms */
 	unsigned int            power_off_longtime;     /* Units: ms */
 	unsigned int		hs_max_dtr;
+#define MMC_HIGH_26_MAX_DTR	26000000
+#define MMC_HIGH_52_MAX_DTR	52000000
+#define MMC_HIGH_DDR_MAX_DTR	52000000
+#define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
 	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 01f4991..b867c62 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -368,66 +368,6 @@
 #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
 
-#define EXT_CSD_CARD_TYPE_SDR_200	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
-					 EXT_CSD_CARD_TYPE_SDR_1_2V)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL	(EXT_CSD_CARD_TYPE_SDR_200 | \
-					 EXT_CSD_CARD_TYPE_52 | \
-					 EXT_CSD_CARD_TYPE_26)
-
-#define	EXT_CSD_CARD_TYPE_SDR_1_2V_ALL	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
-					 EXT_CSD_CARD_TYPE_52 | \
-					 EXT_CSD_CARD_TYPE_26)
-
-#define	EXT_CSD_CARD_TYPE_SDR_1_8V_ALL	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
-					 EXT_CSD_CARD_TYPE_52 | \
-					 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
-						 EXT_CSD_CARD_TYPE_DDR_1_8V | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
-						 EXT_CSD_CARD_TYPE_DDR_1_8V | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
-						 EXT_CSD_CARD_TYPE_DDR_1_2V | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
-						 EXT_CSD_CARD_TYPE_DDR_1_2V | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
-						 EXT_CSD_CARD_TYPE_DDR_52 | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
-						 EXT_CSD_CARD_TYPE_DDR_52 | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_200 | \
-						 EXT_CSD_CARD_TYPE_DDR_1_8V | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_200 | \
-						 EXT_CSD_CARD_TYPE_DDR_1_2V | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52	(EXT_CSD_CARD_TYPE_SDR_200 | \
-						 EXT_CSD_CARD_TYPE_DDR_52 | \
-						 EXT_CSD_CARD_TYPE_52 | \
-						 EXT_CSD_CARD_TYPE_26)
-
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 284320d..e5bc922 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1352,7 +1352,7 @@
 };
 
 static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
-	.playback = {
+	.capture = {
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
@@ -1381,7 +1381,7 @@
 };
 
 static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
-	.playback = {
+	.capture = {
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
 		SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,