Merge "ASoC: msm: Fix SRS key not being sent to DSP sometimes problem" into msm-3.4
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 7c2c556..f9ff226 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -18,6 +18,7 @@
 
 #include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -27,6 +28,8 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/sort.h>
+#include <linux/platform_device.h>
+
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
@@ -402,7 +405,7 @@
 #ifdef CONFIG_CPU_FREQ_MSM
 static struct cpufreq_frequency_table freq_table[NR_CPUS][20];
 
-static void __init cpufreq_table_init(void)
+static void __devinit cpufreq_table_init(void)
 {
 	int cpu;
 	for_each_possible_cpu(cpu) {
@@ -693,7 +696,7 @@
 	return rc;
 }
 
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *speed;
 	uint32_t div, sel, reg_clksel;
@@ -775,7 +778,7 @@
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
 #define MHZ 1000000
-static void __init select_freq_plan(void)
+static void __devinit select_freq_plan(void)
 {
 	unsigned long pll_mhz[ACPU_PLL_END];
 	struct pll_freq_tbl_map *t;
@@ -835,7 +838,7 @@
  * Hardware requires the CPU to be dropped to less than MAX_WAIT_FOR_IRQ_KHZ
  * before entering a wait for irq low-power mode. Find a suitable rate.
  */
-static unsigned long __init find_wait_for_irq_khz(void)
+static unsigned long __devinit find_wait_for_irq_khz(void)
 {
 	unsigned long found_khz = 0;
 	int i;
@@ -847,7 +850,7 @@
 	return found_khz;
 }
 
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
 {
 	int i = 0, cpu;
 	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -868,7 +871,7 @@
 	}
 }
 
-static void __init precompute_stepping(void)
+static void __devinit precompute_stepping(void)
 {
 	int i, step_idx;
 
@@ -909,7 +912,7 @@
 	}
 }
 
-static void __init print_acpu_freq_tbl(void)
+static void __devinit print_acpu_freq_tbl(void)
 {
 	struct clkctl_acpu_speed *t;
 	short down_idx[ACPU_PLL_END];
@@ -947,15 +950,17 @@
 	.switch_time_us = 50,
 };
 
