Merge "msm: pil-8660: Break off modem code into platform driver" into msm-3.0
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 101658c..95c93ad 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5298,13 +5298,16 @@
 	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	 "footswitch-8x60.4"),
 	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,	NULL),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("lut_mdp",		lut_mdp_clk.c,		NULL),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_DUMMY("tv_src_clk",		TV_SRC_CLK,		NULL, OFF),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,		"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_DUMMY("mdp_tv_clk",		MDP_TV_CLK,		NULL, OFF),
+	CLK_DUMMY("tv_clk",		MDP_TV_CLK, "footswitch-8x60.4", OFF),
 	CLK_DUMMY("hdmi_clk",		HDMI_TV_CLK,		NULL, OFF),
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,		NULL),
 	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		NULL),
@@ -5531,7 +5534,9 @@
 	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,	NULL),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("lut_mdp",		lut_mdp_clk.c,		NULL),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("qdss_pclk",		qdss_p_clk.c,		NULL),
 	CLK_LOOKUP("qdss_at_clk",	qdss_at_clk.c,		NULL),
 	CLK_LOOKUP("qdss_pclkdbg_clk",	qdss_pclkdbg_clk.c,	NULL),
@@ -5541,11 +5546,13 @@
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,		NULL),
 	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		"msm_vpe.0"),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 9af21d3..9da8bb4 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3704,8 +3704,11 @@
 	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,		NULL),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("pixel_lcdc_clk",	pixel_lcdc_clk.c,		NULL),
+	CLK_LOOKUP("pixel_lcdc_clk",	pixel_lcdc_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("pixel_mdp_clk",	pixel_mdp_clk.c,		NULL),
+	CLK_LOOKUP("pixel_mdp_clk",	pixel_mdp_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,		NULL),
@@ -3713,8 +3716,10 @@
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		NULL),
 	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 5006419..51f0336 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -22,6 +24,7 @@
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
 #include <mach/scm-io.h>
+#include <mach/socinfo.h>
 #include "clock.h"
 #include "footswitch.h"
 
@@ -49,8 +52,9 @@
 #define RETENTION_BIT		BIT(9)
 
 #define RESET_DELAY_US		1
-/* Core clock rate to use if one has not previously been set. */
-#define DEFAULT_CLK_RATE	27000000
+/* Clock rate to use if one has not previously been set. */
+#define DEFAULT_RATE		27000000
+#define MAX_CLKS		10
 
 /*
  * Lock is only needed to protect against the first footswitch_enable()
@@ -58,72 +62,76 @@
  */
 static DEFINE_MUTEX(claim_lock);
 