-static int __init acpuclk_7627_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_7627_probe(struct platform_device *pdev)
 {
+	const struct acpuclk_pdata *pdata = pdev->dev.platform_data;
+
 	pr_info("%s()\n", __func__);
 
 	drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
 	BUG_ON(IS_ERR(drv_state.ebi1_clk));
 
 	mutex_init(&drv_state.lock);
-	drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
+	drv_state.max_speed_delta_khz = pdata->max_speed_delta_khz;
 	select_freq_plan();
 	acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
 	precompute_stepping();
@@ -970,23 +975,16 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_7x27_soc_data __initdata = {
-	.max_speed_delta_khz = 400000,
-	.init = acpuclk_7627_init,
+static struct platform_driver acpuclk_7627_driver = {
+	.probe = acpuclk_7627_probe,
+	.driver = {
+		.name = "acpuclk-7627",
+		.owner = THIS_MODULE,
+	},
 };
 
-struct acpuclk_soc_data acpuclk_7x27a_soc_data __initdata = {
-	.max_speed_delta_khz = 400000,
-	.init = acpuclk_7627_init,
-};
-
-struct acpuclk_soc_data acpuclk_7x27aa_soc_data __initdata = {
-	.max_speed_delta_khz = 504000,
-	.init = acpuclk_7627_init,
-};
-
-struct acpuclk_soc_data acpuclk_8625_soc_data __initdata = {
-	/* TODO: Need to update speed delta from H/w Team */
-	.max_speed_delta_khz = 604800,
-	.init = acpuclk_7627_init,
-};
+static int __init acpuclk_7627_init(void)
+{
+	return platform_driver_register(&acpuclk_7627_driver);
+}
+postcore_initcall(acpuclk_7627_init);
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 29b0065..b49613e 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -16,6 +16,7 @@
 
 #include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -25,6 +26,7 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/sort.h>
+#include <linux/platform_device.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
@@ -315,7 +317,7 @@
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
 
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *s;
 	uint32_t div, sel, src_num;
@@ -393,7 +395,7 @@
 }
 
 /* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
 {
 	int i;
 	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -431,7 +433,7 @@
  * Truncate the frequency table at the current PLL2 rate and determine the
  * backup PLL to use when scaling PLL2.
  */
-void __init pll2_fixup(void)
+void __devinit pll2_fixup(void)
 {
 	struct clkctl_acpu_speed *speed = acpu_freq_tbl;
 	u8 pll2_l = readl_relaxed(PLL2_L_VAL_ADDR) & 0xFF;
@@ -453,7 +455,7 @@
 #define RPM_BYPASS_MASK	(1 << 3)
 #define PMIC_MODE_MASK	(1 << 4)
 
-static void __init populate_plls(void)
+static void __devinit populate_plls(void)
 {
 	acpuclk_sources[PLL_1] = clk_get_sys("acpu", "pll1_clk");
 	BUG_ON(IS_ERR(acpuclk_sources[PLL_1]));
@@ -479,7 +481,7 @@
 	.switch_time_us = 50,
 };
 
-static int __init acpuclk_7x30_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_7x30_probe(struct platform_device *pdev)
 {
 	pr_info("%s()\n", __func__);
 
@@ -494,6 +496,16 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_7x30_soc_data __initdata = {
-	.init = acpuclk_7x30_init,
+static struct platform_driver acpuclk_7x30_driver = {
+	.probe = acpuclk_7x30_probe,
+	.driver = {
+		.name = "acpuclk-7x30",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_7x30_init(void)
+{
+	return platform_driver_register(&acpuclk_7x30_driver);
+}
+postcore_initcall(acpuclk_7x30_init);
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index afa98c1..d29fee6 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -13,6 +13,7 @@
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -22,6 +23,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
 #include <asm/cpu.h>
@@ -1649,7 +1651,7 @@
 	.wait_for_irq_khz = STBY_KHZ,
 };
 
-static int __init acpuclk_8960_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_8960_probe(struct platform_device *pdev)
 {
 	struct acpu_level *max_acpu_level = select_freq_plan();
 
@@ -1667,14 +1669,15 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_8960_soc_data __initdata = {
-	.init = acpuclk_8960_init,
+static struct platform_driver acpuclk_8960_driver = {
+	.driver = {
+		.name = "acpuclk-8960",
+		.owner = THIS_MODULE,
+	},
 };
 
-struct acpuclk_soc_data acpuclk_8930_soc_data __initdata = {
-	.init = acpuclk_8960_init,
-};
-
-struct acpuclk_soc_data acpuclk_8064_soc_data __initdata = {
-	.init = acpuclk_8960_init,
-};
+static int __init acpuclk_8960_init(void)
+{
+	return platform_driver_probe(&acpuclk_8960_driver, acpuclk_8960_probe);
+}
+device_initcall(acpuclk_8960_init);
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
index cde5a14..996f883 100644
--- a/arch/arm/mach-msm/acpuclock-8x50.c
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,6 +12,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -20,6 +21,7 @@
 #include <linux/cpufreq.h>
 #include <linux/clk.h>
 #include <linux/mfd/tps65023.h>
+#include <linux/platform_device.h>
 
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
@@ -130,7 +132,7 @@
 #ifdef CONFIG_CPU_FREQ_MSM
 static struct cpufreq_frequency_table freq_table[20];
 
-static void __init cpufreq_table_init(void)
+static void __devinit cpufreq_table_init(void)
 {
 	unsigned int i;
 	unsigned int freq_cnt = 0;
@@ -504,7 +506,7 @@
 	return rc;
 }
 
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *speed;
 	uint32_t div, sel, regval;
@@ -582,7 +584,7 @@
 
 #define PLL0_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x308)
 
-static void __init acpu_freq_tbl_fixup(void)
+static void __devinit acpu_freq_tbl_fixup(void)
 {
 	void __iomem *ct_csr_base;
 	uint32_t tcsr_spare2, pll0_m_val;
@@ -645,7 +647,7 @@
 }
 
 /* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
 {
 	int i;
 	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -657,7 +659,7 @@
 }
 
 #ifdef CONFIG_MSM_CPU_AVS
-static int __init acpu_avs_init(int (*set_vdd) (int), int khz)
+static int __devinit acpu_avs_init(int (*set_vdd) (int), int khz)
 {
 	int i;
 	int freq_count = 0;
@@ -704,7 +706,7 @@
 	.switch_time_us = 20,
 };
 
-static int __init acpuclk_8x50_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_8x50_probe(struct platform_device *pdev)
 {
 	mutex_init(&drv_state.lock);
 	drv_state.acpu_set_vdd = qsd8x50_tps65023_set_dcdc1;
@@ -736,6 +738,16 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_8x50_soc_data __initdata = {
-	.init = acpuclk_8x50_init,
+static struct platform_driver acpuclk_8x50_driver = {
+	.probe = acpuclk_8x50_probe,
+	.driver = {
+		.name = "acpuclk-8x50",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_8x50_init(void)
+{
+	return platform_driver_register(&acpuclk_8x50_driver);
+}
+postcore_initcall(acpuclk_8x50_init);
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 48efa18..ef34b3c 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -20,6 +21,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
 
 #include <asm/cpu.h>
 
@@ -734,7 +736,7 @@
 	}
 
 	/* AVS needs SAW_VCTL to be intitialized correctly, before enable,
-	 * and is not initialized at acpuclk_init().
+	 * and is not initialized during probe.
 	 */
 	if (reason == SETRATE_CPUFREQ)
 		AVS_DISABLE(cpu);
@@ -1062,7 +1064,7 @@
 	.wait_for_irq_khz = MAX_AXI,
 };
 
-static int __init acpuclk_8x60_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_8x60_probe(struct platform_device *pdev)
 {
 	struct clkctl_acpu_speed *max_freq;
 	int cpu;
@@ -1091,6 +1093,15 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_8x60_soc_data __initdata = {
-	.init = acpuclk_8x60_init,
+static struct platform_driver acpuclk_8x60_driver = {
+	.driver = {
+		.name = "acpuclk-8x60",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_8x60_init(void)
+{
+	return platform_driver_probe(&acpuclk_8x60_driver, acpuclk_8x60_probe);
+}
+device_initcall(acpuclk_8x60_init);
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index 24b81b9..db7bab3 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -22,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/cpufreq.h>
 #include <linux/clk.h>
+#include <linux/platform_device.h>
 
 #include <asm/cpu.h>
 
@@ -306,7 +308,7 @@
 	.wait_for_irq_khz = 19200,
 };
 
-static int __init acpuclk_9615_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_9615_probe(struct platform_device *pdev)
 {
 	unsigned long max_cpu_khz = 0;
 	int i;
@@ -351,6 +353,15 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_9615_soc_data __initdata = {
-	.init = acpuclk_9615_init,
+static struct platform_driver acpuclk_9615_driver = {
+	.driver = {
+		.name = "acpuclk-9615",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_9615_init(void)
+{
+	return platform_driver_probe(&acpuclk_9615_driver, acpuclk_9615_probe);
+}
+device_initcall(acpuclk_9615_init);
diff --git a/arch/arm/mach-msm/acpuclock-fsm9xxx.c b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
index 3cdc58d..af1c0eb 100644
--- a/arch/arm/mach-msm/acpuclock-fsm9xxx.c
+++ b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,8 +11,10 @@
  *
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
 #include <mach/board.h>
 
 #include "acpuclock.h"
@@ -40,13 +42,22 @@
 	.get_rate = acpuclk_9xxx_get_rate,
 };
 
-static int __init acpuclk_9xxx_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_9xxx_probe(struct platform_device *pdev)
 {
 	acpuclk_register(&acpuclk_9xxx_data);
 	pr_info("ACPU running at %lu KHz\n", acpuclk_get_rate(0));
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_9xxx_soc_data __initdata = {
-	.init = acpuclk_9xxx_init,
+static struct platform_driver acpuclk_9xxx_driver = {
+	.driver = {
+		.name = "acpuclk-9xxx",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_9xxx_init(void)
+{
+	return platform_driver_probe(&acpuclk_9xxx_driver, acpuclk_9xxx_probe);
+}
+device_initcall(acpuclk_9xxx_init);
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index 91071c4..be056e6 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -53,24 +53,7 @@
 	return rate;
 }
 
-void __init acpuclk_register(struct acpuclk_data *data)
+void __devinit acpuclk_register(struct acpuclk_data *data)
 {
 	acpuclk_data = data;
 }
-
-int __init acpuclk_init(struct acpuclk_soc_data *soc_data)
-{
-	int rc;
-
-	if (!soc_data->init)
-		return -EINVAL;
-
-	rc = soc_data->init(soc_data);
-	if (rc)
-		return rc;
-
-	if (!acpuclk_data)
-		return -ENODEV;
-
-	return 0;
-}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index c5f0ee3..e73a2af 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -31,12 +31,11 @@
 };
 
 /**
- * struct acpuclk_soc_data - SoC data for acpuclk_init()
+ * struct acpuclk_pdata - Platform data for acpuclk
  */
-struct acpuclk_soc_data {
+struct acpuclk_pdata {
 	unsigned long max_speed_delta_khz;
 	unsigned int max_axi_khz;
-	int (*init)(struct acpuclk_soc_data *);
 };
 
 /**
@@ -91,25 +90,4 @@
  */
 void acpuclk_register(struct acpuclk_data *data);
 
-/**
- * acpuclk_init() - acpuclock driver initialization function
- *
- * Return 0 for success.
- */
-int acpuclk_init(struct acpuclk_soc_data *);
-
-/* SoC-specific acpuclock initialization functions. */
-extern struct acpuclk_soc_data acpuclk_7x27_soc_data;
-extern struct acpuclk_soc_data acpuclk_7x27a_soc_data;
-extern struct acpuclk_soc_data acpuclk_7x27aa_soc_data;
-extern struct acpuclk_soc_data acpuclk_7x30_soc_data;
-extern struct acpuclk_soc_data acpuclk_8x50_soc_data;
-extern struct acpuclk_soc_data acpuclk_8x60_soc_data;
-extern struct acpuclk_soc_data acpuclk_8960_soc_data;
-extern struct acpuclk_soc_data acpuclk_9xxx_soc_data;
-extern struct acpuclk_soc_data acpuclk_9615_soc_data;
-extern struct acpuclk_soc_data acpuclk_8930_soc_data;
-extern struct acpuclk_soc_data acpuclk_8064_soc_data;
-extern struct acpuclk_soc_data acpuclk_8625_soc_data;
-
 #endif
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 40b87fc..1d231ef 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -74,7 +74,6 @@
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
-#include "acpuclock.h"
 #include "spm.h"
 #include <mach/mpm.h>
 #include "rpm_resources.h"
@@ -2110,6 +2109,7 @@
 };
 
 static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_acpuclk,
 	&apq8064_device_dmov,
 	&apq8064_device_qup_spi_gsbi5,
 	&apq8064_device_ext_5v_vreg,
@@ -2911,7 +2911,6 @@
 		ARRAY_SIZE(apq8064_slim_devices));
 	apq8064_init_dsps();
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
-	acpuclk_init(&acpuclk_8064_soc_data);
 	msm_spm_l2_init(msm_spm_l2_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 6c4cbd3..e075630 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -86,7 +86,6 @@
 #include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include <mach/mpm.h>
-#include "acpuclock.h"
 #include "smd_private.h"
 #include "pm-boot.h"
 #include "msm_watchdog.h"
@@ -2035,6 +2034,7 @@
 };
 
 static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_acpuclk,
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm8960_device_uart_gsbi5,
@@ -2433,7 +2433,6 @@
 	msm8930_init_cam();
 #endif
 	msm8930_init_mmc();
-	acpuclk_init(&acpuclk_8930_soc_data);
 	mxt_init_vkeys_8930();
 	register_i2c_devices();
 	msm8930_init_fb();
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 8f49afd..22ef940 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -97,7 +97,6 @@
 #include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include <mach/mpm.h>
-#include "acpuclock.h"
 #include "smd_private.h"
 #include "pm-boot.h"
 #include "msm_watchdog.h"
@@ -2508,6 +2507,7 @@
 #endif
 
 static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_acpuclk,
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm_device_uart_dm6,
@@ -3060,7 +3060,6 @@
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	msm8960_pm8921_gpio_mpp_init();
 	platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
-	acpuclk_init(&acpuclk_8960_soc_data);
 
 	msm8960_device_qup_spi_gsbi1.dev.platform_data =
 				&msm8960_qup_spi_gsbi1_pdata;
@@ -3173,7 +3172,6 @@
 	msm8960_init_cam();
 #endif
 	msm8960_init_mmc();
-	acpuclk_init(&acpuclk_8960_soc_data);
 	if (machine_is_msm8960_liquid())
 		mxt_init_hw_liquid();
 	register_i2c_devices();
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index dc376b5..1089d61 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -50,7 +50,6 @@
 #include "devices.h"
 #include "board-9615.h"
 #include "pm.h"
-#include "acpuclock.h"
 #include "pm-boot.h"
 #include <mach/gpiomux.h>
 
@@ -850,6 +849,7 @@
 };
 
 static struct platform_device *common_devices[] = {
+	&msm9615_device_acpuclk,
 	&msm9615_device_dmov,
 	&msm_device_smd,
 #ifdef CONFIG_LTC4088_CHARGER
@@ -979,7 +979,6 @@
 	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	msm9615_pm8xxx_gpio_mpp_init();
-	acpuclk_init(&acpuclk_9615_soc_data);
 
 	/* Ensure ar6000pm device is registered before MMC/SDC */
 	msm9615_init_ar6000pm();
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 6ad3cef..b071353 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -38,7 +38,6 @@
 #include <mach/socinfo.h>
 #include "devices.h"
 #include "timer.h"
-#include "acpuclock.h"
 #include "pm.h"
 #include "spm.h"
 #include <linux/regulator/consumer.h>
@@ -804,11 +803,17 @@
 	},
 };
 
+static struct platform_device fsm9xxx_device_acpuclk = {
+	.name		= "acpuclk-9xxx",
+	.id		= -1,
+};
+
 /*
  * Devices
  */
 
 static struct platform_device *devices[] __initdata = {
+	&fsm9xxx_device_acpuclk,
 	&msm_device_smd,
 	&msm_device_dmov,
 	&msm_device_nand,
@@ -873,8 +878,6 @@
 
 static void __init fsm9xxx_init(void)
 {
-	acpuclk_init(&acpuclk_9xxx_soc_data);
-
 	regulator_has_full_constraints();
 
 #if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d42458f..a7fed3e 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -65,7 +65,6 @@
 #include "board-msm7627-regulator.h"
 #include "devices.h"
 #include "clock.h"
-#include "acpuclock.h"
 #include "msm-keypad-devices.h"
 #include "pm.h"
 #include "pm-boot.h"
@@ -1775,7 +1774,7 @@
 		}
 	}
 #endif
-	acpuclk_init(&acpuclk_7x27_soc_data);
+	platform_device_register(&msm7x27_device_acpuclk);
 
 	usb_mpp_init();
 
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 96d8b17..2834f24 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -6956,7 +6956,7 @@
 	msm7x30_init_uart2();
 #endif
 	msm_spm_init(&msm_spm_data, 1);
-	acpuclk_init(&acpuclk_7x30_soc_data);
+	platform_device_register(&msm7x30_device_acpuclk);
 	if (machine_is_msm7x30_surf() || machine_is_msm7x30_fluid())
 		msm7x30_cfg_smsc911x();
 
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 54c8fbd..098ad6e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -100,7 +100,6 @@
 #include "peripheral-loader.h"
 #include <linux/platform_data/qcom_crypto_device.h>
 #include "rpm_resources.h"
-#include "acpuclock.h"
 #include "pm-boot.h"
 #include "board-storage-common-a.h"
 
@@ -5135,6 +5134,7 @@
 };
 
 static struct platform_device *surf_devices[] __initdata = {
+	&msm8x60_device_acpuclk,
 	&msm_device_smd,
 	&msm_device_uart_dm12,
 	&msm_pil_q6v3,
@@ -10339,9 +10339,6 @@
 	 */
 	msm8x60_init_buses();
 	platform_add_devices(early_devices, ARRAY_SIZE(early_devices));
-	/* CPU frequency control is not supported on simulated targets. */
-	if (!machine_is_msm8x60_rumi3() && !machine_is_msm8x60_sim())
-		acpuclk_init(&acpuclk_8x60_soc_data);
 
 	/*
 	 * Enable EBI2 only for boards which make use of it. Leave
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 6a39316..4df4266 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -2409,7 +2409,7 @@
 {
 	msm_clock_init(&qds8x50_clock_init_data);
 	qsd8x50_cfg_smc91x();
-	acpuclk_init(&acpuclk_8x50_soc_data);
+	platform_device_register(&msm8x50_device_acpuclk);
 
 	msm_hsusb_pdata.swfi_latency =
 		msm_pm_data
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 6a9f7f0..550a283 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -202,6 +202,11 @@
 	},
 };
 
+struct platform_device msm8960_device_acpuclk = {
+	.name		= "acpuclk-8960",
+	.id		= -1,
+};
+
 #define SHARED_IMEM_TZ_BASE 0x2a03f720
 static struct resource tzlog_resources[] = {
 	{
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index f13c266..06d8653 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -107,6 +107,11 @@
 	},
 };
 
+struct platform_device msm9615_device_acpuclk = {
+	.name           = "acpuclk-9615",
+	.id             = -1,
+};
+
 #define MSM_USB_BAM_BASE     0x12502000
 #define MSM_USB_BAM_SIZE     SZ_16K
 #define MSM_HSIC_BAM_BASE    0x12542000
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index ffd10fa..4619cca 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -27,6 +27,7 @@
 
 #include "devices.h"
 #include "footswitch.h"
+#include "acpuclock.h"
 
 #include <asm/mach/flash.h>
 
@@ -431,6 +432,16 @@
 	msm_pm_set_irq_extns(&msm7x27_pm_irq_calls);
 }
 
+static struct acpuclk_pdata msm7x27_acpuclk_pdata = {
+	.max_speed_delta_khz = 400000,
+};
+
+struct platform_device msm7x27_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm7x27_acpuclk_pdata,
+};
+
 #define MSM_SDC1_BASE         0xA0400000
 #define MSM_SDC2_BASE         0xA0500000
 #define MSM_SDC3_BASE         0xA0600000
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index adc9169..b3454cd 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -211,6 +211,37 @@
 	},
 };
 
+static struct acpuclk_pdata msm7x27a_acpuclk_pdata = {
+	.max_speed_delta_khz = 400000,
+};
+
+struct platform_device msm7x27a_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm7x27a_acpuclk_pdata,
+};
+
+static struct acpuclk_pdata msm7x27aa_acpuclk_pdata = {
+	.max_speed_delta_khz = 504000,
+};
+
+struct platform_device msm7x27aa_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm7x27aa_acpuclk_pdata,
+};
+
+static struct acpuclk_pdata msm8625_acpuclk_pdata = {
+	/* TODO: Need to update speed delta from H/w Team */
+	.max_speed_delta_khz = 604800,
+};
+
+struct platform_device msm8625_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm8625_acpuclk_pdata,
+};
+
 struct platform_device msm_device_smd = {
 	.name	= "msm_smd",
 	.id	= -1,
@@ -1623,16 +1654,15 @@
 
 	msm_clock_init(&msm7x27a_clock_init_data);
 	if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
-		acpuclk_init(&acpuclk_7x27aa_soc_data);
+		platform_device_register(&msm7x27aa_device_acpuclk);
 	else if (cpu_is_msm8625()) {
 		if (msm8625_cpu_id() == MSM8625)
-			acpuclk_init(&acpuclk_7x27aa_soc_data);
+			platform_device_register(&msm7x27aa_device_acpuclk);
 		else if (msm8625_cpu_id() == MSM8625A)
-			acpuclk_init(&acpuclk_8625_soc_data);
-	 } else {
-		acpuclk_init(&acpuclk_7x27a_soc_data);
-	 }
-
+			platform_device_register(&msm8625_device_acpuclk);
+	} else {
+		platform_device_register(&msm7x27a_device_acpuclk);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index de70429..ff747e2 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -42,6 +42,11 @@
 #include "pm.h"
 #include "irq.h"
 
+struct platform_device msm7x30_device_acpuclk = {
+	.name		= "acpuclk-7x30",
+	.id		= -1,
+};
+
 /* EBI THERMAL DRIVER */
 static struct resource msm_ebi0_thermal_resources[] = {
 	{
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 37844c1..d8bf054 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -163,6 +163,11 @@
 	},
 };
 
+struct platform_device msm8x60_device_acpuclk = {
+	.name		= "acpuclk-8x60",
+	.id		= -1,
+};
+
 #ifdef CONFIG_MSM_DSPS
 #define GSBI12_DEV (&msm_dsps_device.dev)
 #else
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index ee8a2cf..2ecc852 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -34,6 +34,11 @@
 #include <mach/rpc_hsusb.h>
 #include "pm.h"
 
+struct platform_device msm8x50_device_acpuclk = {
+	.name		= "acpuclk-8x50",
+	.id		= -1,
+};
+
 static struct resource resources_uart1[] = {
 	{
 		.start	= INT_UART1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 17cce7b..ea47727 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -412,3 +412,13 @@
 extern struct platform_device mdm_sglte_device;
 
 extern struct platform_device apq_device_tz_log;
+
+extern struct platform_device msm7x27_device_acpuclk;
+extern struct platform_device msm7x27a_device_acpuclk;
+extern struct platform_device msm7x27aa_device_acpuclk;
+extern struct platform_device msm7x30_device_acpuclk;
+extern struct platform_device msm8625_device_acpuclk;
+extern struct platform_device msm8x50_device_acpuclk;
+extern struct platform_device msm8x60_device_acpuclk;
+extern struct platform_device msm8960_device_acpuclk;
+extern struct platform_device msm9615_device_acpuclk;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 83d65b1..69aa411 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1016,7 +1016,7 @@
 					ENCODE_RSP_AND_SEND(8+rt_mask_size-1);
 					return 0;
 				}
-				ptr += MAX_SSID_PER_RANGE*4;
+				rt_mask_ptr += MAX_SSID_PER_RANGE*4;
 			}
 		} else
 			buf = temp;
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 964218f..5ffc133 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -261,6 +261,16 @@
 	---help---
 	  Enable support for Video Pre-processing Engine
 
+config MSM_CAM_IRQ_ROUTER
+	bool "Enable MSM CAM IRQ Router"
+	depends on MSM_CAMERA
+	---help---
+	Enable IRQ Router for Camera. Depending on the
+	configuration, this module can handle the
+	interrupts from multiple camera hardware
+	cores and composite them into a single
+	interrupt to the MSM.
+
 config QUP_EXCLUSIVE_TO_CAMERA
 	bool "QUP exclusive to camera"
 	depends on MSM_CAMERA
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 9ed6cca..431da2e 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -14,6 +14,7 @@
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
   obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
   obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
+  obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index a217f9d..dbb4f32 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -388,6 +388,8 @@
 {
 	struct csic_device *new_csic_dev;
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	new_csic_dev = kzalloc(sizeof(struct csic_device), GFP_KERNEL);
 	if (!new_csic_dev) {
@@ -455,8 +457,11 @@
 
 	iounmap(new_csic_dev->base);
 	new_csic_dev->base = NULL;
+	sd_info.sdev_type = CSIC_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = new_csic_dev->irq->start;
 	msm_cam_register_subdev_node(
-		&new_csic_dev->subdev, CSIC_DEV, pdev->id);
+		&new_csic_dev->subdev, &sd_info);
 
 	return 0;
 
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index bb2a1d4..1ab4e66 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -298,6 +298,8 @@
 static int __devinit csid_probe(struct platform_device *pdev)
 {
 	struct csid_device *new_csid_dev;
+	struct msm_cam_subdev_info sd_info;
+
 	int rc = 0;
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
@@ -338,7 +340,10 @@
 	}
 
 	new_csid_dev->pdev = pdev;
-	msm_cam_register_subdev_node(&new_csid_dev->subdev, CSID_DEV, pdev->id);
+	sd_info.sdev_type = CSID_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = new_csid_dev->irq->start;
+	msm_cam_register_subdev_node(&new_csid_dev->subdev, &sd_info);
 	return 0;
 
 csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index e25660b..4693a8a 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -282,6 +282,8 @@
 {
 	struct csiphy_device *new_csiphy_dev;
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL);
 	if (!new_csiphy_dev) {
@@ -333,8 +335,11 @@
 	disable_irq(new_csiphy_dev->irq->start);
 
 	new_csiphy_dev->pdev = pdev;
+	sd_info.sdev_type = CSIPHY_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = new_csiphy_dev->irq->start;
 	msm_cam_register_subdev_node(
-		&new_csiphy_dev->subdev, CSIPHY_DEV, pdev->id);
+		&new_csiphy_dev->subdev, &sd_info);
 	return 0;
 
 csiphy_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index be97091..0f16bbf 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -640,6 +640,8 @@
 static int __devinit ispif_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s\n", __func__);
 	ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
 	if (!ispif) {
@@ -687,7 +689,10 @@
 	}
 
 	ispif->pdev = pdev;
-	msm_cam_register_subdev_node(&ispif->subdev, ISPIF_DEV, pdev->id);
+	sd_info.sdev_type = ISPIF_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = ispif->irq->start;
+	msm_cam_register_subdev_node(&ispif->subdev, &sd_info);
 	return 0;
 
 ispif_no_mem:
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index c3c09d4..d34b8e1 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1277,6 +1277,7 @@
 	struct msm_camera_sensor_info *sdata;
 	struct msm_cam_v4l2_device *pcam;
 	struct msm_sensor_ctrl_t *s_ctrl;
+	struct msm_cam_subdev_info sd_info;
 
 	D("%s for %s\n", __func__, sensor_sd->name);
 
@@ -1321,8 +1322,11 @@
 	}
 	msm_server_update_sensor_info(pcam, sdata);
 
+	sd_info.sdev_type = SENSOR_DEV;
+	sd_info.sd_index = vnode_count;
+	sd_info.irq_num = 0;
 	/* register the subdevice, must be done for callbacks */
-	rc = msm_cam_register_subdev_node(sensor_sd, SENSOR_DEV, vnode_count);
+	rc = msm_cam_register_subdev_node(sensor_sd, &sd_info);
 	if (rc < 0) {
 		D("%s sensor sub device register failed\n",
 			__func__);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 1f1f329..d0322d1 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -58,14 +58,16 @@
 #define MSM_GEMINI_DRV_NAME "msm_gemini"
 #define MSM_MERCURY_DRV_NAME "msm_mercury"
 #define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
+#define MSM_IRQ_ROUTER_DRV_NAME "msm_cam_irq_router"
 
 #define MAX_NUM_CSIPHY_DEV 3
-#define MAX_NUM_CSID_DEV 3
+#define MAX_NUM_CSID_DEV 4
 #define MAX_NUM_CSIC_DEV 3
 #define MAX_NUM_ISPIF_DEV 1
 #define MAX_NUM_VFE_DEV 2
 #define MAX_NUM_AXI_DEV 2
 #define MAX_NUM_VPE_DEV 1
+#define MAX_NUM_JPEG_DEV 3
 
 enum msm_cam_subdev_type {
 	CSIPHY_DEV,
@@ -79,6 +81,7 @@
 	ACTUATOR_DEV,
 	EEPROM_DEV,
 	GESTURE_DEV,
+	IRQ_ROUTER_DEV,
 };
 
 /* msm queue management APIs*/
@@ -405,6 +408,15 @@
 	struct msm_mem_map_info mem_map;
 };
 
+struct msm_cam_subdev_info {
+	uint8_t sdev_type;
+	/* Subdev index. For eg: CSIPHY0, CSIPHY1 etc */
+	uint8_t sd_index;
+	/* This device/subdev's interrupt number, assigned
+	 * from the hardware document. */
+	uint8_t irq_num;
+};
+
 /* 2 for camera, 1 for gesture */
 #define MAX_NUM_ACTIVE_CAMERA 3
 
@@ -421,6 +433,68 @@
 	uint32_t handle;
 };
 
+struct msm_cam_server_irqmap_entry {
+	int irq_num;
+	int irq_idx;
+	uint8_t cam_hw_idx;
+	uint8_t is_composite;
+};
+
+struct intr_table_entry {
+	/* irq_num as understood by msm.
+	 * Unique for every camera hw core & target. Use a mapping function
+	 * to map this irq number to its equivalent index in camera side. */
+	int irq_num;
+	/* Camera hw core idx, in case of non-composite IRQs*/
+	uint8_t cam_hw_idx;
+	/* Camera hw core mask, in case of composite IRQs. */
+	uint32_t cam_hw_mask;
+	/* Each interrupt is mapped to an index, which is used
+	 * to add/delete entries into the lookup table. Both the information
+	 * are needed in the lookup table to avoid another subdev call into
+	 * the IRQ Router subdev to get the irq_idx in the interrupt context */
+	int irq_idx;
+	/* Is this irq composite? */
+	uint8_t is_composite;
+	/* IRQ Trigger type: TRIGGER_RAISING, TRIGGER_HIGH, etc. */
+	uint32_t irq_trigger_type;
+	/* If IRQ Router hw is present,
+	 * this field holds the number of camera hw core
+	 * which are bundled together in the above
+	 * interrupt. > 1 in case of composite irqs.
+	 * If IRQ Router hw is not present, this field should be set to 1. */
+	int num_hwcore;
+	/* Pointers to the subdevs composited in this
+	 * irq. If not composite, the 0th index stores the subdev to which
+	 * this irq needs to be dispatched to. */
+	struct v4l2_subdev *subdev_list[CAMERA_SS_IRQ_MAX];
+	/* Device requesting the irq. */
+	const char *dev_name;
+	/* subdev private data, if any */
+	void *data;
+};
+
+struct irqmgr_intr_lkup_table {
+	/* Individual(hw) interrupt lookup table:
+	 * This table is populated during initialization and doesnt
+	 * change, unless the IRQ Router has been configured
+	 * for composite IRQs. If the IRQ Router has been configured
+	 * for composite IRQs, the is_composite field of that IRQ will
+	 * be set to 1(default 0). And when there is an interrupt on
+	 * that line, the composite interrupt lookup table is used
+	 * for handling the interrupt. */
+	struct intr_table_entry ind_intr_tbl[CAMERA_SS_IRQ_MAX];
+
+	/* Composite interrupt lookup table:
+	 * This table can be dynamically modified based on the usecase.
+	 * If the usecase requires two or more HW core IRQs to be bundled
+	 * into a single composite IRQ, then this table is populated
+	 * accordingly. Also when this is done, the composite field
+	 * in the intr_lookup_table has to be updated to reflect that
+	 * the irq 'irq_num' will now  be triggered in composite mode. */
+	struct intr_table_entry comp_intr_tbl[CAMERA_SS_IRQ_MAX];
+};
+
 /* abstract camera server device for all sensor successfully probed*/
 struct msm_cam_server_dev {
 
@@ -466,9 +540,18 @@
 	struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
 	struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
 	struct v4l2_subdev *gesture_device;
-};
+	struct v4l2_subdev *irqr_device;
 
-/* camera server related functions */
+	spinlock_t  intr_table_lock;
+	struct irqmgr_intr_lkup_table irq_lkup_table;
+	/* Stores the pointer to the subdev when the individual
+	 * subdevices register themselves with the server. This
+	 * will be used while dispatching composite irqs. The
+	 * cam_hw_idx will serve as the index into this array to
+	 * dispatch the irq to the corresponding subdev. */
+	struct v4l2_subdev *subdev_table[MSM_CAM_HW_MAX];
+	struct msm_cam_server_irqmap_entry hw_irqmap[CAMERA_SS_IRQ_MAX];
+};
 
 /* ISP related functions */
 void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
@@ -583,7 +666,7 @@
 					void __user *arg);
 void msm_release_ion_client(struct kref *ref);
 int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
-			enum msm_cam_subdev_type sdev_type, uint8_t index);
+	struct msm_cam_subdev_info *sd_info);
 int msm_server_open_client(int *p_qidx);
 int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
 int msm_server_close_client(int idx);
diff --git a/drivers/media/video/msm/msm_camirq_router.c b/drivers/media/video/msm/msm_camirq_router.c
new file mode 100644
index 0000000..52dd175
--- /dev/null
+++ b/drivers/media/video/msm/msm_camirq_router.c
@@ -0,0 +1,266 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+#include <media/msm_isp.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include "server/msm_cam_server.h"
+#include "msm_camirq_router.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static void msm_irqrouter_update_irqmap_entry(
+	struct msm_cam_server_irqmap_entry *entry,
+	int is_composite, int irq_idx, int cam_hw_idx)
+{
+	int rc = 0;
+	entry->irq_idx = irq_idx;
+	entry->is_composite = is_composite;
+	entry->cam_hw_idx = cam_hw_idx;
+	rc = msm_cam_server_update_irqmap(entry);
+	if (rc < 0)
+		pr_err("%s Error updating irq %d information ",
+			__func__, irq_idx);
+}
+
+static void msm_irqrouter_send_default_irqmap(
+	struct irqrouter_ctrl_type *irqrouter_ctrl)
+{
+	struct msm_cam_server_irqmap_entry *irqmap =
+		&irqrouter_ctrl->def_hw_irqmap[0];
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_0],
+		0, CAMERA_SS_IRQ_0, MSM_CAM_HW_MICRO);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_1],
+		0, CAMERA_SS_IRQ_1, MSM_CAM_HW_CCI);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_2],
+		0, CAMERA_SS_IRQ_2, MSM_CAM_HW_CSI0);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_3],
+		0, CAMERA_SS_IRQ_3, MSM_CAM_HW_CSI1);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_4],
+		0, CAMERA_SS_IRQ_4, MSM_CAM_HW_CSI2);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_5],
+		0, CAMERA_SS_IRQ_5, MSM_CAM_HW_CSI3);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_6],
+		0, CAMERA_SS_IRQ_6, MSM_CAM_HW_ISPIF);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_7],
+		0, CAMERA_SS_IRQ_7, MSM_CAM_HW_CPP);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_8],
+		0, CAMERA_SS_IRQ_8, MSM_CAM_HW_VFE0);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_9],
+		0, CAMERA_SS_IRQ_9, MSM_CAM_HW_VFE1);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_10],
+		0, CAMERA_SS_IRQ_10, MSM_CAM_HW_JPEG0);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_11],
+		0, CAMERA_SS_IRQ_11, MSM_CAM_HW_JPEG1);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_12],
+		0, CAMERA_SS_IRQ_12, MSM_CAM_HW_JPEG2);
+}
+
+static int msm_irqrouter_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+	/* Only one object of IRQ Router allowed. */
+	if (atomic_read(&irqrouter_ctrl->active) != 0) {
+		pr_err("%s IRQ router is already opened\n", __func__);
+		return -EINVAL;
+	}
+
+	D("%s E ", __func__);
+	atomic_inc(&irqrouter_ctrl->active);
+
+	return 0;
+}
+
+static int msm_irqrouter_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+	if (atomic_read(&irqrouter_ctrl->active) == 0) {
+		pr_err("%s IRQ router is already closed\n", __func__);
+		return -EINVAL;
+	}
+	D("%s E ", __func__);
+	atomic_dec(&irqrouter_ctrl->active);
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_irqrouter_internal_ops = {
+	.open = msm_irqrouter_open,
+	.close = msm_irqrouter_close,
+};
+
+long msm_irqrouter_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+	struct msm_camera_irq_cfg *irq_cfg;
+	struct intr_table_entry irq_req;
+	int rc = 0;
+
+	/* Handle all IRQ Router Subdev IOCTLs here.
+	 * Userspace sends the composite irq configuration.
+	 * IRQ Router subdev then configures the registers to group
+	 * together individual core hw irqs into a composite IRQ
+	 * to the MSM IRQ controller. It also registers them with
+	 * the irq manager in the camera server. */
+	switch (cmd) {
+	case MSM_IRQROUTER_CFG_COMPIRQ:
+		COPY_FROM_USER(rc, &irq_cfg, (void __user *)arg,
+			sizeof(struct msm_camera_irq_cfg));
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			break;
+		}
+
+		if (!irq_cfg ||
+			(irq_cfg->irq_idx < CAMERA_SS_IRQ_0) ||
+			(irq_cfg->irq_idx >= CAMERA_SS_IRQ_MAX)) {
+			pr_err("%s Invalid input", __func__);
+			return -EINVAL;
+		} else {
+			irq_req.cam_hw_mask      = irq_cfg->cam_hw_mask;
+			irq_req.irq_idx          = irq_cfg->irq_idx;
+			irq_req.irq_num          =
+			irqrouter_ctrl->def_hw_irqmap[irq_cfg->irq_idx].irq_num;
+			irq_req.is_composite     = 1;
+			irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+			irq_req.num_hwcore       = irq_cfg->num_hwcore;
+			irq_req.data             = NULL;
+			rc = msm_cam_server_request_irq(&irq_req);
+			if (rc < 0) {
+				pr_err("%s Error requesting comp irq %d ",
+					__func__, irq_req.irq_idx);
+				return rc;
+			}
+			irqrouter_ctrl->def_hw_irqmap
+				[irq_cfg->irq_idx].is_composite = 1;
+		}
+		break;
+	default:
+		pr_err("%s Invalid cmd %d ", __func__, cmd);
+		break;
+	}
+
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_irqrouter_subdev_core_ops = {
+	.ioctl = msm_irqrouter_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_irqrouter_subdev_ops = {
+	.core = &msm_irqrouter_subdev_core_ops,
+};
+
+static int __devinit irqrouter_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct irqrouter_ctrl_type *irqrouter_ctrl;
+	struct msm_cam_subdev_info sd_info;
+
+	D("%s: device id = %d\n", __func__, pdev->id);
+
+	irqrouter_ctrl = kzalloc(sizeof(struct irqrouter_ctrl_type),
+				GFP_KERNEL);
+	if (!irqrouter_ctrl) {
+		pr_err("%s: not enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&irqrouter_ctrl->subdev, &msm_irqrouter_subdev_ops);
+	irqrouter_ctrl->subdev.internal_ops = &msm_irqrouter_internal_ops;
+	irqrouter_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(irqrouter_ctrl->subdev.name,
+			 sizeof(irqrouter_ctrl->subdev.name), "msm_irqrouter");
+	v4l2_set_subdevdata(&irqrouter_ctrl->subdev, irqrouter_ctrl);
+	irqrouter_ctrl->pdev = pdev;
+
+	msm_irqrouter_send_default_irqmap(irqrouter_ctrl);
+
+	media_entity_init(&irqrouter_ctrl->subdev.entity, 0, NULL, 0);
+	irqrouter_ctrl->subdev.entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+	irqrouter_ctrl->subdev.entity.group_id = IRQ_ROUTER_DEV;
+	irqrouter_ctrl->subdev.entity.name = pdev->name;
+
+	sd_info.sdev_type = IRQ_ROUTER_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	/* Now register this subdev with the camera server. */
+	rc = msm_cam_register_subdev_node(&irqrouter_ctrl->subdev, &sd_info);
+	if (rc < 0) {
+		pr_err("%s Error registering irqr subdev %d", __func__, rc);
+		goto error;
+	}
+	irqrouter_ctrl->subdev.entity.revision =
+		irqrouter_ctrl->subdev.devnode->num;
+	atomic_set(&irqrouter_ctrl->active, 0);
+
+	platform_set_drvdata(pdev, &irqrouter_ctrl->subdev);
+
+	return rc;
+error:
+	kfree(irqrouter_ctrl);
+	return rc;
+}
+
+static int __exit irqrouter_exit(struct platform_device *pdev)
+{
+	kfree(irqrouter_ctrl);
+	return 0;
+}
+
+static struct platform_driver msm_irqrouter_driver = {
+	.probe = irqrouter_probe,
+	.remove = irqrouter_exit,
+	.driver = {
+		.name = MSM_IRQ_ROUTER_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_irqrouter_init_module(void)
+{
+	return platform_driver_register(&msm_irqrouter_driver);
+}
+
+static void __exit msm_irqrouter_exit_module(void)
+{
+	platform_driver_unregister(&msm_irqrouter_driver);
+}
+
+module_init(msm_irqrouter_init_module);
+module_exit(msm_irqrouter_exit_module);
+MODULE_DESCRIPTION("msm camera irq router");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_camirq_router.h b/drivers/media/video/msm/msm_camirq_router.h
new file mode 100644
index 0000000..2c9cb73
--- /dev/null
+++ b/drivers/media/video/msm/msm_camirq_router.h
@@ -0,0 +1,206 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_CAM_IRQROUTER_H__
+#define __MSM_CAM_IRQROUTER_H__
+
+#include <linux/bitops.h>
+
+/* Camera SS common registers defines - Start */
+/* These registers are not directly related to
+ * IRQ Router, but are common to the Camera SS.
+ * IRQ Router registers dont have a unique base address
+ * in the memory mapped address space. It is offset from
+ * the Camera SS base address. So keep the common Camera
+ * SS registers also in the IRQ Router subdev for now. */
+
+/* READ ONLY: Camera Subsystem HW version */
+#define CAMSS_HW_VERSION			0x00000000
+
+/* Bits 4:0 of this register can be used to select a desired
+ * camera core test bus to drive the Camera_SS test bus output */
+#define CAMSS_TESTBUS_SEL			0x00000004
+
+/* Bits 4:0 of this register is used to allow either Microcontroller
+ * or the CCI drive the corresponding GPIO output.
+ * For eg: Setting bit 0 of this register allows Microcontroller to
+ * drive GPIO #0. Clearing the bit allows CCI to drive GPIO #0. */
+#define CAMSS_GPIO_MUX_SEL			0x00000008
+
+/* Bit 0 of this register is used to set the default AHB master
+ * for the AHB Arbiter. 0 - AHB Master 0, 1 - AHB Master 1*/
+#define CAMSS_AHB_ARB_CTL			0x0000000C
+
+/* READ ONLY */
+#define CAMSS_XPU2_STATUS			0x00000010
+
+/* Select the appropriate CSI clock for CSID Pixel pipes */
+#define CAMSS_CSI_PIX_CLK_MUX_SEL		0x00000020
+#define CAMSS_CSI_PIX_CLK_CGC_EN		0x00000024
+
+/* Select the appropriate CSI clock for CSID RDI pipes */
+#define CAMSS_CSI_RDI_CLK_MUX_SEL		0x00000028
+#define CAMSS_CSI_RDI_CLK_CGC_EN		0x0000002C
+
+/* Select the appropriate CSI clock for CSI Phy0 */
+#define CAMSS_CSI_PHY_0_CLK_MUX_SEL		0x00000030
+#define CAMSS_CSI_PHY_0_CLK_CGC_EN		0x00000034
+
+/* Select the appropriate CSI clock for CSI Phy1 */
+#define CAMSS_CSI_PHY_1_CLK_MUX_SEL		0x00000038
+#define CAMSS_CSI_PHY_1_CLK_CGC_EN		0x0000003C
+
+/* Select the appropriate CSI clock for CSI Phy2 */
+#define CAMSS_CSI_PHY_2_CLK_MUX_SEL		0x00000040
+#define CAMSS_CSI_PHY_2_CLK_CGC_EN		0x00000044
+/* Camera SS common registers defines - End */
+
+/* IRQ Router registers defines - Start */
+/* This register is used to reset the composite
+ * IRQ outputs of the Camera_SS IRQ Router */
+#define CAMSS_IRQ_COMPOSITE_RESET_CTRL		0x00000060
+
+/* By default, this 'allows' the interrupts from
+ * Micro to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_0		0x00000064
+
+/* By default, this 'allows' the interrupts from
+ * CCI to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_1		0x00000068
+
+/* By default, this 'allows' the interrupts from
+ * CSI_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_2		0x0000006C
+
+/* By default, this 'allows' the interrupts from
+ * CSI_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_3		0x00000070
+
+/* By default, this 'allows' the interrupts from
+ * CSI_2 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_4		0x00000074
+
+/* By default, this 'allows' the interrupts from
+ * CSI_3 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_5		0x00000078
+
+/* By default, this 'allows' the interrupts from
+ * ISPIF to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_6		0x0000007C
+
+/* By default, this 'allows' the interrupts from
+ * CPP to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_7		0x00000080
+
+/* By default, this 'allows' the interrupts from
+ * VFE_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_8		0x00000084
+
+/* By default, this 'allows' the interrupts from
+ * VFE_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_9		0x00000088
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_10		0x0000008C
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_11		0x00000090
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_2 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_12		0x00000094
+
+/* The following IRQ_COMPOSITE_MICRO_MASK registers
+ * allow the interrupts from the individual hw
+ * cores to be composited into an IRQ for Micro. */
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_0	0x000000A4
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_1	0x000000A8
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_2	0x000000AC
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_3	0x000000B0
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_4	0x000000B4
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_5	0x000000B8
+/* IRQ Router register defines - End */
+
+/* Writing this mask will reset all the composite
+ * IRQs of the Camera_SS IRQ Router */
+#define CAMSS_IRQ_COMPOSITE_RESET_MASK		0x003F1FFF
+
+/* Use this to enable Micro IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_MICRO_IRQ_IN_COMPOSITE		BIT(0)
+/* Use this to enable CCI IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CCI_IRQ_IN_COMPOSITE		BIT(1)
+/* Use this to enable CSI0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI0_IRQ_IN_COMPOSITE		BIT(2)
+/* Use this to enable CSI1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI1_IRQ_IN_COMPOSITE		BIT(3)
+/* Use this to enable CSI2 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI2_IRQ_IN_COMPOSITE		BIT(4)
+/* Use this to enable CSI3 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI3_IRQ_IN_COMPOSITE		BIT(5)
+/* Use this to enable ISPIF IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_ISPIF_IRQ_IN_COMPOSITE		BIT(6)
+/* Use this to enable CPP IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CPP_IRQ_IN_COMPOSITE		BIT(7)
+/* Use this to enable VFE0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_VFE0_IRQ_IN_COMPOSITE		BIT(8)
+/* Use this to enable VFE1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_VFE1_IRQ_IN_COMPOSITE		BIT(9)
+/* Use this to enable JPEG0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG0_IRQ_IN_COMPOSITE		BIT(10)
+/* Use this to enable JPEG1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG1_IRQ_IN_COMPOSITE		BIT(11)
+/* Use this to enable JPEG2 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG2_IRQ_IN_COMPOSITE		BIT(12)
+
+struct irqrouter_ctrl_type {
+	/* v4l2 subdev */
+	struct v4l2_subdev subdev;
+	struct platform_device *pdev;
+
+	void __iomem *irqr_dev_base;
+
+	struct resource	*irqr_dev_mem;
+	struct resource *irqr_dev_io;
+	atomic_t active;
+	struct msm_cam_server_irqmap_entry def_hw_irqmap[CAMERA_SS_IRQ_MAX];
+};
+
+#endif /* __MSM_CAM_IRQROUTER_H__ */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
index 6b81d15..5777cb5 100644
--- a/drivers/media/video/msm/msm_gesture.c
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -455,6 +455,8 @@
 	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
 	struct v4l2_subdev *gesture_subdev =
 		kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	struct msm_cam_subdev_info sd_info;
+
 	D("%s\n", __func__);
 	if (!gesture_subdev) {
 		pr_err("%s: no enough memory\n", __func__);
@@ -475,7 +477,10 @@
 	/* events */
 	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
 
-	msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+	sd_info.sdev_type = GESTURE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(gesture_subdev, &sd_info);
 
 	gesture_subdev->entity.revision = gesture_subdev->devnode->num;
 
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index a6cc06e..885cd90 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -3844,7 +3844,10 @@
 static int __devinit vfe31_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
+
 	vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL);
 	if (!vfe31_ctrl) {
 		pr_err("%s: no enough memory\n", __func__);
@@ -3916,7 +3919,10 @@
 	disable_irq(vfe31_ctrl->vfeirq->start);
 
 	vfe31_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vfe31_ctrl->subdev, VFE_DEV, 0);
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = vfe31_ctrl->vfeirq->start;
+	msm_cam_register_subdev_node(&vfe31_ctrl->subdev, &sd_info);
 	return 0;
 
 vfe31_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 9544ce5..9382292 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -25,6 +25,7 @@
 #include <media/msm_isp.h>
 
 #include "msm.h"
+#include "msm_cam_server.h"
 #include "msm_vfe32.h"
 
 atomic_t irq_cnt;
@@ -3979,6 +3980,17 @@
 	return IRQ_HANDLED;
 }
 
+int msm_axi_subdev_isr_routine(struct v4l2_subdev *sd,
+	u32 status, bool *handled)
+{
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+	pr_info("%s E ", __func__);
+	ret = vfe32_parse_irq(axi_ctrl->vfeirq->start, axi_ctrl);
+	*handled = TRUE;
+	return 0;
+}
+
 static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int subdev_cmd, void *arg)
 {
@@ -4678,6 +4690,7 @@
 
 static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
 	.ioctl = msm_axi_subdev_ioctl,
+	.interrupt_service_routine = msm_axi_subdev_isr_routine,
 };
 
 static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = {
@@ -4697,6 +4710,9 @@
 	struct axi_ctrl_t *axi_ctrl;
 	struct vfe32_ctrl_type *vfe32_ctrl;
 	struct vfe_share_ctrl_t *share_ctrl;
+	struct intr_table_entry irq_req;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 
 	share_ctrl = kzalloc(sizeof(struct vfe_share_ctrl_t), GFP_KERNEL);
@@ -4732,7 +4748,11 @@
 			 sizeof(axi_ctrl->subdev.name), "axi");
 	v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl);
 	axi_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&axi_ctrl->subdev, AXI_DEV, 0);