-struct clock_state {
-	int ahb_clk_en;
-	int axi_clk_en;
-	int core_clk_rate;
+struct clk_data {
+	const char *name;
+	struct clk *clk;
+	unsigned long rate;
+	unsigned long reset_rate;
+	bool enabled;
 };
 
 struct footswitch {
 	struct regulator_dev	*rdev;
 	struct regulator_desc	desc;
 	void			*gfs_ctl_reg;
-	int			bus_port1, bus_port2;
+	int			bus_port0, bus_port1;
 	bool			is_enabled;
 	bool			is_claimed;
-	const bool		has_axi_clk;
+	struct clk_data		*clk_data;
 	struct clk		*core_clk;
-	struct clk		*ahb_clk;
-	struct clk		*axi_clk;
-	unsigned int		reset_rate;
-	struct clock_state	clk_state;
 	unsigned int		gfs_delay_cnt:5;
 };
 
 static int setup_clocks(struct footswitch *fs)
 {
 	int rc = 0;
+	struct clk_data *clock;
+	long rate;
 
 	/*
-	 * Enable all clocks in the power domain. If a core requires a
-	 * specific clock rate when being reset, apply it.
+	 * Enable all clocks in the power domain. If a specific clock rate is
+	 * required for reset timing, set that rate before enabling the clocks.
 	 */
-	fs->clk_state.core_clk_rate = clk_get_rate(fs->core_clk);
-	if (!fs->clk_state.core_clk_rate || fs->reset_rate) {
-		int rate = fs->reset_rate ? fs->reset_rate : DEFAULT_CLK_RATE;
-		rc = clk_set_rate(fs->core_clk, rate);
-		if (rc) {
-			pr_err("%s: Failed to set core_clk rate to %d Hz.\n",
-				__func__, fs->reset_rate);
-			return rc;
+	for (clock = fs->clk_data; clock->clk; clock++) {
+		clock->rate = clk_get_rate(clock->clk);
+		if (!clock->rate || clock->reset_rate) {
+			rate = clock->reset_rate ?
+					clock->reset_rate : DEFAULT_RATE;
+			rc = clk_set_rate(clock->clk, rate);
+			if (rc && rc != -ENOSYS) {
+				pr_err("Failed to set %s rate to %lu Hz.\n",
+					clock->name, clock->rate);
+				for (clock--; clock >= fs->clk_data; clock--) {
+					if (clock->enabled)
+						clk_disable(clock->clk);
+					clk_set_rate(clock->clk, clock->rate);
+				}
+				return rc;
+			}
 		}
+		/*
+		 * Some clocks are for reset purposes only. These clocks will
+		 * fail to enable. Ignore the failures but keep track of them so
+		 * we don't try to disable them later and crash due to
+		 * unbalanced calls.
+		 */
+		clock->enabled = !clk_enable(clock->clk);
 	}
-	clk_enable(fs->core_clk);
 
-	/*
-	 * Some AHB and AXI clocks are for reset purposes only. These clocks
-	 * will fail to enable. Keep track of them so we don't try to disable
-	 * them later and crash.
-	 */
-	fs->clk_state.ahb_clk_en = !clk_enable(fs->ahb_clk);
-	if (fs->axi_clk)
-		fs->clk_state.axi_clk_en = !clk_enable(fs->axi_clk);
-
-	return rc;
+	return 0;
 }
 
 static void restore_clocks(struct footswitch *fs)
 {
+	struct clk_data *clock;
+
 	/* Restore clocks to their orignal states before setup_clocks(). */
-	if (fs->axi_clk && fs->clk_state.axi_clk_en)
-		clk_disable(fs->axi_clk);
-	if (fs->clk_state.ahb_clk_en)
-		clk_disable(fs->ahb_clk);
-	clk_disable(fs->core_clk);
-	if (fs->clk_state.core_clk_rate) {
-		if (clk_set_rate(fs->core_clk, fs->clk_state.core_clk_rate))
-			pr_err("%s: Failed to restore core_clk rate.\n",
-				__func__);
+	for (clock = fs->clk_data; clock->clk; clock++) {
+		if (clock->enabled)
+			clk_disable(clock->clk);
+		if (clock->rate && clk_set_rate(clock->clk, clock->rate))
+			pr_err("Failed to restore %s rate to %lu Hz.\n",
+				clock->name, clock->rate);
 	}
 }
 
@@ -137,6 +145,7 @@
 static int footswitch_enable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	mutex_lock(&claim_lock);
@@ -154,17 +163,17 @@
 		return rc;
 
 	/* Un-halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_portunhalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 unhalt failed.\n", __func__);
+			pr_err("Port 0 unhalt failed.\n");
 			goto err;
 		}
 	}
-	if (fs->bus_port2) {
-		rc = msm_bus_axi_portunhalt(fs->bus_port2);
+	if (fs->bus_port1) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port1);
 		if (rc) {
-			pr_err("%s: Port 2 unhalt failed.\n", __func__);
+			pr_err("Port 1 unhalt failed.\n");
 			goto err_port2_halt;
 		}
 	}
@@ -174,10 +183,8 @@
 	 * footswitch_enable() is first called before footswitch_disable()
 	 * and resets should be asserted before power is restored.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
 	udelay(RESET_DELAY_US);
 
@@ -193,10 +200,8 @@
 	writel_relaxed(regval, fs->gfs_ctl_reg);
 
 	/* Deassert resets for all clocks in the power domain. */
-	clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_DEASSERT);
 	/* Toggle core reset again after first power-on (required for GFX3D). */
 	if (fs->desc.id == FS_GFX3D) {
 		clk_reset(fs->core_clk, CLK_RESET_ASSERT);
@@ -212,7 +217,7 @@
 	return 0;
 
 err_port2_halt:
-	msm_bus_axi_porthalt(fs->bus_port1);
+	msm_bus_axi_porthalt(fs->bus_port0);
 err:
 	restore_clocks(fs);
 	return rc;
@@ -221,6 +226,7 @@
 static int footswitch_disable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	/* Return early if already disabled. */
@@ -234,17 +240,17 @@
 		return rc;
 
 	/* Halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_porthalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 halt failed.\n", __func__);
+			pr_err("Port 0 halt failed.\n");
 			goto err;
 		}
 	}
-	if (fs->bus_port2) {
-		rc = msm_bus_axi_porthalt(fs->bus_port2);
+	if (fs->bus_port1) {
+		rc = msm_bus_axi_porthalt(fs->bus_port1);
 		if (rc) {
-			pr_err("%s: Port 1 halt failed.\n", __func__);
+			pr_err("Port 1 halt failed.\n");
 			goto err_port2_halt;
 		}
 	}
@@ -253,10 +259,8 @@
 	 * Assert resets for all clocks in the clock domain so that
 	 * outputs settle prior to clamping.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
 	udelay(RESET_DELAY_US);
 
@@ -283,7 +287,7 @@
 	return 0;
 
 err_port2_halt:
-	msm_bus_axi_portunhalt(fs->bus_port1);
+	msm_bus_axi_portunhalt(fs->bus_port0);
 err:
 	restore_clocks(fs);
 	return rc;
@@ -292,6 +296,7 @@
 static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	mutex_lock(&claim_lock);
@@ -309,10 +314,10 @@
 		return rc;
 
 	/* Un-halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_portunhalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 unhalt failed.\n", __func__);
+			pr_err("Port 0 unhalt failed.\n");
 			goto err;
 		}
 	}
@@ -325,12 +330,10 @@
 	 * footswitch_enable() is first called before footswitch_disable()
 	 * and resets should be asserted before power is restored.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
-	udelay(20);
+	udelay(RESET_DELAY_US);
 
 	/* Enable the power rail at the footswitch. */
 	regval |= ENABLE_BIT;
@@ -343,11 +346,9 @@
 	writel_relaxed(regval, fs->gfs_ctl_reg);
 
 	/* Deassert resets for all clocks in the power domain. */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
-	udelay(20);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_DEASSERT);
+	udelay(RESET_DELAY_US);
 
 	/* Re-enable core clock. */
 	clk_enable(fs->core_clk);
@@ -366,6 +367,7 @@
 static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	/* Return early if already disabled. */
@@ -379,10 +381,10 @@
 		return rc;
 
 	/* Halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_porthalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 halt failed.\n", __func__);
+			pr_err("Port 0 halt failed.\n");
 			goto err;
 		}
 	}
@@ -394,12 +396,10 @@
 	 * Assert resets for all clocks in the clock domain so that
 	 * outputs settle prior to clamping.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
-	udelay(20);
+	udelay(5);
 
 	/*
 	 * Clamp the I/O ports of the core to ensure the values
@@ -438,8 +438,102 @@
 	.disable = gfx2d_footswitch_disable,
 };
 
-#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _axi_clk, \
-		   _reset_rate, _bp1, _bp2) \
+/*
+ * Lists of required clocks for the collapse and restore sequences.
+ *
+ * Order matters here. Clocks are listed in the same order as their
+ * resets will be de-asserted when the core is restored. Also, rate-
+ * settable clocks must be listed before any of the branches that
+ * are derived from them. Otherwise, the branches may fail to enable
+ * if their parent's rate is not yet set.
+ */
+
+static struct clk_data gfx2d0_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ 0 }
+};
+
+static struct clk_data gfx2d1_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ 0 }
+};
+
+static struct clk_data gfx3d_clks[] = {
+	{ .name = "core_clk", .reset_rate = 27000000 },
+	{ .name = "iface_clk" },
+	{ 0 }
+};
+
+
+static struct clk_data ijpeg_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data mdp_8960_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ .name = "vsync_clk" },
+	{ .name = "lut_clk" },
+	{ .name = "tv_src_clk" },
+	{ .name = "tv_clk" },
+	{ 0 }
+};
+
+static struct clk_data mdp_8660_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ .name = "vsync_clk" },
+	{ .name = "tv_src_clk" },
+	{ .name = "tv_clk" },
+	{ .name = "pixel_mdp_clk" },
+	{ .name = "pixel_lcdc_clk" },
+	{ 0 }
+};
+
+static struct clk_data rot_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data ved_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data vfe_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data vpe_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data vcap_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
+		   _bp1, _bp2) \
 	[(_id)] = { \
 		.desc = { \
 			.id = (_id), \
@@ -450,43 +544,42 @@
 		}, \
 		.gfs_ctl_reg = (_gfs_ctl_reg), \
 		.gfs_delay_cnt = (_dc), \
-		.bus_port1 = (_bp1), \
-		.bus_port2 = (_bp2), \
-		.has_axi_clk = (_axi_clk), \
-		.reset_rate = (_reset_rate), \
+		.clk_data = (_clk_data), \
+		.bus_port0 = (_bp1), \
+		.bus_port1 = (_bp2), \
 	}
 static struct footswitch footswitches[] = {
 	FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
-		GFX2D0_GFS_CTL_REG, 31, false, 0,
+		GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
 		MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
 	FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
-		GFX2D1_GFS_CTL_REG, 31, false, 0,
+		GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
 		MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
 	FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
-		GFX3D_GFS_CTL_REG, 31, false, 27000000,
+		GFX3D_GFS_CTL_REG, 31, gfx3d_clks,
 		MSM_BUS_MASTER_GRAPHICS_3D, 0),
 	FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
-		GEMINI_GFS_CTL_REG, 31, true, 0,
+		GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
 		MSM_BUS_MASTER_JPEG_ENC, 0),
 	FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
-		MDP_GFS_CTL_REG, 31, true, 0,
+		MDP_GFS_CTL_REG, 31, NULL,
 		MSM_BUS_MASTER_MDP_PORT0,
 		MSM_BUS_MASTER_MDP_PORT1),
 	FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
-		ROT_GFS_CTL_REG, 31, true, 0,
+		ROT_GFS_CTL_REG, 31, rot_clks,
 		MSM_BUS_MASTER_ROTATOR, 0),
 	FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
-		VED_GFS_CTL_REG, 31, true, 0,
+		VED_GFS_CTL_REG, 31, ved_clks,
 		MSM_BUS_MASTER_HD_CODEC_PORT0,
 		MSM_BUS_MASTER_HD_CODEC_PORT1),
 	FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
-		VFE_GFS_CTL_REG, 31, true, 0,
+		VFE_GFS_CTL_REG, 31, vfe_clks,
 		MSM_BUS_MASTER_VFE, 0),
 	FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
-		VPE_GFS_CTL_REG, 31, true, 0,
+		VPE_GFS_CTL_REG, 31, vpe_clks,
 		MSM_BUS_MASTER_VPE, 0),
 	FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