+
+	sd_info.sdev_type = AXI_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
 
 	v4l2_subdev_init(&vfe32_ctrl->subdev, &msm_vfe_subdev_ops);
 	vfe32_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
@@ -4765,23 +4785,49 @@
 		goto vfe32_no_resource;
 	}
 
-	rc = request_irq(axi_ctrl->vfeirq->start, vfe32_parse_irq,
-		IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
-	if (rc < 0) {
-		release_mem_region(axi_ctrl->vfemem->start,
-			resource_size(axi_ctrl->vfemem));
-		pr_err("%s: irq request fail\n", __func__);
-		rc = -EBUSY;
+	/* Request for this device irq from the camera server. If the
+	 * IRQ Router is present on this target, the interrupt will be
+	 * handled by the camera server and the interrupt service
+	 * routine called. If the request_irq call returns ENXIO, then
+	 * the IRQ Router hardware is not present on this target. We
+	 * have to request for the irq ourselves and register the
+	 * appropriate interrupt handler. */
+	irq_req.cam_hw_idx       = MSM_CAM_HW_VFE0;
+	irq_req.dev_name         = "vfe";
+	irq_req.irq_idx          = CAMERA_SS_IRQ_8;
+	irq_req.irq_num          = axi_ctrl->vfeirq->start;
+	irq_req.is_composite     = 0;
+	irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+	irq_req.num_hwcore       = 1;
+	irq_req.subdev_list[0]   = &axi_ctrl->subdev;
+	irq_req.data             = (void *)axi_ctrl;
+	rc = msm_cam_server_request_irq(&irq_req);
+	if (rc == -ENXIO) {
+		/* IRQ Router hardware is not present on this hardware.
+		 * Request for the IRQ and register the interrupt handler. */
+		rc = request_irq(axi_ctrl->vfeirq->start, vfe32_parse_irq,
+			IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
+		if (rc < 0) {
+			release_mem_region(axi_ctrl->vfemem->start,
+				resource_size(axi_ctrl->vfemem));
+			pr_err("%s: irq request fail\n", __func__);
+			rc = -EBUSY;
+			goto vfe32_no_resource;
+		}
+		disable_irq(axi_ctrl->vfeirq->start);
+	} else if (rc < 0) {
+		pr_err("%s Error registering irq ", __func__);
 		goto vfe32_no_resource;
 	}
 
-	disable_irq(axi_ctrl->vfeirq->start);
-
 	tasklet_init(&axi_ctrl->vfe32_tasklet,
 		axi32_do_tasklet, (unsigned long)axi_ctrl);
 
 	vfe32_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vfe32_ctrl->subdev, VFE_DEV, 0);
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = axi_ctrl->vfeirq->start;
+	msm_cam_register_subdev_node(&vfe32_ctrl->subdev, &sd_info);
 	return 0;
 
 vfe32_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 7369f6f..398621f 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -1795,6 +1795,8 @@
 
 static int __devinit vfe2x_probe(struct platform_device *pdev)
 {
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	vfe2x_ctrl = kzalloc(sizeof(struct vfe2x_ctrl_type), GFP_KERNEL);
 	if (!vfe2x_ctrl) {
@@ -1811,7 +1813,10 @@
 	platform_set_drvdata(pdev, &vfe2x_ctrl->subdev);
 
 	vfe2x_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, VFE_DEV, 0);
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, &sd_info);
 	return 0;
 }
 
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 54e9582..fb22cf9 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -970,6 +970,8 @@
 static int __devinit msm_vpe_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	D("%s: device id = %d\n", __func__, pdev->id);
 	vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
 	if (!vpe_ctrl) {
@@ -1028,7 +1030,10 @@
 
 	atomic_set(&vpe_ctrl->active, 0);
 	vpe_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vpe_ctrl->subdev, VPE_DEV, pdev->id);
+	sd_info.sdev_type = VPE_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = vpe_ctrl->vpeirq->start;
+	msm_cam_register_subdev_node(&vpe_ctrl->subdev, &sd_info);
 	vpe_ctrl->subdev.entity.revision = vpe_ctrl->subdev.devnode->num;
 	msm_queue_init(&vpe_ctrl->eventData_q, "ackevents");
 
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 65893c1..dfa7fbe 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1435,20 +1435,379 @@
 	}
 
 	return;
-}

-

-void msm_cam_release_subdev_node(struct video_device *vdev)

-{

-	struct v4l2_subdev *sd = video_get_drvdata(vdev);

-	sd->devnode = NULL;

-	kfree(vdev);

+}
+
+void msm_cam_release_subdev_node(struct video_device *vdev)
+{
+	struct v4l2_subdev *sd = video_get_drvdata(vdev);
+	sd->devnode = NULL;
+	kfree(vdev);
+}
+
+/* Helper function to get the irq_idx corresponding
+ * to the irq_num. */
+int get_irq_idx_from_irq_num(int irq_num)
+{
+	int i;
+	for (i = 0; i < CAMERA_SS_IRQ_MAX; i++)
+		if (irq_num == g_server_dev.hw_irqmap[i].irq_num)
+			return g_server_dev.hw_irqmap[i].irq_idx;
+
+	return -EINVAL;
+}
+
+static irqreturn_t msm_camera_server_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	int irq_idx, i, rc;
+	u32 status = 0;
+	struct intr_table_entry *ind_irq_tbl;
+	struct intr_table_entry *comp_irq_tbl;
+	bool subdev_handled = 0;
+
+	irq_idx = get_irq_idx_from_irq_num(irq_num);
+	if (irq_idx < 0) {
+		pr_err("server_parse_irq: no clients for irq #%d. returning ",
+			irq_num);
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+	ind_irq_tbl = &g_server_dev.irq_lkup_table.ind_intr_tbl[0];
+	comp_irq_tbl = &g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+	if (ind_irq_tbl[irq_idx].is_composite) {
+		for (i = 0; i < comp_irq_tbl[irq_idx].num_hwcore; i++) {
+			if (comp_irq_tbl[irq_idx].subdev_list[i]) {
+				rc = v4l2_subdev_call(
+					comp_irq_tbl[irq_idx].subdev_list[i],
+					core, interrupt_service_routine,
+					status, &subdev_handled);
+				if ((rc < 0) || !subdev_handled) {
+					pr_err("server_parse_irq:Error\n"
+						"handling irq %d rc = %d",
+						irq_num, rc);
+					/* Dispatch the irq to the remaining
+					 * subdevs in the list. */
+					continue;
+				}
+			}
+		}
+	} else {
+		rc = v4l2_subdev_call(ind_irq_tbl[irq_idx].subdev_list[0],
+			core, interrupt_service_routine,
+			status, &subdev_handled);
+		if ((rc < 0) || !subdev_handled) {
+			pr_err("server_parse_irq: Error handling irq %d rc = %d",
+				irq_num, rc);
+			spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+				flags);
+			return IRQ_HANDLED;
+		}
+	}
+	spin_unlock_irqrestore(&g_server_dev.intr_table_lock, flags);
+	return IRQ_HANDLED;
+}
+
+/* Helper function to get the irq_idx corresponding
+ * to the camera hwcore. This function should _only_
+ * be invoked when the IRQ Router is configured
+ * non-composite mode. */
+int get_irq_idx_from_camhw_idx(int cam_hw_idx)
+{
+	int i;
+	for (i = 0; i < MSM_CAM_HW_MAX; i++)
+		if (cam_hw_idx == g_server_dev.hw_irqmap[i].cam_hw_idx)
+			return g_server_dev.hw_irqmap[i].irq_idx;
+
+	return -EINVAL;
+}
+
+static inline void update_compirq_subdev_info(
+	struct intr_table_entry *irq_entry,
+	uint32_t cam_hw_mask, uint8_t cam_hw_id,
+	int *num_hwcore)
+{
+	if (cam_hw_mask & (0x1 << cam_hw_id)) {
+		/* If the mask has been set for this cam hwcore
+		 * update the subdev ptr......*/
+		irq_entry->subdev_list[cam_hw_id] =
+			g_server_dev.subdev_table[cam_hw_id];
+		(*num_hwcore)++;
+	} else {
+		/*....else, just clear it, so that the irq will
+		 * not be dispatched to this hw. */
+		irq_entry->subdev_list[cam_hw_id] = NULL;
+	}
+}
+
+static int msm_server_update_composite_irq_info(
+	struct intr_table_entry *irq_req)
+{
+	int num_hwcore = 0, rc = 0;
+	struct intr_table_entry *comp_irq_tbl =
+		&g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+
+	comp_irq_tbl[irq_req->irq_idx].is_composite = 1;
+	comp_irq_tbl[irq_req->irq_idx].irq_trigger_type =
+		irq_req->irq_trigger_type;
+	comp_irq_tbl[irq_req->irq_idx].num_hwcore = irq_req->num_hwcore;
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_MICRO, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CCI, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI0, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI1, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI2, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI3, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_ISPIF, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CPP, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_VFE0, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_VFE1, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_JPEG0, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_JPEG1, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_JPEG2, &num_hwcore);
+
+	if (num_hwcore != irq_req->num_hwcore) {
+		pr_warn("%s Mismatch!! requested cam hwcores: %d, Mask set %d",
+			__func__, irq_req->num_hwcore, num_hwcore);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_cam_server_request_irq(void *arg)
+{
+	unsigned long flags;
+	int rc = 0;
+	struct intr_table_entry *irq_req =  (struct intr_table_entry *)arg;
+	struct intr_table_entry *ind_irq_tbl =
+		&g_server_dev.irq_lkup_table.ind_intr_tbl[0];
+	struct intr_table_entry *comp_irq_tbl =
+		&g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+
+	if (!irq_req || !irq_req->irq_num || !irq_req->num_hwcore) {
+		pr_err("%s Invalid input ", __func__);
+		return -EINVAL;
+	}
+
+	if (!g_server_dev.irqr_device) {
+		/* This either means, the current target does not
+		 * have a IRQ Router hw or the IRQ Router device is
+		 * not probed yet. The latter should not happen.
+		 * In any case, just return back without updating
+		 * the interrupt lookup table. */
+		pr_info("%s IRQ Router hw is not present. ", __func__);
+		return -ENXIO;
+	}
+
+	if (irq_req->is_composite) {
+		if (irq_req->irq_idx >= CAMERA_SS_IRQ_0 &&
+				irq_req->irq_idx < CAMERA_SS_IRQ_MAX) {
+			spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+			/* Update the composite irq information into
+			 * the composite irq lookup table.... */
+			if (msm_server_update_composite_irq_info(irq_req)) {
+				pr_err("%s Invalid configuration", __func__);
+				spin_unlock_irqrestore(
+					&g_server_dev.intr_table_lock, flags);
+				return -EINVAL;
+			}
+			spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+				flags);
+			/*...and then update the corresponding entry
+			 * in the individual irq lookup table to indicate
+			 * that this IRQ is a composite irq and needs to be
+			 * sent to multiple subdevs. */
+			ind_irq_tbl[irq_req->irq_idx].is_composite = 1;
+			rc = request_irq(comp_irq_tbl[irq_req->irq_idx].irq_num,
+				msm_camera_server_parse_irq,
+				irq_req->irq_trigger_type,
+				ind_irq_tbl[irq_req->irq_idx].dev_name,
+				ind_irq_tbl[irq_req->irq_idx].data);
+			if (rc < 0) {
+				pr_err("%s: request_irq failed for %s\n",
+					__func__, irq_req->dev_name);
+				return -EBUSY;
+			}
+		} else {
+			pr_err("%s Invalid irq_idx %d ",
+				__func__, irq_req->irq_idx);
+			return -EINVAL;
+		}
+	} else {
+		if (irq_req->cam_hw_idx >= MSM_CAM_HW_MICRO &&
+				irq_req->cam_hw_idx < MSM_CAM_HW_MAX) {
+			/* Update the irq information into
+			 * the individual irq lookup table.... */
+			irq_req->irq_idx =
+				get_irq_idx_from_camhw_idx(irq_req->cam_hw_idx);
+			if (irq_req->cam_hw_idx < 0) {
+				pr_err("%s Invalid hw index %d ", __func__,
+					irq_req->cam_hw_idx);
+				return -EINVAL;
+			}
+			spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+			/* Make sure the composite irq is not configured for
+			 * this IRQ already. */
+			BUG_ON(ind_irq_tbl[irq_req->irq_idx].is_composite);
+
+			ind_irq_tbl[irq_req->irq_idx] = *irq_req;
+			/* irq_num is stored inside the server's hw_irqmap
+			 * during the device subdevice registration. */
+			ind_irq_tbl[irq_req->irq_idx].irq_num =
+			g_server_dev.hw_irqmap[irq_req->irq_idx].irq_num;
+
+			/*...and clear the corresponding entry in the
+			 * compsoite irq lookup table to indicate that this
+			 * IRQ will only be dispatched to single subdev. */
+			memset(&comp_irq_tbl[irq_req->irq_idx], 0,
+					sizeof(struct intr_table_entry));
+			D("%s Saving Entry %d %d %d %p",
+			__func__,
+			ind_irq_tbl[irq_req->cam_hw_idx].irq_num,
+			ind_irq_tbl[irq_req->cam_hw_idx].cam_hw_idx,
+			ind_irq_tbl[irq_req->cam_hw_idx].is_composite,
+			ind_irq_tbl[irq_req->cam_hw_idx].subdev_list[0]);
+
+			spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+				flags);
+
+			rc = request_irq(ind_irq_tbl[irq_req->irq_idx].irq_num,
+				msm_camera_server_parse_irq,
+				irq_req->irq_trigger_type,
+				ind_irq_tbl[irq_req->irq_idx].dev_name,
+				ind_irq_tbl[irq_req->irq_idx].data);
+			if (rc < 0) {
+				pr_err("%s: request_irq failed for %s\n",
+					__func__, irq_req->dev_name);
+				return -EBUSY;
+			}
+		} else {
+			pr_err("%s Invalid hw index %d ", __func__,
+				irq_req->cam_hw_idx);
+			return -EINVAL;
+		}
+	}
+	D("%s Successfully requested for IRQ for device %s ", __func__,
+		irq_req->dev_name);
+	return rc;
+}
+
+int msm_cam_server_update_irqmap(
+	struct msm_cam_server_irqmap_entry *irqmap_entry)
+{
+	if (!irqmap_entry || (irqmap_entry->irq_idx < CAMERA_SS_IRQ_0 ||
+		irqmap_entry->irq_idx >= CAMERA_SS_IRQ_MAX)) {
+		pr_err("%s Invalid irqmap entry ", __func__);
+		return -EINVAL;
+	}
+	g_server_dev.hw_irqmap[irqmap_entry->irq_idx] = *irqmap_entry;
+	return 0;
+}
+
+static int msm_cam_server_register_subdev(struct v4l2_device *v4l2_dev,
+	struct v4l2_subdev *sd)
+{
+	int rc = 0;
+	struct video_device *vdev;
+
+	if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) {
+		pr_err("%s Invalid input ", __func__);
+		return -EINVAL;
+	}
+
+	rc = v4l2_device_register_subdev(v4l2_dev, sd);
+	if (rc < 0) {
+		pr_err("%s v4l2 subdev register failed for %s ret = %d",
+			__func__, sd->name, rc);
+		return rc;
+	}
+
+	/* Register a device node for every subdev marked with the
+	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+	 */
+	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+		return rc;
+
+	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+	if (!vdev) {
+		pr_err("%s Not enough memory ", __func__);
+		rc = -ENOMEM;
+		goto clean_up;
+	}
+
+	video_set_drvdata(vdev, sd);
+	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+	vdev->v4l2_dev = v4l2_dev;
+	vdev->fops = &v4l2_subdev_fops;
+	vdev->release = msm_cam_release_subdev_node;
+	rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+						  sd->owner);
+	if (rc < 0) {
+		pr_err("%s Error registering video device %s", __func__,
+			sd->name);
+		kfree(vdev);
+		goto clean_up;
+	}
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	sd->entity.info.v4l.major = VIDEO_MAJOR;
+	sd->entity.info.v4l.minor = vdev->minor;
+#endif
+	sd->devnode = vdev;
+	return 0;
+
+clean_up:
+	if (sd->devnode)
+		video_unregister_device(sd->devnode);
+	return rc;
+}
+
+static int msm_cam_server_fill_sdev_irqnum(int cam_hw_idx,
+	int irq_num)
+{
+	int rc = 0, irq_idx;
+	irq_idx = get_irq_idx_from_camhw_idx(cam_hw_idx);
+	if (irq_idx < 0) {
+		pr_err("%s Invalid cam_hw_idx %d ", __func__, cam_hw_idx);
+		rc = -EINVAL;
+	} else {
+		g_server_dev.hw_irqmap[irq_idx].irq_num = irq_num;
+	}
+	return rc;
 }
 
 int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