-		VCAP_GFS_CTL_REG, 31, true, 0,
+		VCAP_GFS_CTL_REG, 31, vcap_clks,
 		MSM_BUS_MASTER_VIDEO_CAP, 0),
 };
 
@@ -494,6 +587,7 @@
 {
 	struct footswitch *fs;
 	struct regulator_init_data *init_data;
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	if (pdev == NULL)
@@ -505,30 +599,24 @@
 	fs = &footswitches[pdev->id];
 	init_data = pdev->dev.platform_data;
 
-	/* Setup core clock. */
-	fs->core_clk = clk_get(&pdev->dev, "core_clk");
-	if (IS_ERR(fs->core_clk)) {
-		pr_err("%s: clk_get(core_clk) failed\n", __func__);
-		rc = PTR_ERR(fs->core_clk);
-		goto err_core_clk;
+	if (pdev->id == FS_MDP) {
+		if (cpu_is_msm8960() || cpu_is_msm8930())
+			fs->clk_data = mdp_8960_clks;
+		else if (cpu_is_msm8x60())
+			fs->clk_data = mdp_8660_clks;
+		else
+			BUG();
 	}
 
-	/* Setup AHB clock. */
-	fs->ahb_clk = clk_get(&pdev->dev, "iface_clk");
-	if (IS_ERR(fs->ahb_clk)) {
-		pr_err("%s: clk_get(iface_clk) failed\n", __func__);
-		rc = PTR_ERR(fs->ahb_clk);
-		goto err_ahb_clk;
-	}
-
-	/* Setup AXI clock. */
-	if (fs->has_axi_clk) {
-		fs->axi_clk = clk_get(&pdev->dev, "bus_clk");
-		if (IS_ERR(fs->axi_clk)) {
-			pr_err("%s: clk_get(bus_clk) failed\n", __func__);
-			rc = PTR_ERR(fs->axi_clk);
-			goto err_axi_clk;
+	for (clock = fs->clk_data; clock->name; clock++) {
+		clock->clk = clk_get(&pdev->dev, clock->name);
+		if (IS_ERR(clock->clk)) {
+			rc = PTR_ERR(clock->clk);
+			pr_err("clk_get(%s) failed\n", clock->name);
+			goto err;
 		}
+		if (!strncmp(clock->name, "core_clk", 8))
+			fs->core_clk = clock->clk;
 	}
 
 	/*
@@ -543,34 +631,28 @@
 
 	fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
 	if (IS_ERR(footswitches[pdev->id].rdev)) {
-		pr_err("%s: regulator_register(\"%s\") failed\n",
-			__func__, fs->desc.name);
+		pr_err("regulator_register(\"%s\") failed\n",
+			fs->desc.name);
 		rc = PTR_ERR(footswitches[pdev->id].rdev);
-		goto err_register;
+		goto err;
 	}
 
 	return 0;
 
-err_register:
-	if (fs->has_axi_clk)
-		clk_put(fs->axi_clk);
-err_axi_clk:
-	clk_put(fs->ahb_clk);
-err_ahb_clk:
-	clk_put(fs->core_clk);
-err_core_clk:
+err:
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_put(clock->clk);
+
 	return rc;
 }
 
 static int __devexit footswitch_remove(struct platform_device *pdev)
 {
 	struct footswitch *fs = &footswitches[pdev->id];
+	struct clk_data *clock;
 
-	clk_put(fs->core_clk);
-	clk_put(fs->ahb_clk);
-	if (fs->axi_clk)
-		clk_put(fs->axi_clk);
-
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_put(clock->clk);
 	regulator_unregister(fs->rdev);
 
 	return 0;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a971594..aef3f4e 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -83,6 +83,8 @@
 		return AO8960_TOOLS_ID;
 	case APQ8064_MACHINE_ID:
 		return APQ8064_TOOLS_ID;
+	case MSM8930_MACHINE_ID:
+		return MSM8930_TOOLS_ID;
 	default:
 		return 0;
 	}
@@ -97,6 +99,12 @@
 	switch (socinfo_get_id()) {
 	case AO8960_MACHINE_ID:
 	case APQ8064_MACHINE_ID:
+	case MSM8930_MACHINE_ID:
+	case MSM8630_MACHINE_ID:
+	case MSM8230_MACHINE_ID:
+	case APQ8030_MACHINE_ID:
+	case MSM8627_MACHINE_ID:
+	case MSM8227_MACHINE_ID:
 		return 1;
 	default:
 		return 0;
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index edf5c27..d6fb937 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -82,6 +82,7 @@
 #define MAX_SESSIONS 16
 #define INVALID_SESSION -1
 #define VERSION_KEY_MASK 0xFFFFFF00
+#define MAX_DOWNSCALE_RATIO 3
 
 struct tile_parm {
 	unsigned int width;  /* tile's width */
@@ -428,7 +429,9 @@
 		}
 		iowrite32((1  << 18) | 		/* chroma sampling 1=H2V1 */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 		iowrite32(0 << 29 | 		/* frame format 0 = linear */
 			  (use_imem ? 0 : 1) << 22 | /* tile size */
@@ -528,7 +531,9 @@
 		}
 		iowrite32((3  << 18) | 		/* chroma sampling 3=4:2:0 */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 
 		iowrite32((is_tile ? 2 : 0) << 29 |  /* frame format */
@@ -579,7 +584,9 @@
 			  MSM_ROTATOR_OUT_PACK_PATTERN1);
 		iowrite32((1  << 18) | 		/* chroma sampling 1=H2V1 */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 		iowrite32(0 << 29 | 		/* frame format 0 = linear */
 			  (use_imem ? 0 : 1) << 22 | /* tile size */
@@ -624,7 +631,9 @@
 		iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
 		iowrite32((0  << 18) | 		/* chroma sampling 0=rgb */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 		switch (info->src.format) {
 		case MDP_RGB_565:
@@ -1068,24 +1077,31 @@
 	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
 		return -EFAULT;
 
-	if (info.rotations & MDP_ROT_90) {
-		dst_w = info.src_rect.h;
-		dst_h = info.src_rect.w;
-	} else {
-		dst_w = info.src_rect.w;
-		dst_h = info.src_rect.h;
-	}
-
 	if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
 	    (info.src.height > MSM_ROTATOR_MAX_H) ||
 	    (info.src.width > MSM_ROTATOR_MAX_W) ||
 	    (info.dst.height > MSM_ROTATOR_MAX_H) ||
 	    (info.dst.width > MSM_ROTATOR_MAX_W) ||
-	    checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
+	    (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
+		pr_err("%s: Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (info.rotations & MDP_ROT_90) {
+		dst_w = info.src_rect.h >> info.downscale_ratio;
+		dst_h = info.src_rect.w >> info.downscale_ratio;
+	} else {
+		dst_w = info.src_rect.w >> info.downscale_ratio;
+		dst_h = info.src_rect.h >> info.downscale_ratio;
+	}
+
+	if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
 	    checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
 	    checkoffset(info.dst_x, dst_w, info.dst.width) ||
-	    checkoffset(info.dst_y, dst_h, info.dst.height))
-		return -EINVAL;
+	    checkoffset(info.dst_y, dst_h, info.dst.height)) {
+		pr_err("%s: Invalid src or dst rect\n", __func__);
+		return -ERANGE;
+	}
 
 	switch (info.src.format) {
 	case MDP_RGB_565:
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 5c94a3c..bdbaffd 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -41,9 +41,16 @@
 #define AO8960_MACHINE_ID	87
 #define MSM8660_MACHINE_ID	71
 #define APQ8064_MACHINE_ID	109
+#define MSM8930_MACHINE_ID	116
+#define MSM8630_MACHINE_ID	117
+#define MSM8230_MACHINE_ID	118
+#define APQ8030_MACHINE_ID	119
+#define MSM8627_MACHINE_ID	120
+#define MSM8227_MACHINE_ID	121
 #define APQ8060_TOOLS_ID	4062
 #define AO8960_TOOLS_ID		4064
 #define APQ8064_TOOLS_ID	4072
+#define MSM8930_TOOLS_ID	4072
 
 #define MSG_MASK_0			(0x00000001)
 #define MSG_MASK_1			(0x00000002)
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 611d7b4..72809cf 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -30,6 +30,7 @@
 	unsigned int    dst_y;
 	unsigned char   rotations;
 	int enable;
+	unsigned int	downscale_ratio;
 };
 
 struct msm_rotator_data_info {