-	enum msm_cam_subdev_type sdev_type, uint8_t index)
+	struct msm_cam_subdev_info *sd_info)
 {
-	struct video_device *vdev;
-	int err = 0;
+	int err = 0, cam_hw_idx;
+	uint8_t sdev_type, index;
+
+	sdev_type = sd_info->sdev_type;
+	index     = sd_info->sd_index;
 
 	switch (sdev_type) {
 	case CSIPHY_DEV:
@@ -1466,7 +1825,13 @@
 			err = -EINVAL;
 			break;
 		}
+		cam_hw_idx = MSM_CAM_HW_CSI0 + index;
 		g_server_dev.csid_device[index] = sd;
+		if (g_server_dev.irqr_device) {
+			g_server_dev.subdev_table[cam_hw_idx] = sd;
+			err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
+				sd_info->irq_num);
+		}
 		break;
 
 	case CSIC_DEV:
@@ -1480,6 +1845,11 @@
 
 	case ISPIF_DEV:
 		g_server_dev.ispif_device = sd;
+		if (g_server_dev.irqr_device) {
+			g_server_dev.subdev_table[cam_hw_idx] = sd;
+			err = msm_cam_server_fill_sdev_irqnum(MSM_CAM_HW_ISPIF,
+				sd_info->irq_num);
+		}
 		break;
 
 	case VFE_DEV:
@@ -1488,7 +1858,13 @@
 			err = -EINVAL;
 			break;
 		}
+		cam_hw_idx = MSM_CAM_HW_VFE0 + index;
 		g_server_dev.vfe_device[index] = sd;
+		if (g_server_dev.irqr_device) {
+			g_server_dev.subdev_table[cam_hw_idx] = sd;
+			err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
+				sd_info->irq_num);
+		}
 		break;
 
 	case VPE_DEV:
@@ -1512,6 +1888,9 @@
 	case GESTURE_DEV:
 		g_server_dev.gesture_device = sd;
 		break;
+	case IRQ_ROUTER_DEV:
+		g_server_dev.irqr_device = sd;
+		break;
 	default:
 		break;
 	}
@@ -1519,49 +1898,11 @@
 	if (err < 0)
 		return err;
 
-	err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
-	if (err < 0) {
-		pr_err("%s v4l2 subdev register failed for %d ret = %d",
-			__func__, sdev_type, err);
-		return err;
-	}
-
-	/* Register a device node for every subdev marked with the
-	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
-	 */
-	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
-		return err;
-
-	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);

-	if (!vdev) {

-		err = -ENOMEM;

-		goto clean_up;

-	}

-

-	video_set_drvdata(vdev, sd);

-	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
-	vdev->v4l2_dev = &g_server_dev.v4l2_dev;
-	vdev->fops = &v4l2_subdev_fops;
-	vdev->release = msm_cam_release_subdev_node;

-	err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
-						  sd->owner);
-	if (err < 0) {

-		kfree(vdev);

-		goto clean_up;

-	}

-#if defined(CONFIG_MEDIA_CONTROLLER)
-	sd->entity.info.v4l.major = VIDEO_MAJOR;

-	sd->entity.info.v4l.minor = vdev->minor;

-#endif
-	sd->devnode = vdev;

-	return 0;
-

-clean_up:

-	if (sd->devnode)

-		video_unregister_device(sd->devnode);

-	return err;

+	err = msm_cam_server_register_subdev(&g_server_dev.v4l2_dev, sd);
+	return err;
 }
 
+
 static int msm_setup_server_dev(struct platform_device *pdev)
 {
 	int rc = -ENODEV, i;
@@ -1604,6 +1945,9 @@
 
 	mutex_init(&g_server_dev.server_lock);
 	mutex_init(&g_server_dev.server_queue_lock);
+	spin_lock_init(&g_server_dev.intr_table_lock);
+	memset(&g_server_dev.irq_lkup_table, 0,
+			sizeof(struct irqmgr_intr_lkup_table));
 	g_server_dev.pcam_active = NULL;
 	g_server_dev.camera_info.num_cameras = 0;
 	atomic_set(&g_server_dev.number_pcam_active, 0);
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
index 677feaa..8a02d32 100644
--- a/drivers/media/video/msm/server/msm_cam_server.h
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -61,5 +61,7 @@
 	struct v4l2_event_subscription *sub);
 int msm_server_get_crop(struct msm_cam_v4l2_device *pcam,
 	int idx, struct v4l2_crop *crop);
-
+int msm_cam_server_request_irq(void *arg);
+int msm_cam_server_update_irqmap(
+	struct msm_cam_server_irqmap_entry *entry);
 #endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 1c646dd..6cd9e6b 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -28,6 +28,7 @@
 #include "msm_smem.h"
 
 #define BASE_DEVICE_NUMBER 32
+#define MAX_EVENTS 30
 
 struct msm_vidc_drv *vidc_driver;
 
@@ -215,21 +216,20 @@
 	int rc;
 	struct buffer_info *bi;
 	struct v4l2_buffer buffer_info;
+	struct v4l2_plane plane;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (b->count == 0) {
 		list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
 			bi = list_entry(ptr, struct buffer_info, list);
 			if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 				buffer_info.type = bi->type;
-				buffer_info.m.planes[0].reserved[0] =
-					bi->fd;
-				buffer_info.m.planes[0].reserved[1] =
-					bi->buff_off;
-				buffer_info.m.planes[0].length = bi->size;
-				buffer_info.m.planes[0].m.userptr =
-					bi->uvaddr;
+				plane.reserved[0] = bi->fd;
+				plane.reserved[1] = bi->buff_off;
+				plane.length = bi->size;
+				plane.m.userptr = bi->uvaddr;
+				buffer_info.m.planes = &plane;
 				buffer_info.length = 1;
-				pr_err("Releasing buffer: %d, %d, %d\n",
+				pr_info("Releasing buffer: %d, %d, %d\n",
 				buffer_info.m.planes[0].reserved[0],
 				buffer_info.m.planes[0].reserved[1],
 				buffer_info.m.planes[0].length);
@@ -359,9 +359,7 @@
 				struct v4l2_event_subscription *sub)
 {
 	int rc = 0;
-	if (sub->type == V4L2_EVENT_ALL)
-		sub->type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-	rc = v4l2_event_subscribe(fh, sub, 0);
+	rc = v4l2_event_subscribe(fh, sub, MAX_EVENTS);
 	return rc;
 }
 
@@ -445,7 +443,7 @@
 	INIT_LIST_HEAD(&core->instances);
 	mutex_init(&core->sync_lock);
 	spin_lock_init(&core->lock);
-	core->base_addr = 0x34f00000;
+	core->base_addr = 0x14f00000;
 	core->state = VIDC_CORE_UNINIT;
 	for (i = SYS_MSG_INDEX(SYS_MSG_START);
 		i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index ed99d35..ec93628 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -348,7 +348,7 @@
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
 		.name = "H.264 Loop Filter Mode",
-		.type = V4L2_CTRL_TYPE_INTEGER,
+		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
 		.maximum = L_MODE,
 		.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
@@ -375,7 +375,9 @@
 
 static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
 {
-	return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+	int sz = ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+	sz = (sz + 4095) & (~4095);
+	return sz;
 }
 
 static struct hal_quantization
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index a11f817..11fbcf4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -186,7 +186,7 @@
 void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
 				unsigned long size, int write)
 {
-	return NULL;
+	return (void *)0xdeadbeef;
 }
 
 void vidc_put_userptr(void *buf_priv)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 52f1dca..9b617aa 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -183,21 +183,9 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
-	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_OPEN_DONE;
-		v4l2_event_queue(vdev, &dqevent);
-		return;
 	} else {
 		pr_err("Failed to get valid response for session init\n");
 	}
@@ -207,24 +195,17 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
 	struct v4l2_event dqevent;
 	struct msm_vidc_cb_event *event_notify;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_EVENT_CHANGE;
+		dqevent.type = V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED;
+		dqevent.id = 0;
 		event_notify = (struct msm_vidc_cb_event *) response->data;
 		inst->reconfig_height = event_notify->height;
 		inst->reconfig_width = event_notify->width;
 		inst->in_reconfig = true;
-		v4l2_event_queue(vdev, &dqevent);
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 		return;
 	} else {
 		pr_err("Failed to get valid response for event_change\n");
@@ -262,20 +243,9 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
-	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_START_DONE;
-		v4l2_event_queue(vdev, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for start\n");
 	}
@@ -285,20 +255,9 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
-	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_STOP_DONE;
-		v4l2_event_queue(vdev, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for stop\n");
 	}
@@ -320,19 +279,12 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
 	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_FLUSH_DONE;
-		v4l2_event_queue(vdev, &dqevent);
+		dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+		dqevent.id = 0;
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for flush\n");
 	}
@@ -343,20 +295,13 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
 	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_CLOSE_DONE;
-		v4l2_event_queue(vdev, &dqevent);
+		dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+		dqevent.id = 0;
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for session close\n");
 	}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index fb1ab58..fb8fbc4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -75,11 +75,6 @@
 	MSM_VIDC_CORE_UNINIT,
 };
 
-enum vidc_resposes_id {
-	MSM_VIDC_DECODER_FLUSH_DONE = 0x11,
-	MSM_VIDC_DECODER_EVENT_CHANGE,
-};
-
 struct buf_info {
 	struct list_head list;
 	struct vb2_buffer *buf;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index c983389..a1561f0 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -3308,6 +3308,9 @@
 	int rc;
 	int vdd_safe;
 
+	/* forcing 19p2mhz before accessing any charger registers */
+	pm8921_chg_force_19p2mhz_clk(chip);
+
 	rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
 					BOOT_DONE_BIT, BOOT_DONE_BIT);
 	if (rc) {
@@ -3501,8 +3504,6 @@
 	/* Disable EOC FSM processing */
 	pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
 
-	pm8921_chg_force_19p2mhz_clk(chip);
-
 	rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
 						VREF_BATT_THERM_FORCE_ON);
 	if (rc)
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 90a3b1e..be8e6aa 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1546,7 +1546,8 @@
 {									\
 	if (size >= sizeof(buffer))					\
 		return -EINVAL;						\
-	strlcpy(buffer, strim((char *) buf), sizeof(buffer));		\
+	strlcpy(buffer, buf, sizeof(buffer));				\
+	strim(buffer);							\
 	return size;							\
 }									\
 static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 55d2b3e..cad6e02 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -914,6 +914,7 @@
 		goto error;
 	}
 
+	mutex_lock(&mgmt->mdp_do_hist_mutex);
 	mutex_lock(&mgmt->mdp_hist_mutex);
 	if (mgmt->mdp_is_hist_start == TRUE) {
 		pr_err("%s histogram already started\n", __func__);
@@ -933,6 +934,7 @@
 
 error_lock:
 	mutex_unlock(&mgmt->mdp_hist_mutex);
+	mutex_unlock(&mgmt->mdp_do_hist_mutex);
 error:
 	return ret;
 }
@@ -949,6 +951,7 @@
 		goto error;
 	}
 
+	mutex_lock(&mgmt->mdp_do_hist_mutex);
 	mutex_lock(&mgmt->mdp_hist_mutex);
 	if (mgmt->mdp_is_hist_start == FALSE) {
 		pr_err("%s histogram already stopped\n", __func__);
@@ -969,10 +972,12 @@
 
 	mutex_unlock(&mgmt->mdp_hist_mutex);
 	cancel_work_sync(&mgmt->mdp_histogram_worker);
+	mutex_unlock(&mgmt->mdp_do_hist_mutex);
 	return ret;
 
 error_lock:
 	mutex_unlock(&mgmt->mdp_hist_mutex);
+	mutex_unlock(&mgmt->mdp_do_hist_mutex);
 error:
 	return ret;
 }
@@ -1178,11 +1183,13 @@
 	return ret;
 }
 
+#define MDP_HISTOGRAM_TIMEOUT_MS	84 /*5 Frames*/
 static int mdp_do_histogram(struct fb_info *info,
 					struct mdp_histogram_data *hist)
 {
 	struct mdp_hist_mgmt *mgmt = NULL;
 	int ret = 0;
+	unsigned long timeout = (MDP_HISTOGRAM_TIMEOUT_MS * HZ) / 1000;
 
 	ret = mdp_histogram_block2mgmt(hist->block, &mgmt);
 	if (ret) {
@@ -1227,9 +1234,17 @@
 	mgmt->hist = hist;
 	mutex_unlock(&mgmt->mdp_hist_mutex);
 
-	if (wait_for_completion_killable(&mgmt->mdp_hist_comp)) {
-		pr_err("%s(): histogram bin collection killed", __func__);
-		ret = -EINVAL;
+	ret = wait_for_completion_killable_timeout(&mgmt->mdp_hist_comp,
+								timeout);
+	if (ret <= 0) {
+		if (!ret) {
+			mgmt->hist = NULL;
+			ret = -ETIMEDOUT;
+			pr_debug("%s: bin collection timedout", __func__);
+		} else {
+			mgmt->hist = NULL;
+			pr_debug("%s: bin collection interrupted", __func__);
+		}
 		goto error;
 	}
 
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 45430e8..a5171f0 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -590,6 +590,12 @@
 			__func__, dev_ctxt);
 		return false;
 	}
+	if (dev_ctxt->turbo_mode_set &&
+			(req_perf_lvl < RESTRK_1080P_TURBO_PERF_LEVEL)) {
+		VCDRES_MSG_MED("%s(): TURBO MODE!!\n", __func__);
+		return true;
+	}
+
 	VCDRES_MSG_LOW("%s(), req_perf_lvl = %d", __func__, req_perf_lvl);
 
 	if (resource_context.vidc_platform_data->disable_turbo
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 2b534f1..96e729d 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -759,6 +759,7 @@
 	client = dev_ctxt->cctxt_list_head;
 	dev_ctxt->cctxt_list_head = cctxt;
 	cctxt->next = client;
+	dev_ctxt->turbo_mode_set = 0;
 
 	*clnt_cctxt = cctxt;
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
index 80e03ba..33b2300 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
@@ -312,6 +312,7 @@
 		return false;
 	}
 	dev_ctxt->curr_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
+	vcd_update_decoder_perf_level(dev_ctxt, RESTRK_1080P_TURBO_PERF_LEVEL);
 #endif
 	return rc;
 }
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index f18fafd..63ebdea 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2295,11 +2295,11 @@
 #define V4L2_EVENT_FRAME_SYNC			4
 #define V4L2_EVENT_PRIVATE_START		0x08000000
 
-#define V4L2_EVENT_MSM_VIDC_START	{ V4L2_EVENT_PRIVATE_START + 0x00001000}
-#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE	{V4L2_EVENT_PRIVATE_START + 1}
+#define V4L2_EVENT_MSM_VIDC_START	(V4L2_EVENT_PRIVATE_START + 0x00001000)
+#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE	(V4L2_EVENT_PRIVATE_START + 1)
 #define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED	\
-		{V4L2_EVENT_PRIVATE_START + 2}
-#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE	{V4L2_EVENT_PRIVATE_START + 3}
+		(V4L2_EVENT_PRIVATE_START + 2)
+#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE	(V4L2_EVENT_PRIVATE_START + 3)
 
 /* Payload for V4L2_EVENT_VSYNC */
 struct v4l2_event_vsync {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 0c9b274..320ac8b 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1594,4 +1594,66 @@
 	uint32_t len;
 };
 
+enum msm_camss_irq_idx {
+	CAMERA_SS_IRQ_0,
+	CAMERA_SS_IRQ_1,
+	CAMERA_SS_IRQ_2,
+	CAMERA_SS_IRQ_3,
+	CAMERA_SS_IRQ_4,
+	CAMERA_SS_IRQ_5,
+	CAMERA_SS_IRQ_6,
+	CAMERA_SS_IRQ_7,
+	CAMERA_SS_IRQ_8,
+	CAMERA_SS_IRQ_9,
+	CAMERA_SS_IRQ_10,
+	CAMERA_SS_IRQ_11,
+	CAMERA_SS_IRQ_12,
+	CAMERA_SS_IRQ_MAX
+};
+
+enum msm_cam_hw_idx {
+	MSM_CAM_HW_MICRO,
+	MSM_CAM_HW_CCI,
+	MSM_CAM_HW_CSI0,
+	MSM_CAM_HW_CSI1,
+	MSM_CAM_HW_CSI2,
+	MSM_CAM_HW_CSI3,
+	MSM_CAM_HW_ISPIF,
+	MSM_CAM_HW_CPP,
+	MSM_CAM_HW_VFE0,
+	MSM_CAM_HW_VFE1,
+	MSM_CAM_HW_JPEG0,
+	MSM_CAM_HW_JPEG1,
+	MSM_CAM_HW_JPEG2,
+	MSM_CAM_HW_MAX
+};
+
+struct msm_camera_irq_cfg {
+	/* Bit mask of all the camera hardwares that needs to
+	 * be composited into a single IRQ to the MSM.
+	 * Current usage: (may be updated based on hw changes)
+	 * Bits 31:13 - Reserved.
+	 * Bits 12:0
+	 * 12 - MSM_CAM_HW_JPEG2
+	 * 11 - MSM_CAM_HW_JPEG1
+	 * 10 - MSM_CAM_HW_JPEG0
+	 *  9 - MSM_CAM_HW_VFE1
+	 *  8 - MSM_CAM_HW_VFE0
+	 *  7 - MSM_CAM_HW_CPP
+	 *  6 - MSM_CAM_HW_ISPIF
+	 *  5 - MSM_CAM_HW_CSI3
+	 *  4 - MSM_CAM_HW_CSI2
+	 *  3 - MSM_CAM_HW_CSI1
+	 *  2 - MSM_CAM_HW_CSI0
+	 *  1 - MSM_CAM_HW_CCI
+	 *  0 - MSM_CAM_HW_MICRO
+	 */
+	uint32_t cam_hw_mask;
+	uint8_t  irq_idx;
+	uint8_t  num_hwcore;
+};
+
+#define MSM_IRQROUTER_CFG_COMPIRQ \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, void __user *)
+
 #endif /* __LINUX_MSM_CAMERA_H */
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index a7fd38b..2da5c6a 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -18,6 +18,8 @@
 #include <linux/gpio.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/slimbus/slimbus.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -1417,6 +1419,19 @@
 	return 0;
 }
 
+static int msm_slimbus_1_startup(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL)
+		pm_runtime_get_sync(slim->dev.parent);
+
+	return 0;
+}
+
 static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
 {
 
@@ -1433,6 +1448,19 @@
 		rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
 }
 
+static void msm_slimbus_1_shutdown(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL) {
+		pm_runtime_mark_last_busy(slim->dev.parent);
+		pm_runtime_put(slim->dev.parent);
+	}
+}
+
 static struct snd_soc_ops msm_be_ops = {
 	.startup = msm_startup,
 	.hw_params = msm_hw_params,
@@ -1445,9 +1473,9 @@
 };
 
 static struct snd_soc_ops msm_slimbus_1_be_ops = {
-	.startup = msm_startup,
+	.startup = msm_slimbus_1_startup,
 	.hw_params = msm_slimbus_1_hw_params,
-	.shutdown = msm_shutdown,
+	.shutdown = msm_slimbus_1_shutdown,
 };
 
 static struct snd_soc_ops msm_slimbus_3_be_ops = {