Merge "msm: pm: Remove power management support for 7201a and 7x25" into msm-3.0
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index fb5cff7..11b1f73 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -321,6 +321,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5c01299..886a691 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -330,6 +330,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
@@ -342,12 +343,12 @@
 CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
-CONFIG_MSM_GEMINI=y
-CONFIG_S5K3L1YX=y
-CONFIG_IMX091=y
 CONFIG_MSM_EEPROM=y
 CONFIG_IMX074_EEPROM=y
 CONFIG_IMX091_EEPROM=y
+CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
+CONFIG_IMX091=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 0e18918..3df5000 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -251,6 +251,7 @@
 		.gpio      = 16,	/* GSBI5 I2C QUP SCL */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi5,
+			[GPIOMUX_ACTIVE] = &gsbi5,
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 8328501..0ece37c 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -79,6 +79,10 @@
 	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla2x-slim"),
 	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla-slim"),
 	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",          "0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",     "0-000d"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla top level"),
 };
 VREG_CONSUMERS(S3) = {
 	REGULATOR_SUPPLY("8018_s3",		NULL),
@@ -91,6 +95,14 @@
 	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla2x-slim"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla top level"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"0-000d"),
 };
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8018_s4",		NULL),
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index da9ce67..3b99e6c 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -51,6 +51,7 @@
 #include "pm.h"
 #include "acpuclock.h"
 #include "pm-boot.h"
+#include <mach/gpiomux.h>
 
 #ifdef CONFIG_ION_MSM
 #define MSM_ION_AUDIO_SIZE	0xAF000
@@ -295,6 +296,95 @@
 
 #define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
 
+/*
+ * MDM9x15 I2S.
+ */
+static struct wcd9xxx_pdata wcd9xxx_i2c_platform_data = {
+	.irq = MSM_GPIO_TO_INT(85),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_TABLA_IRQS,
+	.reset_gpio = 84,
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	}
+	},
+};
+
+static struct i2c_board_info wcd9xxx_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+};
+
+static struct i2c_registry msm9615_i2c_devices[] __initdata = {
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_9615_GSBI5_QUP_I2C_BUS_ID,
+		wcd9xxx_device_info,
+		ARRAY_SIZE(wcd9xxx_device_info),
+	},
+};
+/*
+ * MDM9x15 I2S.
+ */
+
 /* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
  * 4 micbiases are used to power various analog and digital
  * microphones operating at 1800 mV. Technically, all micbiases
@@ -700,6 +790,8 @@
 	&msm_stub_codec,
 	&msm_voice,
 	&msm_voip,
+	&msm_i2s_cpudai0,
+	&msm_i2s_cpudai1,
 	&msm_pcm_hostless,
 	&msm_cpudai_afe_01_rx,
 	&msm_cpudai_afe_01_tx,
@@ -728,8 +820,27 @@
 
 static void __init msm9615_i2c_init(void)
 {
+	u8 mach_mask = 0;
+	int i;
+	/* Mask is hardcoded to SURF (CDP).
+	 * works on MTP with same configuration.
+	 */
+	mach_mask = I2C_SURF;
+	if (machine_is_msm9615_cdp())
+		mach_mask = I2C_SURF;
+	else if (machine_is_msm9615_mtp())
+		mach_mask = I2C_FFA;
+	else
+		pr_err("unmatched machine ID in register_i2c_devices\n");
 	msm9615_device_qup_i2c_gsbi5.dev.platform_data =
 					&msm9615_i2c_qup_gsbi5_pdata;
+	for (i = 0; i < ARRAY_SIZE(msm9615_i2c_devices); ++i) {
+		if (msm9615_i2c_devices[i].machs & mach_mask) {
+			i2c_register_board_info(msm9615_i2c_devices[i].bus,
+						msm9615_i2c_devices[i].info,
+						msm9615_i2c_devices[i].len);
+			}
+	}
 }
 
 static void __init msm9615_reserve(void)
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 7dd003f..80656b3 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,34 @@
 #include <linux/mfd/pm8xxx/pm8018.h>
 #include <linux/regulator/gpio-regulator.h>
 
+/*
+ * MDM9x15 I2S.
+ */
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA  (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM  (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+	u8                     machs;
+	int                    bus;
+	struct i2c_board_info *info;
+	int                    len;
+};
+#endif
+/* Tabla slave address for I2C */
+#define TABLA_I2C_SLAVE_ADDR		0x0d
+#define TABLA_ANALOG_I2C_SLAVE_ADDR	0x77
+#define TABLA_DIGITAL1_I2C_SLAVE_ADDR	0x66
+#define TABLA_DIGITAL2_I2C_SLAVE_ADDR	0x55
+#define MSM_9615_GSBI5_QUP_I2C_BUS_ID 0
+/*
+ * MDM9x15 I2S.
+ */
+
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8018_GPIO_BASE		NR_GPIO_IRQS
 #define PM8018_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8018_GPIO_BASE)
@@ -36,7 +64,7 @@
 #define GPIO_VREG_ID_EXT_2P95V		0
 
 extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
-
+uint32_t msm9615_rpm_get_swfi_latency(void);
 int msm9615_init_gpiomux(void);
 void msm9615_init_mmc(void);
 void mdm9615_allocate_fb_region(void);
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index bfd9379..23df1cf 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -125,6 +125,11 @@
 	KEY_VOLUMEDOWN,
 };
 
+static const unsigned short keymap_8625_evt[] = {
+	KEY_VOLUMEDOWN,
+	KEY_VOLUMEUP,
+};
+
 static struct gpio_event_matrix_info kp_matrix_info_8625 = {
 	.info.func      = gpio_event_matrix_func,
 	.keymap         = keymap_8625,
@@ -853,7 +858,11 @@
 #endif
 
 	/* keypad */
-	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+	if (machine_is_msm8625_evt())
+		kp_matrix_info_8625.keymap = keymap_8625_evt;
+
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+			machine_is_msm8625_evt())
 		platform_device_register(&kp_pdev_8625);
 	else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
 		platform_device_register(&kp_pdev_sku3);
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 803550a..9ec618d 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -760,9 +760,9 @@
 static void msm7x27a_cfg_uart2dm_serial(void) { }
 #endif
 
-struct fmem_platform_data fmem_pdata;
+static struct fmem_platform_data fmem_pdata;
 
-struct platform_device fmem_device = {
+static struct platform_device fmem_device = {
 	.name = "fmem",
 	.id = 1,
 	.dev = { .platform_data = &fmem_pdata },
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index f565075..b74b285 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -31,6 +31,7 @@
 #include <linux/memblock.h>
 #include <linux/input/ft5x06_ts.h>
 #include <linux/msm_adc.h>
+#include <linux/fmem.h>
 #include <asm/mach/mmc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -382,6 +383,9 @@
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
 	.cached = 1,
 	.memory_type = MEMTYPE_EBI1,
+	.request_region = request_fmem_c_region,
+	.release_region = release_fmem_c_region,
+	.reusable = 1,
 };
 
 static struct platform_device android_pmem_adsp_device = {
@@ -618,6 +622,14 @@
 	},
 };
 
+static struct fmem_platform_data fmem_pdata;
+
+static struct platform_device fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &fmem_pdata },
+};
+
 static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
 	&android_pmem_device,
@@ -630,6 +642,7 @@
 	&asoc_msm_dai0,
 	&asoc_msm_dai1,
 	&msm_adc_device,
+	&fmem_device,
 };
 
 static struct platform_device *qrd7627a_devices[] __initdata = {
@@ -687,12 +700,44 @@
 	},
 };
 
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+		&android_pmem_adsp_pdata,
+		&android_pmem_audio_pdata,
+		&android_pmem_pdata,
+};
+#endif
+
 static void __init size_pmem_devices(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	unsigned int reusable_count = 0;
+
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 	android_pmem_pdata.size = pmem_mdp_size;
 	android_pmem_audio_pdata.size = pmem_audio_size;
+
+	fmem_pdata.size = 0;
+	fmem_pdata.align = PAGE_SIZE;
+
+	/* Find pmem devices that should use FMEM (reusable) memory.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+		struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+		if (!reusable_count && pdata->reusable)
+			fmem_pdata.size += pdata->size;
+
+		reusable_count += (pdata->reusable) ? 1 : 0;
+
+		if (pdata->reusable && reusable_count > 1) {
+			pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+				__func__, pdata->name);
+			pdata->reusable = 0;
+		}
+	}
+
 #endif
 }
 
@@ -704,9 +749,10 @@
 static void __init reserve_pmem_memory(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
-	reserve_memory_for(&android_pmem_adsp_pdata);
-	reserve_memory_for(&android_pmem_pdata);
-	reserve_memory_for(&android_pmem_audio_pdata);
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+		reserve_memory_for(pmem_pdata_array[i]);
+
 	msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
 #endif
 }
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 1fd9b4d..a950e46 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1655,6 +1655,10 @@
 			   "msm-dai-q6.1"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.1"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
 	CLK_LOOKUP("bit_clk",		spare_i2s_mic_bit_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index c084d29..8eb1580 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -62,6 +62,9 @@
 #define MSM_PMIC1_SSBI_CMD_PHYS	0x00500000
 #define MSM_PMIC_SSBI_SIZE	SZ_4K
 
+#define MSM_GPIO_I2C_CLK 16
+#define MSM_GPIO_I2C_SDA 17
+
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
 	.bark_time = 11000,
@@ -307,6 +310,19 @@
 		.end	= GSBI5_QUP_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
+	{
+		.name   = "i2c_clk",
+		.start     = MSM_GPIO_I2C_CLK,
+		.end       = MSM_GPIO_I2C_CLK,
+		.flags     = IORESOURCE_IO,
+	},
+	{
+		.name   = "i2c_sda",
+		.start     = MSM_GPIO_I2C_SDA,
+		.end       = MSM_GPIO_I2C_SDA,
+		.flags     = IORESOURCE_IO,
+
+	},
 };
 
 struct platform_device msm9615_device_qup_i2c_gsbi5 = {
@@ -472,6 +488,15 @@
 	.id	= -1,
 };
 
+struct platform_device msm_i2s_cpudai0 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_RX,
+};
+
+struct platform_device msm_i2s_cpudai1 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_TX,
+};
 struct platform_device msm_voip = {
 	.name	= "msm-voip-dsp",
 	.id	= -1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 31142c1..8f42ede 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -223,6 +223,8 @@
 extern struct platform_device msm_cpudai_incall_music_rx;
 extern struct platform_device msm_cpudai_incall_record_rx;
 extern struct platform_device msm_cpudai_incall_record_tx;
+extern struct platform_device msm_i2s_cpudai0;
+extern struct platform_device msm_i2s_cpudai1;
 
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 90d236b..ba5b8ac 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -653,7 +653,8 @@
 void msm_camio_camif_pad_reg_reset_2(void);
 
 void msm_camio_vfe_blk_reset(void);
-void msm_camio_vfe_blk_reset_2(int flag);
+void msm_camio_vfe_blk_reset_2(void);
+void msm_camio_vfe_blk_reset_3(void);
 
 int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *sinfo);
 void msm_camio_3d_disable(void);
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 8d99c1c..f8e187d 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -39,6 +39,7 @@
 #include <linux/msm_charm.h>
 #include "msm_watchdog.h"
 #include "mdm_private.h"
+#include "sysmon.h"
 
 #define MDM_MODEM_TIMEOUT	6000
 #define MDM_MODEM_DELTA	100
@@ -47,6 +48,7 @@
 
 static int mdm_debug_on;
 static struct workqueue_struct *mdm_queue;
+static struct workqueue_struct *mdm_sfr_queue;
 
 #define EXTERNAL_MODEM "external_modem"
 
@@ -58,6 +60,36 @@
 
 static int first_boot = 1;
 
+#define RD_BUF_SIZE			100
+#define SFR_MAX_RETRIES		10
+#define SFR_RETRY_INTERVAL	1000
+
+static void mdm_restart_reason_fn(struct work_struct *work)
+{
+	int ret, ntries = 0;
+	char sfr_buf[RD_BUF_SIZE];
+
+	do {
+		msleep(SFR_RETRY_INTERVAL);
+		ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+					sfr_buf, sizeof(sfr_buf));
+		if (ret) {
+			/*
+			 * The sysmon device may not have been probed as yet
+			 * after the restart.
+			 */
+			pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
+					"%d/%d tries\n", __func__, ret,
+					ntries + 1,	SFR_MAX_RETRIES);
+		} else {
+			pr_err("mdm restart reason: %s\n", sfr_buf);
+			break;
+		}
+	} while (++ntries < SFR_MAX_RETRIES);
+}
+
+static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
+
 long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
 				unsigned long arg)
 {
@@ -253,8 +285,11 @@
 			msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
 		mdm_drv->mdm_boot_status = -ETIMEDOUT;
 		pr_info("%s: mdm modem restart timed out.\n", __func__);
-	} else
+	} else {
 		pr_info("%s: mdm modem has been restarted\n", __func__);
+		/* Log the reason for the restart */
+		queue_work(mdm_sfr_queue, &sfr_reason_work);
+	}
 	INIT_COMPLETION(mdm_boot);
 	return mdm_drv->mdm_boot_status;
 }
@@ -421,6 +456,16 @@
 		goto fatal_err;
 	}
 
+	mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+	if (!mdm_sfr_queue) {
+		pr_err("%s: could not create workqueue mdm_sfr_queue."
+			" All mdm functionality will be disabled\n",
+			__func__);
+		ret = -ENOMEM;
+		destroy_workqueue(mdm_queue);
+		goto fatal_err;
+	}
+
 	atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
 	mdm_debugfs_init();
 
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index ee78a31..6d8f2a2 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -455,30 +455,21 @@
 static void msm_pm_config_hw_before_power_down(void)
 {
 	if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
 		__raw_writel(4, APPS_SECOP);
-		mb();
 	} else if (cpu_is_msm7x27()) {
 		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
-		mb();
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
 	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
 		   cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
 		   cpu_is_msm7x25ab()) {
 		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
-		mb();
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
-	} else {
+	} else if (cpu_is_qsd8x50()) {
 		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
 		mb();
-		__raw_writel(1, APPS_PWRDOWN);
-		mb();
 		__raw_writel(0, APPS_STANDBY_CTL);
-		mb();
 	}
+	mb();
+	__raw_writel(1, APPS_PWRDOWN);
+	mb();
 }
 
 /*
@@ -559,13 +550,11 @@
 		__raw_writel(0, APPS_PWRDOWN);
 		mb();
 		msm_spm_reinit();
-	} else {
+	} else if (cpu_is_msm8625()) {
 		__raw_writel(0, APPS_PWRDOWN);
 		mb();
-		__raw_writel(0, APPS_CLK_SLEEP_EN);
-		mb();
 
-		if (cpu_is_msm8625() && power_collapsed) {
+		if (power_collapsed) {
 			/*
 			 * enable the SCU while coming out of power
 			 * collapse.
@@ -576,6 +565,11 @@
 			 */
 			configure_top_csr();
 		}
+	} else {
+		__raw_writel(0, APPS_PWRDOWN);
+		mb();
+		__raw_writel(0, APPS_CLK_SLEEP_EN);
+		mb();
 	}
 }
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index d811f71..b047cf4 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -218,7 +218,6 @@
 
 	/* 8064 IDs */
 	[109] = MSM_CPU_8064,
-	[130] = MSM_CPU_8064,
 
 	/* 8930 IDs */
 	[116] = MSM_CPU_8930,
@@ -247,14 +246,17 @@
 	[128] = MSM_CPU_8625,
 	[129] = MSM_CPU_8625,
 
-	/* 9625 IDs */
-	[130] = MSM_CPU_9625,
+	/* 8064 MPQ ID */
+	[130] = MSM_CPU_8064,
 
 	/* 7x25AB IDs */
 	[131] = MSM_CPU_7X25AB,
 	[132] = MSM_CPU_7X25AB,
 	[133] = MSM_CPU_7X25AB,
 
+	/* 9625 IDs */
+	[134] = MSM_CPU_9625,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
@@ -625,7 +627,7 @@
 		strlcpy(dummy_socinfo.build_id, "copper - ",
 			sizeof(dummy_socinfo.build_id));
 	} else if (early_machine_is_msm9625()) {
-		dummy_socinfo.id = 130;
+		dummy_socinfo.id = 134;
 		strlcpy(dummy_socinfo.build_id, "msm9625 - ",
 			sizeof(dummy_socinfo.build_id));
 	} else if (machine_is_msm8625_rumi3())
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 940af32..bbb13f3 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -996,19 +996,41 @@
 {
 	struct ion_client *client = s->private;
 	struct rb_node *n;
+	struct rb_node *n2;
 
-	seq_printf(s, "%16.16s: %16.16s : %16.16s : %16.16s\n", "heap_name",
-			"size_in_bytes", "handle refcount", "buffer");
+	seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
+			"heap_name", "size_in_bytes", "handle refcount",
+			"buffer", "physical", "[domain,partition] - virt");
+
 	mutex_lock(&client->lock);
 	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
 		struct ion_handle *handle = rb_entry(n, struct ion_handle,
 						     node);
+		enum ion_heap_type type = handle->buffer->heap->type;
 
-		seq_printf(s, "%16.16s: %16x : %16d : %16p\n",
+		seq_printf(s, "%16.16s: %16x : %16d : %12p",
 				handle->buffer->heap->name,
 				handle->buffer->size,
 				atomic_read(&handle->ref.refcount),
 				handle->buffer);
+
+		if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
+			type == ION_HEAP_TYPE_CARVEOUT ||
+			type == ION_HEAP_TYPE_CP)
+			seq_printf(s, " : %12lx", handle->buffer->priv_phys);
+		else
+			seq_printf(s, " : %12s", "N/A");
+
+		for (n2 = rb_first(&handle->buffer->iommu_maps); n2;
+				   n2 = rb_next(n2)) {
+			struct ion_iommu_map *imap =
+				rb_entry(n2, struct ion_iommu_map, node);
+			seq_printf(s, " : [%d,%d] - %8lx",
+					imap->domain_info[DI_DOMAIN_NUM],
+					imap->domain_info[DI_PARTITION_NUM],
+					imap->iova_addr);
+		}
+		seq_printf(s, "\n");
 	}
 
 	seq_printf(s, "%16.16s %d\n", "client refcount:",
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 2f83a40..c2d46e2 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -160,7 +160,7 @@
 				sizeof(struct kgsl_iommu_pt));
 		return NULL;
 	}
-	iommu_pt->domain = iommu_domain_alloc(0);
+	iommu_pt->domain = iommu_domain_alloc(MSM_IOMMU_DOMAIN_PT_CACHEABLE);
 	if (!iommu_pt->domain) {
 		KGSL_CORE_ERR("Failed to create iommu domain\n");
 		kfree(iommu_pt);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3238d33..701160c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -777,7 +777,7 @@
 			input_report_abs(input_dev, ABS_MT_POSITION_Y,
 					finger[id].y);
 			input_report_abs(input_dev, ABS_MT_PRESSURE,
-					finger[id].area);
+					 finger[id].pressure);
 		} else {
 			finger[id].status = 0;
 		}
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index ebfed6c..b60f99f 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -13,6 +13,7 @@
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   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) += io/ eeprom/ sensors/ actuators/ csi/
+  obj-$(CONFIG_MSM_CAMERA) += msm_gesture.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 6a5a647..2d7fefd 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -289,6 +289,8 @@
 			return rc;
 		}
 	}
+	if (csic_dev->hw_version == CSIC_7X)
+		msm_camio_vfe_blk_reset_3();
 
 #if DBG_CSIC
 	enable_irq(csic_dev->irq->start);
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 45761d5..946b985 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -85,27 +85,18 @@
 	clk_set_rate(clk, rate);
 }
 
-void msm_camio_vfe_blk_reset_2(int vfe_apps_reset)
+void msm_camio_vfe_blk_reset_2(void)
 {
 	uint32_t val;
 
-	if (apps_reset && !vfe_apps_reset)
-		return;
-
 	/* do apps reset */
 	val = readl_relaxed(appbase + 0x00000210);
-	if (apps_reset)
-		val |= 0x10A0001;
-	else
-		val |= 0x1;
+	val |= 0x1;
 	writel_relaxed(val, appbase + 0x00000210);
 	usleep_range(10000, 11000);
 
 	val = readl_relaxed(appbase + 0x00000210);
-	if (apps_reset)
-		val &= ~(0x10A0001);
-	else
-		val &= ~0x1;
+	val &= ~0x1;
 	writel_relaxed(val, appbase + 0x00000210);
 	usleep_range(10000, 11000);
 
@@ -122,6 +113,26 @@
 	usleep_range(10000, 11000);
 }
 
+void msm_camio_vfe_blk_reset_3(void)
+{
+	uint32_t val;
+
+	if (!apps_reset)
+		return;
+
+	/* do apps reset */
+	val = readl_relaxed(appbase + 0x00000210);
+	val |= 0x10A0000;
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+
+	val = readl_relaxed(appbase + 0x00000210);
+	val &= ~(0x10A0000);
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+	mb();
+}
+
 void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
 {
 	switch (perf_setting) {
diff --git a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
index a1270ea..9dc097b 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
@@ -156,6 +156,11 @@
 	return;
 }
 
+void msm_camio_vfe_blk_reset_3(void)
+{
+	return;
+}
+
 static void msm_camio_axi_cfg(enum msm_bus_perf_setting perf_setting)
 {
 	switch (perf_setting) {
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 1220b6e..034cbc5 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -45,6 +45,10 @@
 module_param(msm_camera_v4l2_nr, uint, 0644);
 MODULE_PARM_DESC(msm_camera_v4l2_nr, "videoX start number, -1 is autodetect");
 
+static long msm_server_send_v4l2_evt(void *evt);
+static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
+	unsigned int notification, void *arg);
+
 static void msm_queue_init(struct msm_device_queue *queue, const char *name)
 {
 	D("%s\n", __func__);
@@ -178,10 +182,16 @@
 		return -EINVAL;
 	}
 
+	D("%s qid %d evtid %d %d\n", __func__, command->queue_idx,
+		command->evt_id,
+		g_server_dev.server_queue[command->queue_idx].evt_id);
 	g_server_dev.server_queue[command->queue_idx].ctrl = command;
 	if (command->evt_id !=
 		g_server_dev.server_queue[command->queue_idx].evt_id) {
-		pr_err("Invalid event id from userspace\n");
+		pr_err("%s Invalid event id from userspace cmd id %d %d qid %d\n",
+			__func__, command->evt_id,
+			g_server_dev.server_queue[command->queue_idx].evt_id,
+			command->queue_idx);
 		return -EINVAL;
 	}
 
@@ -241,6 +251,8 @@
 	mutex_lock(&server_dev->server_queue_lock);
 	if (++server_dev->server_evt_id == 0)
 		server_dev->server_evt_id++;
+	D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+		server_dev->server_evt_id);
 
 	server_dev->server_queue[out->queue_idx].evt_id =
 		server_dev->server_evt_id;
@@ -317,7 +329,7 @@
 {
 	int rc = 0;
 	struct msm_ctrl_cmd ctrlcmd;
-	D("%s\n", __func__);
+	D("%s qid %d\n", __func__, pcam->server_queue_idx);
 	ctrlcmd.type	   = MSM_V4L2_OPEN;
 	ctrlcmd.timeout_ms = 10000;
 	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -337,7 +349,7 @@
 {
 	int rc = 0;
 	struct msm_ctrl_cmd ctrlcmd;
-	D("%s\n", __func__);
+	D("%s qid %d\n", __func__, pcam->server_queue_idx);
 	ctrlcmd.type	   = MSM_V4L2_CLOSE;
 	ctrlcmd.timeout_ms = 10000;
 	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -1432,7 +1444,7 @@
 			sub->type++;
 			D("sub->type while = 0x%x\n", sub->type);
 		} while (sub->type !=
-			V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MAX);
+			V4L2_EVENT_PRIVATE_START + MSM_SVR_RESP_MAX);
 	} else {
 		D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type);
 		rc = v4l2_event_subscribe(fh, sub);
@@ -1555,6 +1567,150 @@
 	msm_mctl_free(pcam);
 	return rc;
 }
+
+int msm_server_open_client(int *p_qidx)
+{
+	int rc = 0;
+	int server_q_idx = 0;
+	struct msm_cam_server_queue *queue = NULL;
+
+	mutex_lock(&g_server_dev.server_lock);
+	server_q_idx = msm_find_free_queue();
+	if (server_q_idx < 0) {
+		mutex_unlock(&g_server_dev.server_lock);
+		return server_q_idx;
+	}
+
+	*p_qidx = server_q_idx;
+	queue = &g_server_dev.server_queue[server_q_idx];
+	queue->ctrl = NULL;
+	queue->ctrl_data = kzalloc(sizeof(uint8_t) *
+		max_control_command_size, GFP_KERNEL);
+	msm_queue_init(&queue->ctrl_q, "control");
+	msm_queue_init(&queue->eventData_q, "eventdata");
+	queue->queue_active = 1;
+	mutex_unlock(&g_server_dev.server_lock);
+	return rc;
+}
+
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out,
+	int ctrl_id)
+{
+	int rc = 0;
+	void *value;
+	struct msm_queue_cmd *rcmd;
+	struct msm_queue_cmd *event_qcmd;
+	struct msm_ctrl_cmd *ctrlcmd;
+	struct msm_cam_server_dev *server_dev = &g_server_dev;
+	struct msm_device_queue *queue =
+		&server_dev->server_queue[out->queue_idx].ctrl_q;
+
+	struct v4l2_event v4l2_evt;
+	struct msm_isp_event_ctrl *isp_event;
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		return -ENOMEM;
+	}
+	event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!event_qcmd) {
+		pr_err("%s Insufficient memory. return", __func__);
+		kfree(isp_event);
+		return -ENOMEM;
+	}
+
+	D("%s\n", __func__);
+	mutex_lock(&server_dev->server_queue_lock);
+	if (++server_dev->server_evt_id == 0)
+		server_dev->server_evt_id++;
+
+	D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+		server_dev->server_evt_id);
+	server_dev->server_queue[out->queue_idx].evt_id =
+		server_dev->server_evt_id;
+	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + ctrl_id;
+	v4l2_evt.u.data[0] = out->queue_idx;
+	/* setup event object to transfer the command; */
+	isp_event->resptype = MSM_CAM_RESP_V4L2;
+	isp_event->isp_data.ctrl = *out;
+	isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+
+	atomic_set(&event_qcmd->on_heap, 1);
+	event_qcmd->command = isp_event;
+
+	msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
+				&event_qcmd->list_eventdata);
+
+	/* now send command to config thread in userspace,
+	 * and wait for results */
+	v4l2_event_queue(server_dev->server_command_queue.pvdev,
+					  &v4l2_evt);
+	D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+	mutex_unlock(&server_dev->server_queue_lock);
+
+	/* wait for config return status */
+	D("Waiting for config status\n");
+	rc = wait_event_interruptible_timeout(queue->wait,
+		!list_empty_careful(&queue->list),
+		msecs_to_jiffies(out->timeout_ms));
+	D("Waiting is over for config status\n");
+	if (list_empty_careful(&queue->list)) {
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			kfree(isp_event);
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			return rc;
+		}
+	}
+
+	rcmd = msm_dequeue(queue, list_control);
+	BUG_ON(!rcmd);
+	D("%s Finished servicing ioctl\n", __func__);
+
+	ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
+	value = out->value;
+	if (ctrlcmd->length > 0)
+		memcpy(value, ctrlcmd->value, ctrlcmd->length);
+
+	memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
+	out->value = value;
+
+	kfree(ctrlcmd);
+	server_dev->server_queue[out->queue_idx].ctrl = NULL;
+
+	free_qcmd(rcmd);
+	kfree(isp_event);
+	D("%s: rc %d\n", __func__, rc);
+	/* rc is the time elapsed. */
+	if (rc >= 0) {
+		/* TODO: Refactor msm_ctrl_cmd::status field */
+		if (out->status == 0)
+			rc = -1;
+		else if (out->status == 1 || out->status == 4)
+			rc = 0;
+		else
+			rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_server_close_client(int idx)
+{
+	int rc = 0;
+	struct msm_cam_server_queue *queue = NULL;
+	mutex_lock(&g_server_dev.server_lock);
+	queue = &g_server_dev.server_queue[idx];
+	queue->queue_active = 0;
+	kfree(queue->ctrl);
+	queue->ctrl = NULL;
+	kfree(queue->ctrl_data);
+	queue->ctrl_data = NULL;
+	msm_queue_drain(&queue->ctrl_q, list_control);
+	msm_drain_eventq(&queue->eventData_q);
+	mutex_unlock(&g_server_dev.server_lock);
+	return rc;
+}
 /* v4l2_file_operations */
 static int msm_open(struct file *f)
 {
@@ -1610,7 +1766,10 @@
 			pcam_inst->my_index,
 			pcam->vnode_id, pcam->use_count);
 	pcam->use_count++;
+	D("%s use_count %d\n", __func__, pcam->use_count);
 	if (pcam->use_count == 1) {
+		struct msm_cam_server_queue *queue;
+		int ges_evt = MSM_V4L2_GES_CAM_OPEN;
 		pcam->server_queue_idx = server_q_idx;
 		queue = &g_server_dev.server_queue[server_q_idx];
 		queue->ctrl = NULL;
@@ -1620,6 +1779,10 @@
 		msm_queue_init(&queue->eventData_q, "eventdata");
 		queue->queue_active = 1;
 
+		pr_err("%s send gesture evt\n", __func__);
+		msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_CAM_EVT, &ges_evt);
+
 		rc = msm_cam_server_open_session(&g_server_dev, pcam);
 		if (rc < 0) {
 			pr_err("%s: cam_server_open_session failed %d\n",
@@ -1713,6 +1876,74 @@
 	}
 	mutex_unlock(&pcam->vid_lock);
 	kfree(pcam_inst);
+	pr_err("%s: error end", __func__);
+	return rc;
+}
+
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
+
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		D("%s: invalid handle\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pmctl->mctl_release) {
+		rc = pmctl->mctl_release(pmctl);
+		if (rc < 0)
+			pr_err("mctl_release fails %d\n", rc);
+	}
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	kref_put(&pmctl->refcount, msm_release_ion_client);
+#endif
+
+	rc = msm_cam_server_close_session(&g_server_dev, pcam);
+	if (rc < 0)
+		pr_err("msm_cam_server_close_session fails %d\n", rc);
+
+	return rc;
+}
+
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+	int *p_active)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
+	D("%s: %p", __func__, g_server_dev.pcam_active);
+	*p_active = 0;
+	if (g_server_dev.pcam_active) {
+		D("%s: Active camera present return", __func__);
+		return 0;
+	}
+	rc = msm_cam_server_open_session(&g_server_dev, pcam);
+	if (rc < 0) {
+		pr_err("%s: cam_server_open_session failed %d\n",
+		__func__, rc);
+		return rc;
+	}
+
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	/* Should be set to sensor ops if any but right now its OK!! */
+	if (!pmctl->mctl_open) {
+		D("%s: media contoller is not inited\n",
+			 __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+
+	D("%s: call mctl_open\n", __func__);
+	rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
+
+	if (rc < 0) {
+		pr_err("%s: HW open failed rc = 0x%x\n",  __func__, rc);
+		return rc;
+	}
+	pmctl->pcam_ptr = pcam;
+	*p_active = 1;
 	return rc;
 }
 
@@ -1839,6 +2070,7 @@
 	f->private_data = NULL;
 
 	if (pcam->use_count == 0) {
+		int ges_evt = MSM_V4L2_GES_CAM_CLOSE;
 		if (g_server_dev.use_count > 0) {
 			rc = msm_send_close_server(pcam);
 			if (rc < 0)
@@ -1866,6 +2098,9 @@
 
 		if (g_server_dev.use_count == 0)
 			mutex_unlock(&g_server_dev.server_lock);
+
+		msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_CAM_EVT, &ges_evt);
 	}
 	mutex_unlock(&pcam->vid_lock);
 	return rc;
@@ -2080,6 +2315,11 @@
 		rc = 0;
 		break;
 	}
+
+	case MSM_CAM_IOCTL_SEND_EVENT:
+		rc = msm_server_send_v4l2_evt(arg);
+		break;
+
 	default:
 		pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
 		break;
@@ -2143,6 +2383,29 @@
 	return 0;
 }
 
+static long msm_server_send_v4l2_evt(void *evt)
+{
+	struct v4l2_event *v4l2_ev = (struct v4l2_event *)evt;
+	int rc = 0;
+
+	if (NULL == evt) {
+		pr_err("%s: evt is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	D("%s: evt type 0x%x\n", __func__, v4l2_ev->type);
+	if ((v4l2_ev->type >= MSM_GES_APP_EVT_MIN) &&
+		(v4l2_ev->type < MSM_GES_APP_EVT_MAX)) {
+		msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_EVT, v4l2_ev);
+	} else {
+		pr_err("%s: Invalid evt %d\n", __func__, v4l2_ev->type);
+		rc = -EINVAL;
+	}
+	D("%s: end\n", __func__);
+
+	return rc;
+}
 
 static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
 		unsigned int cmd, unsigned long evt)
@@ -2635,6 +2898,14 @@
 		rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
 			core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
 		break;
+	case NOTIFY_GESTURE_EVT:
+		rc = v4l2_subdev_call(g_server_dev.gesture_device,
+			core, ioctl, VIDIOC_MSM_GESTURE_EVT, arg);
+		break;
+	case NOTIFY_GESTURE_CAM_EVT:
+		rc = v4l2_subdev_call(g_server_dev.gesture_device,
+			core, ioctl, VIDIOC_MSM_GESTURE_CAM_EVT, arg);
+		break;
 	default:
 		break;
 	}
@@ -2674,6 +2945,8 @@
 		if (index >= MAX_NUM_AXI_DEV)
 			return -EINVAL;
 		g_server_dev.axi_device[index] = sd;
+	} else if (sdev_type == GESTURE_DEV) {
+		g_server_dev.gesture_device = sd;
 	}
 
 	err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 04e224c..6798cbb 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -32,6 +32,7 @@
 #include <mach/camera.h>
 #include <media/msm_isp.h>
 #include <linux/ion.h>
+#include <media/msm_gestures.h>
 
 #define MSM_V4L2_DIMENSION_SIZE 96
 #define MAX_DEV_NAME_LEN 50
@@ -69,6 +70,7 @@
 	SENSOR_DEV,
 	ACTUATOR_DEV,
 	EEPROM_DEV,
+	GESTURE_DEV,
 };
 
 /* msm queue management APIs*/
@@ -150,6 +152,8 @@
 	NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
 	NOTIFY_VFE_IRQ,
 	NOTIFY_AXI_IRQ,
+	NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
+	NOTIFY_GESTURE_CAM_EVT, /* arg = int */
 	NOTIFY_INVALID
 };
 
@@ -330,6 +334,8 @@
 	struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
 	struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
 	struct mutex dev_lock;
+	int active;
+	int use_count;
 };
 
 /* abstract camera device for each sensor successfully probed*/
@@ -384,7 +390,8 @@
 	struct msm_mem_map_info mem_map;
 };
 
-#define MAX_NUM_ACTIVE_CAMERA 2
+/* 2 for camera, 1 for gesture */
+#define MAX_NUM_ACTIVE_CAMERA 3
 
 struct msm_cam_server_queue {
 	uint32_t queue_active;
@@ -444,6 +451,7 @@
 	struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];
 	struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
 	struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
+	struct v4l2_subdev *gesture_device;
 };
 
 /* camera server related functions */
@@ -566,6 +574,12 @@
 uint32_t msm_camera_get_mctl_handle(void);
 struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle);
 void msm_camera_free_mctl(uint32_t handle);
+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);
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+	int *p_active);
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
 #endif /* __KERNEL__ */
 
 #endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
new file mode 100644
index 0000000..654594d
--- /dev/null
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -0,0 +1,497 @@
+/* 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 <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include <media/msm_camera.h>
+#include <media/msm_gestures.h>
+#include <media/v4l2-ctrls.h>
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_gesture: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+struct msm_gesture_ctrl {
+	int queue_id;
+	atomic_t active;
+	struct v4l2_ctrl_handler ctrl_handler;
+	int num_ctrls;
+	struct v4l2_fh *p_eventHandle;
+	struct v4l2_subdev *sd;
+	struct msm_ges_evt event;
+	int camera_opened;
+};
+
+static struct msm_gesture_ctrl g_gesture_ctrl;
+
+int msm_gesture_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	D("%s\n", __func__);
+	if (sub->type == V4L2_EVENT_ALL)
+		sub->type = MSM_GES_APP_NOTIFY_EVENT;
+	return v4l2_event_subscribe(fh, sub);
+}
+
+static int msm_gesture_send_ctrl(struct msm_gesture_ctrl *p_gesture_ctrl,
+	int type, void *value, int length, uint32_t timeout)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s qid %d\n", __func__, p_gesture_ctrl->queue_id);
+	ctrlcmd.type = type;
+	ctrlcmd.timeout_ms = timeout;
+	ctrlcmd.length = length;
+	ctrlcmd.value = value;
+	ctrlcmd.vnode_id = 0;
+	ctrlcmd.queue_idx = p_gesture_ctrl->queue_id;
+	ctrlcmd.config_ident = 0;
+
+	rc = msm_server_send_ctrl(&ctrlcmd, MSM_GES_RESP_V4L2);
+	return rc;
+}
+
+static int msm_gesture_proc_ctrl_cmd(struct msm_gesture_ctrl *p_gesture_ctrl,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd *tmp_cmd = NULL;
+	uint8_t *ctrl_data = NULL;
+	void __user *uptr_cmd;
+	void __user *uptr_value;
+	uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
+	uint32_t value_len;
+
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
+	uptr_cmd = (void __user *)ctrl->value;
+	uptr_value = (void __user *)tmp_cmd->value;
+	value_len = tmp_cmd->length;
+
+	D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+		__func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
+		(uint32_t)uptr_value, tmp_cmd->length);
+
+	ctrl_data = kzalloc(value_len + cmd_len, GFP_KERNEL);
+	if (ctrl_data == 0) {
+		pr_err("%s could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto end;
+	}
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
+	if (copy_from_user((void *)ctrl_data, uptr_cmd,
+			cmd_len)) {
+		pr_err("%s: copy_from_user failed.\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+	tmp_cmd->value = (void *)(ctrl_data + cmd_len);
+	if (uptr_value && tmp_cmd->length > 0) {
+		if (copy_from_user((void *)tmp_cmd->value, uptr_value,
+			value_len)) {
+			pr_err("%s: copy_from_user failed, size=%d\n",
+				__func__, value_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	} else
+		tmp_cmd->value = NULL;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_send_ctrl((struct msm_ctrl_cmd *)ctrl_data,
+			MSM_GES_RESP_V4L2);
+	D("%s: msm_server_control rc=%d\n", __func__, rc);
+	if (rc == 0) {
+		if (uptr_value && tmp_cmd->length > 0 &&
+			copy_to_user((void __user *)uptr_value,
+				(void *)(ctrl_data + cmd_len),
+				tmp_cmd->length)) {
+			pr_err("%s: copy_to_user failed, size=%d\n",
+				__func__, tmp_cmd->length);
+			rc = -EINVAL;
+			goto end;
+		}
+		tmp_cmd->value = uptr_value;
+		if (copy_to_user((void __user *)uptr_cmd,
+			(void *)tmp_cmd, cmd_len)) {
+			pr_err("%s: copy_to_user failed in cpy, size=%d\n",
+				__func__, cmd_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+end:
+	D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
+		__func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
+		tmp_cmd->length, tmp_cmd->status, rc);
+	kfree(ctrl_data);
+	return rc;
+}
+
+static int msm_gesture_s_ctrl(struct v4l2_subdev *sd,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s ctrl->id %d\n", __func__, ctrl->id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, ctrl);
+	if (rc != 0) {
+		pr_err("%s set ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_s_ctrl_ops(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct v4l2_control control;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	control.id = ctrl->id;
+	control.value = ctrl->val;
+	D("%s ctrl->id 0x%x\n", __func__, ctrl->id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+	if (rc != 0) {
+		pr_err("%s proc ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_s_ctrl_ext(struct v4l2_subdev *sd,
+	struct v4l2_ext_controls *ctrls)
+{
+	int rc = 0;
+	struct v4l2_control control;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	if ((ctrls->count < 1) || (NULL == ctrls->controls)) {
+		pr_err("%s invalid ctrl failed\n", __func__);
+		return -EINVAL;
+	}
+	control.id = ctrls->controls->id;
+	control.value = ctrls->controls->value;
+	D("%s ctrl->id %d\n", __func__, control.id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+	if (rc != 0) {
+		pr_err("%s proc ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_handle_event(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+	int rc = 0;
+	struct v4l2_event *evt = (struct v4l2_event *)arg;
+	struct msm_ges_evt *p_ges_evt = NULL;
+	D("%s: Received gesture evt 0x%x ", __func__, evt->type);
+	p_gesture_ctrl->event.evt_len = 0;
+	p_gesture_ctrl->event.evt_data = NULL;
+	if (0 != evt->u.data[0]) {
+		p_ges_evt = (struct msm_ges_evt *)evt->u.data;
+		D("%s: event data %p len %d", __func__,
+			p_ges_evt->evt_data,
+			p_ges_evt->evt_len);
+
+		if (p_ges_evt->evt_len > 0) {
+			p_gesture_ctrl->event.evt_data =
+				kzalloc(p_ges_evt->evt_len, GFP_KERNEL);
+
+			if (NULL == p_gesture_ctrl->event.evt_data) {
+				pr_err("%s: cannot allocate event", __func__);
+				rc = -ENOMEM;
+			} else {
+				if (copy_from_user(
+					(void *)p_gesture_ctrl->event.evt_data,
+					(void __user *)p_ges_evt->evt_data,
+					p_ges_evt->evt_len)) {
+					pr_err("%s: copy_from_user failed",
+							__func__);
+					rc = -EFAULT;
+				} else {
+					D("%s: copied the event", __func__);
+					p_gesture_ctrl->event.evt_len =
+						p_ges_evt->evt_len;
+				}
+			}
+		}
+	}
+
+	if (rc == 0) {
+		ktime_get_ts(&evt->timestamp);
+		v4l2_event_queue(&sd->devnode, evt);
+	}
+	D("%s: exit rc %d ", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_get_evt_payload(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+	int rc = 0;
+	struct msm_ges_evt *p_ges_evt = (struct msm_ges_evt *)arg;
+	D("%s: enter ", __func__);
+	if (NULL != p_gesture_ctrl->event.evt_data) {
+		D("%s: event data %p len %d", __func__,
+			p_gesture_ctrl->event.evt_data,
+			p_gesture_ctrl->event.evt_len);
+
+		if (copy_to_user((void __user *)p_ges_evt->evt_data,
+			p_gesture_ctrl->event.evt_data,
+			p_gesture_ctrl->event.evt_len)) {
+			pr_err("%s: copy_to_user failed.\n", __func__);
+			rc = -EFAULT;
+		} else {
+			D("%s: copied the event", __func__);
+			p_ges_evt->evt_len = p_gesture_ctrl->event.evt_len;
+		}
+	}
+	D("%s: exit rc %d ", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_handle_cam_event(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, int cam_evt)
+{
+	int rc = 0;
+	D("%s: cam_evt %d ", __func__, cam_evt);
+
+	if ((cam_evt != MSM_V4L2_GES_CAM_OPEN)
+		&& (cam_evt != MSM_V4L2_GES_CAM_CLOSE)) {
+		pr_err("%s: error invalid event %d ", __func__, cam_evt);
+		return -EINVAL;
+	}
+
+	p_gesture_ctrl->camera_opened =
+		(cam_evt == MSM_V4L2_GES_CAM_OPEN);
+
+	if (atomic_read(&p_gesture_ctrl->active) == 0) {
+		D("%s gesture not active\n", __func__);
+		return 0;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, cam_evt, NULL,
+		0, 2000);
+	if (rc != 0) {
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+	}
+	D("%s exit rc %d\n", __func__, rc);
+	return rc;
+}
+
+long msm_gesture_ioctl(struct v4l2_subdev *sd,
+	 unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	switch (cmd) {
+	case MSM_GES_IOCTL_CTRL_COMMAND: {
+		struct v4l2_control *ctrl = (struct v4l2_control *)arg;
+		D("%s MSM_GES_IOCTL_CTRL_COMMAND arg %p size %d\n", __func__,
+			arg, sizeof(ctrl));
+		rc = msm_gesture_s_ctrl(sd, ctrl);
+		break;
+	}
+	case VIDIOC_MSM_GESTURE_EVT: {
+		rc = msm_gesture_handle_event(sd, p_gesture_ctrl, arg);
+		break;
+	}
+	case VIDIOC_MSM_GESTURE_CAM_EVT: {
+		int cam_evt = *((int *)arg);
+		rc = msm_gesture_handle_cam_event(sd, p_gesture_ctrl, cam_evt);
+		break;
+	}
+	case MSM_GES_GET_EVT_PAYLOAD: {
+		rc = msm_gesture_get_evt_payload(sd, p_gesture_ctrl, arg);
+		break;
+	}
+	default:
+		pr_err("%s: Invalid ioctl %d", __func__, cmd);
+		break;
+	}
+	D("%s exit rc %d\n", __func__, rc);
+	return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_gesture_ctrl_ops = {
+	.s_ctrl = msm_gesture_s_ctrl_ops,
+};
+
+static const struct v4l2_ctrl_config msm_gesture_ctrl_filter = {
+	.ops = &msm_gesture_ctrl_ops,
+	.id = MSM_GESTURE_CID_CTRL_CMD,
+	.name = "Gesture ctrl",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.flags = V4L2_CTRL_FLAG_SLIDER,
+	.max = 0x7fffffff,
+	.step = 1,
+	.min = 0x80000000,
+};
+
+static int msm_gesture_init_ctrl(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl)
+{
+	int rc = 0;
+	p_gesture_ctrl->num_ctrls = 1;
+	p_gesture_ctrl->ctrl_handler.error = 0;
+	v4l2_ctrl_handler_init(&p_gesture_ctrl->ctrl_handler,
+		p_gesture_ctrl->num_ctrls);
+	v4l2_ctrl_new_custom(&p_gesture_ctrl->ctrl_handler,
+		&msm_gesture_ctrl_filter, p_gesture_ctrl);
+	if (p_gesture_ctrl->ctrl_handler.error) {
+		int err = p_gesture_ctrl->ctrl_handler.error;
+		D("%s: error adding control %d", __func__, err);
+		p_gesture_ctrl->ctrl_handler.error = 0;
+	}
+	sd->ctrl_handler = &p_gesture_ctrl->ctrl_handler;
+	return rc;
+}
+
+static int msm_gesture_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0, rc_err = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	if (atomic_read(&p_gesture_ctrl->active) != 0) {
+		pr_err("%s already opened\n", __func__);
+		return -EINVAL;
+	}
+	memset(&p_gesture_ctrl->event, 0x0, sizeof(struct msm_ges_evt));
+	rc = msm_server_open_client(&p_gesture_ctrl->queue_id);
+	if (rc != 0) {
+		pr_err("%s open failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = msm_gesture_init_ctrl(sd, p_gesture_ctrl);
+	if (rc != 0) {
+		pr_err("%s init ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_OPEN, NULL,
+		0, 10000);
+	if (rc != 0) {
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	atomic_inc(&p_gesture_ctrl->active);
+
+	return rc;
+
+err:
+	rc_err = msm_server_close_client(p_gesture_ctrl->queue_id);
+	if (rc_err != 0)
+		pr_err("%s failed %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	if (atomic_read(&p_gesture_ctrl->active) == 0) {
+		pr_err("%s already closed\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_CLOSE, NULL,
+		0, 10000);
+	if (rc != 0)
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+
+	rc = msm_server_close_client(p_gesture_ctrl->queue_id);
+	if (rc != 0)
+		pr_err("%s failed %d\n", __func__, rc);
+
+	v4l2_ctrl_handler_free(&p_gesture_ctrl->ctrl_handler);
+	kfree(p_gesture_ctrl->event.evt_data);
+
+	atomic_dec(&p_gesture_ctrl->active);
+	g_gesture_ctrl.queue_id = -1;
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_gesture_core_ops = {
+	.s_ctrl = msm_gesture_s_ctrl,
+	.s_ext_ctrls = msm_gesture_s_ctrl_ext,
+	.ioctl = msm_gesture_ioctl,
+	.subscribe_event = msm_gesture_subscribe_event,
+};
+
+static struct v4l2_subdev_video_ops msm_gesture_video_ops;
+
+static struct v4l2_subdev_ops msm_gesture_subdev_ops = {
+	.core = &msm_gesture_core_ops,
+	.video  = &msm_gesture_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_gesture_internal_ops = {
+	.open = msm_gesture_open,
+	.close = msm_gesture_close,
+};
+
+static int msm_gesture_node_register(void)
+{
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	struct v4l2_subdev *gesture_subdev =
+		kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	D("%s\n", __func__);
+	if (!gesture_subdev) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	};
+
+	v4l2_subdev_init(gesture_subdev, &msm_gesture_subdev_ops);
+	gesture_subdev->internal_ops = &msm_gesture_internal_ops;
+	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(gesture_subdev->name,
+			 sizeof(gesture_subdev->name), "gesture");
+
+	media_entity_init(&gesture_subdev->entity, 0, NULL, 0);
+	gesture_subdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+	gesture_subdev->entity.group_id = GESTURE_DEV;
+	gesture_subdev->entity.name = gesture_subdev->name;
+
+	/* events */
+	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	gesture_subdev->nevents = MAX_GES_EVENTS;
+
+	msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+
+	gesture_subdev->entity.revision = gesture_subdev->devnode.num;
+
+	atomic_set(&p_gesture_ctrl->active, 0);
+	p_gesture_ctrl->queue_id = -1;
+	p_gesture_ctrl->event.evt_data = NULL;
+	p_gesture_ctrl->event.evt_len = 0;
+	return 0;
+}
+
+static int __init msm_gesture_init_module(void)
+{
+	return msm_gesture_node_register();
+}
+
+module_init(msm_gesture_init_module);
+MODULE_DESCRIPTION("MSM Gesture driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index e878063..e9eb68f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -923,7 +923,6 @@
 	struct msm_cam_v4l2_device *pcam  = NULL;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	struct msm_cam_media_controller *pmctl;
-	D("%s : E ", __func__);
 
 	if (f == NULL) {
 		pr_err("%s :: cannot open video driver data", __func__);
@@ -935,8 +934,8 @@
 		pr_err("%s NULL pointer passed in!\n", __func__);
 		return rc;
 	}
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 
+	D("%s : E use_count %d", __func__, pcam->mctl_node.use_count);
 	mutex_lock(&pcam->mctl_node.dev_lock);
 	for (i = 0; i < MSM_DEV_INST_MAX; i++) {
 		if (pcam->mctl_node.dev_inst[i] == NULL)
@@ -960,6 +959,21 @@
 
 	D("%s pcam_inst %p my_index = %d\n", __func__,
 		pcam_inst, pcam_inst->my_index);
+	rc = msm_cam_server_open_mctl_session(pcam,
+		&pcam->mctl_node.active);
+	if (rc < 0) {
+		pr_err("%s: mctl session open failed %d", __func__, rc);
+		mutex_unlock(&pcam->mctl_node.dev_lock);
+		return rc;
+	}
+
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		pr_err("%s mctl NULL!\n", __func__);
+		return rc;
+	}
+
+	D("%s active %d\n", __func__, pcam->mctl_node.active);
 	rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 					pcam->mctl_node.pvdev);
 	if (rc < 0) {
@@ -973,6 +987,7 @@
 	D("f->private_data = 0x%x, pcam = 0x%x\n",
 		(u32)f->private_data, (u32)pcam_inst);
 
+	pcam->mctl_node.use_count++;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
 	D("%s : X ", __func__);
 	return rc;
@@ -1030,6 +1045,17 @@
 
 	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 	mutex_lock(&pcam->mctl_node.dev_lock);
+	D("%s : active %d ", __func__, pcam->mctl_node.active);
+	if (pcam->mctl_node.active == 1) {
+		rc = msm_cam_server_close_mctl_session(pcam);
+		if (rc < 0) {
+			pr_err("%s: mctl session close failed %d",
+				__func__, rc);
+			mutex_unlock(&pcam->mctl_node.dev_lock);
+			return rc;
+		}
+		pmctl = NULL;
+	}
 	pcam_inst->streamon = 0;
 	pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] = NULL;
 	if (pcam_inst->vbqueue_initialized)
@@ -1040,10 +1066,14 @@
 	v4l2_fh_exit(&pcam_inst->eventHandle);
 
 	kfree(pcam_inst);
-	kref_put(&pmctl->refcount, msm_release_ion_client);
+	if (NULL != pmctl) {
+		D("%s : release ion client", __func__);
+		kref_put(&pmctl->refcount, msm_release_ion_client);
+	}
 	f->private_data = NULL;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
-	D("%s : X ", __func__);
+	pcam->mctl_node.use_count--;
+	D("%s : use_count %d X ", __func__, pcam->mctl_node.use_count);
 	return rc;
 }
 
@@ -1246,6 +1276,11 @@
 				pb->m.planes[i].data_offset;
 			pcam_inst->buf_offset[pb->index][i].addr_offset =
 				pb->m.planes[i].reserved[0];
+			pcam_inst->plane_info.plane[i].offset = 0;
+			D("%s, len %d user[%d] %p buf_len %d\n",
+				__func__, pb->length, i,
+				(void *)pb->m.planes[i].m.userptr,
+				pb->m.planes[i].length);
 		}
 	} else {
 		D("%s stored reserved info %d", __func__, pb->reserved);
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 5bc81a7..42d13a1 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -431,8 +431,8 @@
 	int pp_divert_type = 0, pp_type = 0;
 
 	msm_mctl_check_pp(p_mctl, image_mode, &pp_divert_type, &pp_type);
-	D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x",
-		__func__, pp_type, pp_divert_type, frame_id);
+	D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x image_mode %d",
+		__func__, pp_type, pp_divert_type, frame_id, image_mode);
 	if (pp_type || pp_divert_type)
 		rc = msm_mctl_do_pp_divert(p_mctl,
 		image_mode, fbuf, frame_id, pp_type);
@@ -440,9 +440,26 @@
 		idx = msm_mctl_img_mode_to_inst_index(
 				p_mctl, image_mode, 0);
 		if (idx < 0) {
-			pr_err("%s Invalid instance, dropping buffer\n",
-				__func__);
-			return idx;
+			/* check mctl node */
+			if ((image_mode >= 0) &&
+				p_mctl->pcam_ptr->mctl_node.
+					dev_inst_map[image_mode]) {
+				int index = p_mctl->pcam_ptr->mctl_node.
+					   dev_inst_map[image_mode]->my_index;
+				pcam_inst = p_mctl->pcam_ptr->mctl_node.
+					dev_inst[index];
+				D("%s: Mctl node index %d inst %p",
+					__func__, index, pcam_inst);
+				rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
+					image_mode, fbuf,
+					&frame_id, 1);
+				D("%s mctl node buf done %d\n", __func__, 0);
+				return -EINVAL;
+			} else {
+			  pr_err("%s Invalid instance, dropping buffer\n",
+				  __func__);
+			  return idx;
+			}
 		}
 		pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
 		rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
@@ -573,6 +590,10 @@
 					plane_offset =
 					mem->offset.sp_off.cbcr_off;
 
+				D("%s: data off %d plane off %d",
+					__func__,
+					pcam_inst->buf_offset[buf_idx][i].
+					data_offset, plane_offset);
 				free_buf->ch_paddr[i] =	(uint32_t)
 				videobuf2_to_pmem_contig(&buf->vidbuf, i) +
 				pcam_inst->buf_offset[buf_idx][i].data_offset +
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index becdd95..3e8d3be 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -3056,7 +3056,7 @@
 		ch2_paddr = vfe32_get_ch_addr(ping_pong,
 			vfe32_ctrl->outpath.out1.ch2);
 
-		pr_debug("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+		CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
 			__func__, ch0_paddr, ch1_paddr, ch2_paddr);
 		if (free_buf) {
 			/* Y channel */
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index dd567d1..2d9d607 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -341,7 +341,6 @@
 static uint32_t extlen;
 
 struct mutex vfe_lock;
-static int apps_reset;
 static uint8_t vfestopped;
 
 static struct stop_event stopevent;
@@ -1216,8 +1215,7 @@
 		if (queue == QDSP_CMDQUEUE) {
 			switch (vfecmd.id) {
 			case VFE_CMD_RESET:
-				msm_camio_vfe_blk_reset_2(apps_reset);
-				apps_reset = 0;
+				msm_camio_vfe_blk_reset_2();
 				vfestopped = 0;
 				break;
 			case VFE_CMD_START:
@@ -1717,8 +1715,6 @@
 	CDBG("msm_cam_clk_enable: disable vfe_clk\n");
 	msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
 			vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
-	apps_reset = 1;
-
 	msm_adsp_disable(qcam_mod);
 	msm_adsp_disable(vfe_mod);
 
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index b7ae0f4..8cad387 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -191,7 +191,7 @@
 		}
 
 		vbuf->v4l2_buf.timestamp =
-			ns_to_timeval(frame_data->time_stamp);
+			ns_to_timeval(frame_data->time_stamp * NSEC_PER_USEC);
 
 		WFD_MSG_DBG("bytes used %d, ts: %d.%d, frame type is %d\n",
 				frame_data->data_len,
@@ -1051,6 +1051,7 @@
 	struct v4l2_fract *frate = arg;
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_frame_rate vcd_frame_rate;
+	struct vcd_property_vop_timing_constant_delta vcd_delta;
 	int rc;
 	vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
 	vcd_property_hdr.sz =
@@ -1060,8 +1061,25 @@
 	vcd_frame_rate.fps_numerator = frate->denominator;
 	rc = vcd_set_property(client_ctx->vcd_handle,
 					&vcd_property_hdr, &vcd_frame_rate);
-	if (rc)
+	if (rc) {
 		WFD_MSG_ERR("Failed to set frame rate, rc = %d\n", rc);
+		goto set_framerate_fail;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_VOP_TIMING_CONSTANT_DELTA;
+	vcd_property_hdr.sz = sizeof(vcd_delta);
+
+	vcd_delta.constant_delta = (frate->numerator * USEC_PER_SEC) /
+					frate->denominator;
+	rc = vcd_set_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_delta);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set frame delta, rc = %d", rc);
+		goto set_framerate_fail;
+	}
+
+set_framerate_fail:
 	return rc;
 }
 
@@ -1827,12 +1845,16 @@
 	struct venc_buf_info *venc_buf = arg;
 	struct mem_region *mregion = venc_buf->mregion;
 	struct vcd_frame_data vcd_input_buffer = {0};
+	int64_t ts = 0;
+
+	ts = venc_buf->timestamp;
+	do_div(ts, NSEC_PER_USEC);
 
 	vcd_input_buffer.virtual = mregion->kvaddr;
 	vcd_input_buffer.frm_clnt_data = (u32)mregion;
 	vcd_input_buffer.ip_frm_tag = (u32)mregion;
 	vcd_input_buffer.data_len = mregion->size;
-	vcd_input_buffer.time_stamp = venc_buf->timestamp;
+	vcd_input_buffer.time_stamp = ts;
 	vcd_input_buffer.offset = 0;
 
 	rc = vcd_encode_frame(client_ctx->vcd_handle,
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index deb35cc..737b726 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -958,6 +958,8 @@
 	case VIDIOC_G_ENC_INDEX:
 	case VIDIOC_ENCODER_CMD:
 	case VIDIOC_TRY_ENCODER_CMD:
+	case VIDIOC_DECODER_CMD:
+	case VIDIOC_TRY_DECODER_CMD:
 	case VIDIOC_DBG_S_REGISTER:
 	case VIDIOC_DBG_G_REGISTER:
 	case VIDIOC_DBG_G_CHIP_IDENT:
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5e44c90..d64ecb5 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -244,6 +244,8 @@
 	[_IOC_NR(VIDIOC_ENCODER_CMD)] 	   = "VIDIOC_ENCODER_CMD",
 	[_IOC_NR(VIDIOC_TRY_ENCODER_CMD)]  = "VIDIOC_TRY_ENCODER_CMD",
 
+	[_IOC_NR(VIDIOC_DECODER_CMD)]	   = "VIDIOC_DECODER_CMD",
+	[_IOC_NR(VIDIOC_TRY_DECODER_CMD)]  = "VIDIOC_TRY_DECODER_CMD",
 	[_IOC_NR(VIDIOC_DBG_S_REGISTER)]   = "VIDIOC_DBG_S_REGISTER",
 	[_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
 
@@ -1775,6 +1777,28 @@
 			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
 		break;
 	}
+	case VIDIOC_DECODER_CMD:
+	{
+		struct v4l2_decoder_cmd *p = arg;
+
+		if (!ops->vidioc_decoder_cmd)
+			break;
+		ret = ops->vidioc_decoder_cmd(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+		break;
+	}
+	case VIDIOC_TRY_DECODER_CMD:
+	{
+		struct v4l2_decoder_cmd *p = arg;
+
+		if (!ops->vidioc_try_decoder_cmd)
+			break;
+		ret = ops->vidioc_try_decoder_cmd(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+		break;
+	}
 	case VIDIOC_G_PARM:
 	{
 		struct v4l2_streamparm *p = arg;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 2a25089..76d38c1 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -41,7 +41,7 @@
 };
 
 struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_intf;
+static int wcd9xxx_intf = -1;
 
 static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		       int bytes, void *dest, bool interface_reg)
@@ -331,17 +331,35 @@
 	pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
 			idbyte_0, idbyte_1, idbyte_2, idbyte_3);
 
-	if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+	if (wcd9xxx->slim != NULL) {
+		if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+			if (TABLA_IS_1_X(wcd9xxx->version)) {
+				wcd9xxx_dev = tabla1x_devs;
+				wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+			} else {
+				wcd9xxx_dev = tabla_devs;
+				wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+			}
+		} else {
+			wcd9xxx_dev = sitar_devs;
+			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+		}
+	} else {
+		/* Need to add here check for Tabla.
+		 * For now the read of version takes
+		 * care of now only tabla.
+		 */
+		pr_debug("%s : Read codec version using I2C\n",	__func__);
 		if (TABLA_IS_1_X(wcd9xxx->version)) {
 			wcd9xxx_dev = tabla1x_devs;
 			wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
-		} else {
+		} else if (TABLA_IS_2_0(wcd9xxx->version)) {
 			wcd9xxx_dev = tabla_devs;
 			wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+		} else {
+			wcd9xxx_dev = sitar_devs;
+			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 		}
-	} else {
-		wcd9xxx_dev = sitar_devs;
-		wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 	}
 
 	ret = mfd_add_devices(wcd9xxx->dev, -1,
@@ -372,7 +390,8 @@
 	wake_lock_destroy(&wcd9xxx->wlock);
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
-	slim_remove_device(wcd9xxx->slim_slave);
+	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		slim_remove_device(wcd9xxx->slim_slave);
 	kfree(wcd9xxx);
 }
 
@@ -478,12 +497,11 @@
 };
 #endif
 
-static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx,
+				struct wcd9xxx_pdata *pdata)
 {
 	int ret;
 	int i;
-	struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
-
 	wcd9xxx->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
 				   ARRAY_SIZE(pdata->regulator),
 				   GFP_KERNEL);
@@ -695,6 +713,10 @@
 	int ret = 0;
 	static int device_id;
 
+	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		pr_info("tabla card is already detected in slimbus mode\n");
+		return -ENODEV;
+	}
 	if (device_id > 0) {
 		wcd9xxx_modules[device_id++].client = client;
 		pr_info("probe for other slaves devices of tabla\n");
@@ -721,8 +743,7 @@
 	dev_set_drvdata(&client->dev, wcd9xxx);
 	wcd9xxx->dev = &client->dev;
 	wcd9xxx->reset_gpio = pdata->reset_gpio;
-
-	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
 	if (ret) {
 		pr_err("%s: Fail to enable Codec supplies\n", __func__);
 		goto err_codec;
@@ -809,7 +830,7 @@
 	wcd9xxx->reset_gpio = pdata->reset_gpio;
 	wcd9xxx->dev = &slim->dev;
 
-	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
 	if (ret)
 		goto err_codec;
 	usleep_range(5, 5);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 925c032..15ddd83 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -228,16 +228,17 @@
 	complete(&mrq->completion);
 }
 
-static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
 	init_completion(&mrq->completion);
 	mrq->done = mmc_wait_done;
 	if (mmc_card_removed(host->card)) {
 		mrq->cmd->error = -ENOMEDIUM;
 		complete(&mrq->completion);
-		return;
+		return -ENOMEDIUM;
 	}
 	mmc_start_request(host, mrq);
+	return 0;
 }
 
 static void mmc_wait_for_req_done(struct mmc_host *host,
@@ -315,6 +316,7 @@
 {
 	int err = 0;
 	struct mmc_async_req *data = host->areq;
+	int start_err = 0;
 
 	/* Prepare a new request */
 	if (areq)
@@ -323,24 +325,23 @@
 	if (host->areq) {
 		mmc_wait_for_req_done(host, host->areq->mrq);
 		err = host->areq->err_check(host->card, host->areq);
-		if (err) {
-			mmc_post_req(host, host->areq->mrq, 0);
-			if (areq)
-				mmc_post_req(host, areq->mrq, -EINVAL);
-
-			host->areq = NULL;
-			goto out;
-		}
 	}
 
-	if (areq)
-		__mmc_start_req(host, areq->mrq);
+	if (!err && areq)
+		start_err = __mmc_start_req(host, areq->mrq);
 
 	if (host->areq)
 		mmc_post_req(host, host->areq->mrq, 0);
 
-	host->areq = areq;
- out:
+	/* Cancel a prepared request if it was not started. */
+	if ((err || start_err) && areq)
+			mmc_post_req(host, areq->mrq, -EINVAL);
+
+	if (err)
+		host->areq = NULL;
+	else
+		host->areq = areq;
+
 	if (error)
 		*error = err;
 	return data;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 25195b7..4967c4e 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1167,6 +1167,8 @@
 
 	if (data->flags & MMC_DATA_READ)
 		datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
+	else if (host->curr.use_wr_data_pend)
+		datactrl |= MCI_DATA_PEND;
 
 	clks = (unsigned long long)data->timeout_ns * host->clk_rate;
 	do_div(clks, 1000000000UL);
@@ -1642,13 +1644,11 @@
 				msmsdcc_request_end(host, cmd->mrq);
 			}
 		}
-	} else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
-		if (cmd->data->flags & MMC_DATA_READ)
-			msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
-		else
-			msmsdcc_request_start(host, host->curr.mrq);
 	} else if (cmd->data) {
-		if (!(cmd->data->flags & MMC_DATA_READ))
+		if (cmd == host->curr.mrq->sbc)
+			msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
+		else if ((cmd->data->flags & MMC_DATA_WRITE) &&
+			   !host->curr.use_wr_data_pend)
 			msmsdcc_start_data(host, cmd->data, NULL, 0);
 	}
 }
@@ -1924,12 +1924,17 @@
 static void
 msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
 {
-	if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
+	if (mrq->data) {
 		/* Queue/read data, daisy-chain command when data starts */
-		if (mrq->sbc)
-			msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
+		if ((mrq->data->flags & MMC_DATA_READ) ||
+		    host->curr.use_wr_data_pend)
+			msmsdcc_start_data(host, mrq->data,
+					   mrq->sbc ? mrq->sbc : mrq->cmd,
+					   0);
 		else
-			msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
+			msmsdcc_start_command(host,
+					      mrq->sbc ? mrq->sbc : mrq->cmd,
+					      0);
 	} else {
 		msmsdcc_start_command(host, mrq->cmd, 0);
 	}
@@ -2025,20 +2030,18 @@
 				host->sdcc_version) {
 			host->curr.wait_for_auto_prog_done = 1;
 		}
+		if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
+		    (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
+			host->curr.use_wr_data_pend = true;
 	}
 
 	if (mrq->data && mrq->sbc) {
 		mrq->sbc->mrq = mrq;
 		mrq->sbc->data = mrq->data;
-		if (mrq->data->flags & MMC_DATA_WRITE) {
+		if (mrq->data->flags & MMC_DATA_WRITE)
 			host->curr.wait_for_auto_prog_done = 1;
-			msmsdcc_start_command(host, mrq->sbc, 0);
-		} else {
-			msmsdcc_request_start(host, mrq);
-		}
-	} else {
-		msmsdcc_request_start(host, mrq);
 	}
+	msmsdcc_request_start(host, mrq);
 
 	spin_unlock_irqrestore(&host->lock, flags);
 }
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index e29ed91..78c12c1 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -78,6 +78,7 @@
 #define MCI_DPSM_DIRECTION	(1 << 1)
 #define MCI_DPSM_MODE		(1 << 2)
 #define MCI_DPSM_DMAENABLE	(1 << 3)
+#define MCI_DATA_PEND		(1 << 17)
 #define MCI_AUTO_PROG_DONE	(1 << 19)
 #define MCI_RX_DATA_PEND	(1 << 20)
 
@@ -294,6 +295,7 @@
 	int			got_dataend;
 	int			wait_for_auto_prog_done;
 	int			got_auto_prog_done;
+	bool			use_wr_data_pend;
 	int			user_pages;
 };
 
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dedf3da..e13b5c3 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1437,6 +1437,8 @@
 			dto -= 13;
 		else
 			dto = 0;
+		/* Use the maximum timeout value allowed in the standard of 14
+		   or 0xE */
 		if (dto > 14)
 			dto = 14;
 	}
diff --git a/drivers/video/msm/logo.c b/drivers/video/msm/logo.c
index c061e86..1b5d7c5 100644
--- a/drivers/video/msm/logo.c
+++ b/drivers/video/msm/logo.c
@@ -76,6 +76,12 @@
 
 	max = fb_width(info) * fb_height(info);
 	ptr = data;
+	if (info->node == 1 || info->node == 2) {
+		err = -EPERM;
+		pr_err("%s:%d no info->creen_base on fb%d!\n",
+		       __func__, __LINE__, info->node);
+		goto err_logo_free_data;
+	}
 	bits = (unsigned short *)(info->screen_base);
 	while (count > 3) {
 		unsigned n = ptr[0];
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b4d8db0..ce8744b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1179,18 +1179,26 @@
 	if (!remainder_mode2)
 		remainder_mode2 = PAGE_SIZE;
 
-	/* calculate smem_len based on max size of two supplied modes */
-	fix->smem_len = MAX((msm_fb_line_length(mfd->index, panel_info->xres,
-					      bpp) *
-			    panel_info->yres + PAGE_SIZE -
-				remainder) * mfd->fb_page,
-			    (msm_fb_line_length(mfd->index,
-					       panel_info->mode2_xres,
-					       bpp) *
-			    panel_info->mode2_yres + PAGE_SIZE -
-				remainder_mode2) * mfd->fb_page);
-
-
+	/*
+	 * calculate smem_len based on max size of two supplied modes.
+	 * Only fb0 has mem. fb1 and fb2 don't have mem.
+	 */
+	if (mfd->index == 0)
+		fix->smem_len = MAX((msm_fb_line_length(mfd->index,
+							panel_info->xres,
+							bpp) *
+				     panel_info->yres + PAGE_SIZE -
+				     remainder) * mfd->fb_page,
+				    (msm_fb_line_length(mfd->index,
+							panel_info->mode2_xres,
+							bpp) *
+				     panel_info->mode2_yres + PAGE_SIZE -
+				     remainder_mode2) * mfd->fb_page);
+	else if (mfd->index == 1 || mfd->index == 2) {
+		pr_debug("%s:%d no memory is allocated for fb%d!\n",
+			__func__, __LINE__, mfd->index);
+		fix->smem_len = 0;
+	}
 
 	mfd->var_xres = panel_info->xres;
 	mfd->var_yres = panel_info->yres;
@@ -1294,10 +1302,11 @@
 	fbram_phys += fbram_offset;
 	fbram_size -= fbram_offset;
 
-	if (fbram_size < fix->smem_len) {
-		printk(KERN_ERR "error: no more framebuffer memory!\n");
-		return -ENOMEM;
-	}
+	if (mfd->index == 0)
+		if (fbram_size < fix->smem_len) {
+			pr_err("error: no more framebuffer memory!\n");
+			return -ENOMEM;
+		}
 
 	fbi->screen_base = fbram;
 	fbi->fix.smem_start = (unsigned long)fbram_phys;
@@ -1311,8 +1320,8 @@
 			fbi->fix.smem_start, mfd->map_buffer->iova[0],
 			mfd->map_buffer->iova[1]);
 	}
-
-	memset(fbi->screen_base, 0x0, fix->smem_len);
+	if (mfd->index == 0)
+		memset(fbi->screen_base, 0x0, fix->smem_len);
 
 	mfd->op_enable = TRUE;
 	mfd->panel_power_on = FALSE;
@@ -1517,7 +1526,11 @@
 	}
 
 	if (!mfd->ref_cnt) {
-		mdp_set_dma_pan_info(info, NULL, TRUE);
+		if ((info->node != 1) && (info->node != 2)) {
+			mdp_set_dma_pan_info(info, NULL, TRUE);
+		} else
+			pr_debug("%s:%d no mdp_set_dma_pan_info %d\n",
+				__func__, __LINE__, info->node);
 
 		if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
 			printk(KERN_ERR "msm_fb_open: can't turn on display!\n");
@@ -1565,6 +1578,15 @@
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct msm_fb_panel_data *pdata;
 
+	/*
+	 * If framebuffer is 1 or 2, io pen display is not allowed.
+	 */
+	if (info->node == 1 || info->node == 2) {
+		pr_err("%s: no pan display for fb%d!",
+		       __func__, info->node);
+		return -EPERM;
+	}
+
 	if (info->node != 0 || mfd->cont_splash_done)	/* primary */
 		if ((!mfd->op_enable) || (!mfd->panel_power_on))
 			return -EPERM;
@@ -1585,6 +1607,7 @@
 
 	/* "UPDT" */
 	if (var->reserved[0] == 0x54445055) {
+
 		dirty.xoffset = var->reserved[1] & 0xffff;
 		dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
 
@@ -1738,9 +1761,12 @@
 	if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
 		return -EINVAL;
 
-	if (info->fix.smem_len <
-		(var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8)))
-		return -EINVAL;
+	if ((info->node != 1) && (info->node != 2))
+		if (info->fix.smem_len <
+		    (var->xres_virtual*
+		     var->yres_virtual*
+		     (var->bits_per_pixel/8)))
+			return -EINVAL;
 
 	if ((var->xres == 0) || (var->yres == 0))
 		return -EINVAL;
@@ -2593,7 +2619,11 @@
 	struct mdp_blit_req_list req_list_header;
 
 	int count, i, req_list_count;
-
+	if (info->node == 1 || info->node == 2) {
+		pr_err("%s: no pan display for fb%d.",
+		       __func__, info->node);
+		return -EPERM;
+	}
 	/* Get the count size for the total BLIT request. */
 	if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
 		return -EFAULT;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 0d5ba9c..5019d31 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -502,7 +502,12 @@
 	}
 
 	rc = ddl_set_property(cctxt->ddl_handle, prop_hdr, prop_val);
-	VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+	if (rc) {
+		/* Some properties aren't known to ddl that we can handle */
+		if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+			VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+	}
+
 	switch (prop_hdr->prop_id) {
 	case VCD_I_META_BUFFER_MODE:
 		{
@@ -537,16 +542,30 @@
 			break;
 		}
 	case VCD_I_INTRA_PERIOD:
-	   {
-		  struct vcd_property_i_period *iperiod =
-			 (struct vcd_property_i_period *)prop_val;
-		  cctxt->bframe = iperiod->b_frames;
-		  break;
-	   }
+		{
+			struct vcd_property_i_period *iperiod =
+				(struct vcd_property_i_period *)prop_val;
+			cctxt->bframe = iperiod->b_frames;
+			break;
+		}
 	case VCD_REQ_PERF_LEVEL:
 		rc = vcd_req_perf_level(cctxt,
-			(struct vcd_property_perf_level *)prop_val);
+				(struct vcd_property_perf_level *)prop_val);
 		break;
+	case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+		{
+			struct vcd_property_vop_timing_constant_delta *delta =
+				prop_val;
+
+			if (delta->constant_delta > 0) {
+				cctxt->time_frame_delta = delta->constant_delta;
+				rc = VCD_S_SUCCESS;
+			} else {
+				VCD_MSG_ERROR("Frame delta must be positive");
+				rc = VCD_ERR_ILLEGAL_PARM;
+			}
+			break;
+		}
 	default:
 		{
 			break;
@@ -559,6 +578,7 @@
     (struct vcd_clnt_ctxt *cctxt,
      struct vcd_property_hdr *prop_hdr, void *prop_val)
 {
+	int rc;
 	VCD_MSG_LOW("vcd_get_property_cmn in %d:", cctxt->clnt_state.state);
 	VCD_MSG_LOW("property Id = %d", prop_hdr->prop_id);
 	if (!prop_hdr->sz || !prop_hdr->prop_id) {
@@ -566,7 +586,24 @@
 
 		return VCD_ERR_ILLEGAL_PARM;
 	}
-	return ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+	rc = ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+	if (rc) {
+		/* Some properties aren't known to ddl that we can handle */
+		if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+			VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+	}
+
+	switch (prop_hdr->prop_id) {
+	case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+	{
+		struct vcd_property_vop_timing_constant_delta *delta =
+			(struct vcd_property_vop_timing_constant_delta *)
+			prop_val;
+		delta->constant_delta = cctxt->time_frame_delta;
+		rc = VCD_S_SUCCESS;
+	}
+	}
+	return rc;
 }
 
 static u32 vcd_set_buffer_requirements_cmn
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index d228146..7ae4f45 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -191,6 +191,7 @@
 	u32 frm_p_units;
 	u32 reqd_perf_lvl;
 	u32 time_resoln;
+	u32 time_frame_delta;
 
 	struct vcd_buffer_pool in_buf_pool;
 	struct vcd_buffer_pool out_buf_pool;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 2df7144..6358a0e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -3052,13 +3052,15 @@
 	u32 frm_delta;
 	u64 temp, max = ~((u64)0);
 
-	if (frame->time_stamp >= cctxt->status.prev_ts)
+	if (cctxt->time_frame_delta)
+		temp = cctxt->time_frame_delta;
+	else if (frame->time_stamp >= cctxt->status.prev_ts)
 		temp = frame->time_stamp - cctxt->status.prev_ts;
 	else
 		temp = (max - cctxt->status.prev_ts) +
 			frame->time_stamp;
 
-	VCD_MSG_LOW("Curr_ts=%lld  Prev_ts=%lld Diff=%llu",
+	VCD_MSG_LOW("Curr_ts=%lld  Prev_ts=%lld Diff=%llu\n",
 			frame->time_stamp, cctxt->status.prev_ts, temp);
 
 	temp *= cctxt->time_resoln;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 131c856..eda60c0 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1860,6 +1860,54 @@
 	};
 };
 
+/* Decoder commands */
+#define V4L2_DEC_CMD_START       (0)
+#define V4L2_DEC_CMD_STOP        (1)
+#define V4L2_DEC_CMD_PAUSE       (2)
+#define V4L2_DEC_CMD_RESUME      (3)
+
+/* Flags for V4L2_DEC_CMD_START */
+#define V4L2_DEC_CMD_START_MUTE_AUDIO	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_PAUSE */
+#define V4L2_DEC_CMD_PAUSE_TO_BLACK	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_STOP */
+#define V4L2_DEC_CMD_STOP_TO_BLACK	(1 << 0)
+#define V4L2_DEC_CMD_STOP_IMMEDIATELY	(1 << 1)
+
+/* Play format requirements (returned by the driver): */
+
+/* The decoder has no special format requirements */
+#define V4L2_DEC_START_FMT_NONE		(0)
+/* The decoder requires full GOPs */
+#define V4L2_DEC_START_FMT_GOP		(1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct v4l2_decoder_cmd {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u64 pts;
+		} stop;
+
+		struct {
+			/* 0 or 1000 specifies normal speed,
+			   1 specifies forward single stepping,
+			   -1 specifies backward single stepping,
+			   >1: playback at speed/1000 of the normal speed,
+			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			__s32 speed;
+			__u32 format;
+		} start;
+
+		struct {
+			__u32 data[16];
+		} raw;
+	};
+};
 #endif
 
 
@@ -2226,6 +2274,15 @@
 #define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
 #define VIDIOC_PREPARE_BUF	_IOWR('V', 93, struct v4l2_buffer)
 
+/* Experimental selection API */
+#define VIDIOC_G_SELECTION	_IOWR('V', 94, struct v4l2_selection)
+#define VIDIOC_S_SELECTION	_IOWR('V', 95, struct v4l2_selection)
+
+/* Experimental, these two ioctls may change over the next couple of kernel
+   versions. */
+#define VIDIOC_DECODER_CMD	_IOWR('V', 96, struct v4l2_decoder_cmd)
+#define VIDIOC_TRY_DECODER_CMD	_IOWR('V', 97, struct v4l2_decoder_cmd)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 8dfb0fc..03951ce 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -4,4 +4,4 @@
 header-y += vcap_fmt.h
 header-y += msm_isp.h
 header-y += msm_gemini.h
-header-y += msm_v4l2_overlay.h
+header-y += msm_gestures.h
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 32a1759..c93b696 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -66,7 +66,7 @@
 	u32 alloc_len;
 	u32 data_len;
 	u32 offset;
-	s64 time_stamp;
+	s64 time_stamp; /* in usecs*/
 	u32 flags;
 	u32 frm_clnt_data;
 	struct vcd_property_dec_output_buffer dec_op_prop;
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index e776d41..cd00800 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -53,6 +53,7 @@
 #define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
 #define VCD_REQ_PERF_LEVEL (VCD_START_BASE + 0x26)
 #define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
+#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -300,6 +301,10 @@
 	u32   vop_time_resolution;
 };
 
+struct vcd_property_vop_timing_constant_delta {
+	u32 constant_delta; /*In usecs */
+};
+
 struct vcd_property_short_header {
 	u32             short_header;
 };
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 3f647dc..d4cf1d2 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1433,6 +1433,9 @@
 #define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t *)
 
+#define MSM_CAM_IOCTL_SEND_EVENT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
+
 struct msm_camera_v4l2_ioctl_t {
 	void __user *ioctl_ptr;
 };
diff --git a/include/media/msm_gestures.h b/include/media/msm_gestures.h
new file mode 100644
index 0000000..c9af034
--- /dev/null
+++ b/include/media/msm_gestures.h
@@ -0,0 +1,66 @@
+/* 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 __LINUX_MSM_GESTURES_H
+#define __LINUX_MSM_GESTURES_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <media/msm_camera.h>
+
+#define MSM_GES_IOCTL_CTRL_COMMAND \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 20, struct v4l2_control)
+
+#define VIDIOC_MSM_GESTURE_EVT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 21, struct v4l2_event)
+
+#define MSM_GES_GET_EVT_PAYLOAD \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 22, struct msm_ges_evt)
+
+#define VIDIOC_MSM_GESTURE_CAM_EVT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 23, int)
+
+#define MSM_GES_RESP_V4L2  MSM_CAM_RESP_MAX
+#define MSM_GES_RESP_MAX  (MSM_GES_RESP_V4L2 + 1)
+
+#define MSM_SVR_RESP_MAX  MSM_GES_RESP_MAX
+
+
+#define MSM_V4L2_GES_BASE                             100
+#define MSM_V4L2_GES_OPEN         (MSM_V4L2_GES_BASE + 0)
+#define MSM_V4L2_GES_CLOSE        (MSM_V4L2_GES_BASE + 1)
+#define MSM_V4L2_GES_CAM_OPEN     (MSM_V4L2_GES_BASE + 2)
+#define MSM_V4L2_GES_CAM_CLOSE    (MSM_V4L2_GES_BASE + 3)
+
+#define MSM_GES_APP_EVT_MIN     (V4L2_EVENT_PRIVATE_START + 0x14)
+#define MSM_GES_APP_NOTIFY_EVENT        (MSM_GES_APP_EVT_MIN + 0)
+#define MSM_GES_APP_NOTIFY_ERROR_EVENT  (MSM_GES_APP_EVT_MIN + 1)
+#define MSM_GES_APP_EVT_MAX             (MSM_GES_APP_EVT_MIN + 2)
+
+#define MSM_GESTURE_CID_CTRL_CMD V4L2_CID_BRIGHTNESS
+
+#define MAX_GES_EVENTS 25
+
+struct msm_ges_ctrl_cmd {
+	int type;
+	void *value;
+	int len;
+	int fd;
+	uint32_t cookie;
+};
+
+struct msm_ges_evt {
+	void *evt_data;
+	int evt_len;
+};
+
+#endif /*__LINUX_MSM_GESTURES_H*/
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 4d1c74a..46c13ba 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -207,6 +207,10 @@
 					struct v4l2_encoder_cmd *a);
 	int (*vidioc_try_encoder_cmd)  (struct file *file, void *fh,
 					struct v4l2_encoder_cmd *a);
+	int (*vidioc_decoder_cmd)      (struct file *file, void *fh,
+					struct v4l2_decoder_cmd *a);
+	int (*vidioc_try_decoder_cmd)  (struct file *file, void *fh,
+					struct v4l2_decoder_cmd *a);
 
 	/* Stream type-dependent parameter ioctls */
 	int (*vidioc_g_parm)           (struct file *file, void *fh,
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index f02a7ef..7060677 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -16,6 +16,7 @@
 #include <linux/mfd/pm8xxx/pm8018.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -26,6 +27,7 @@
 #include <mach/socinfo.h>
 #include "msm-pcm-routing.h"
 #include "../codecs/wcd9310.h"
+#include <mach/gpiomux.h>
 
 /* 9615 machine driver */
 
@@ -56,8 +58,189 @@
 #define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
-static u32 top_spk_pamp_gpio  = PM8018_GPIO_PM_TO_SYS(18);
-static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(19);
+/*
+ * Added for I2S
+ */
+#define GPIO_SPKR_I2S_MCLK	24
+#define GPIO_PRIM_I2S_SCK	20
+#define GPIO_PRIM_I2S_DOUT	23
+#define GPIO_PRIM_I2S_WS	21
+#define GPIO_PRIM_I2S_DIN	22
+#define GPIO_SEC_I2S_SCK	25
+#define GPIO_SEC_I2S_WS		26
+#define GPIO_SEC_I2S_DOUT	28
+#define GPIO_SEC_I2S_DIN	27
+
+static struct gpiomux_setting cdc_i2s_mclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_sclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_dout = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_ws = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_din = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm9615_audio_prim_i2s_codec_configs[] = {
+	{
+		.gpio = GPIO_SPKR_I2S_MCLK,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_mclk,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_SCK,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_sclk,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_DOUT,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_dout,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_WS,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_ws,
+		},
+	},
+	{
+		.gpio = GPIO_PRIM_I2S_DIN,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_din,
+		},
+	},
+};
+
+/* Physical address for LPA CSR
+ * LPA SIF mux registers. These are
+ * ioremap( ) for Virtual address.
+ */
+#define LPASS_CSR_BASE	0x28000000
+#define LPA_IF_BASE		0x28100000
+#define SIF_MUX_REG_BASE (LPASS_CSR_BASE + 0x00000000)
+#define LPA_IF_REG_BASE (LPA_IF_BASE + 0x00000000)
+#define LPASS_SIF_MUX_ADDR  (SIF_MUX_REG_BASE + 0x00004000)
+#define LPAIF_SPARE_ADDR (LPA_IF_REG_BASE + 0x00000070)
+/* SIF & SPARE MUX Values */
+#define MSM_SIF_FUNC_PCM              0
+#define MSM_SIF_FUNC_I2S_MIC        1
+#define MSM_SIF_FUNC_I2S_SPKR      2
+#define MSM_LPAIF_SPARE_DISABLE                 0x0
+#define MSM_LPAIF_SPARE_BOTH_ENABLE     0x3
+
+/* I2S INTF CTL */
+#define MSM_INTF_PRIM        0
+#define MSM_INTF_SECN        1
+#define MSM_INTF_BOTH       2
+
+/* I2S Dir CTL */
+#define MSM_DIR_RX         0
+#define MSM_DIR_TX         1
+#define MSM_DIR_BOTH   2
+#define MSM_DIR_MAX     3
+
+/* I2S HW Params */
+#define NO_OF_BITS_PER_SAMPLE  16
+#define I2S_MIC_SCLK_RATE 1536000
+static int msm9615_i2s_rx_ch = 1;
+static int msm9615_i2s_tx_ch = 1;
+static int msm9615_i2s_spk_control;
+/* SIF mux bit mask & shift */
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK                   0x30000
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT                      0x10
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK                       0x3
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT                       0x0
+
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK		0x3
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT		0x2
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK	0x3
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT		0x0
+
+static u32 spare_shadow;
+static u32 sif_shadow;
+
+
+struct msm_i2s_mux_ctl {
+	const u8 sifconfig;
+	const u8 spareconfig;
+};
+struct msm_clk {
+	struct clk *osr_clk;
+	struct clk *bit_clk;
+	int clk_enable;
+};
+struct msm_i2s_clk {
+	struct msm_clk rx_clk;
+	struct msm_clk tx_clk;
+};
+struct msm_i2s_ctl {
+	struct msm_i2s_clk prim_clk;
+	struct msm_i2s_clk sec_clk;
+	struct msm_i2s_mux_ctl mux_ctl[MSM_DIR_MAX];
+	u8 intf_status[MSM_INTF_BOTH][MSM_DIR_BOTH];
+	void *sif_virt_addr;
+	void *spare_virt_addr;
+};
+static struct msm_i2s_ctl msm9x15_i2s_ctl = {
+	{{NULL, NULL, 0}, {NULL, NULL, 0} }, /* prim_clk */
+	{{NULL, NULL, 0}, {NULL, NULL, 0} }, /* sec_clk */
+	/* mux_ctl */
+	{
+		/* Rx path only */
+		{ MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_DISABLE },
+		/* Tx path only */
+		{  MSM_SIF_FUNC_I2S_MIC, MSM_LPAIF_SPARE_DISABLE },
+		/* Rx + Tx path only */
+		{ MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_BOTH_ENABLE },
+	},
+	/* intf_status */
+	{
+		/* Prim I2S */
+		{0, 0},
+		/* Sec I2S */
+		{0, 0}
+	},
+	/* sif_virt_addr */
+	NULL,
+	/* spare_virt_addr */
+	NULL,
+};
+
+enum msm9x15_set_i2s_clk {
+	MSM_I2S_CLK_SET_FALSE,
+	MSM_I2S_CLK_SET_TRUE,
+	MSM_I2S_CLK_SET_RATE0,
+};
+/*
+ * Added for I2S
+ */
+
+static u32 top_spk_pamp_gpio  = PM8018_GPIO_PM_TO_SYS(3);
+static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
 static int mdm9615_spk_control;
 static int mdm9615_ext_bottom_spk_pamp;
 static int mdm9615_ext_top_spk_pamp;
@@ -318,16 +501,15 @@
 		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
 		if (clk_users != 1)
 			return 0;
+		if (IS_ERR(codec_clk)) {
 
-		if (codec_clk) {
-			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
-			clk_prepare_enable(codec_clk);
-			tabla_mclk_enable(codec, 1, dapm);
-		} else {
 			pr_err("%s: Error setting Tabla MCLK\n", __func__);
 			clk_users--;
 			return -EINVAL;
 		}
+		clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+		clk_prepare_enable(codec_clk);
+		tabla_mclk_enable(codec, 1, dapm);
 	} else {
 		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
 		if (clk_users == 0)
@@ -651,6 +833,20 @@
 	return tabla_cal;
 }
 
+static int msm9615_i2s_set_spk(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm9615_i2s_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm9615_i2s_spk_control = ucontrol->value.integer.value[0];
+	mdm9615_ext_control(codec);
+	return 1;
+}
+
 static int mdm9615_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
@@ -704,13 +900,567 @@
 								__func__);
 			goto end;
 		}
-
-
 	}
 end:
 	return ret;
 }
 
+static int msm9615_i2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm9615_i2s_rx_ch  = %d\n", __func__,
+		 msm9615_i2s_rx_ch);
+	ucontrol->value.integer.value[0] = msm9615_i2s_rx_ch - 1;
+	return 0;
+}
+
+static int msm9615_i2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	msm9615_i2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
+		 msm9615_i2s_rx_ch);
+	return 1;
+}
+
+static int msm9615_i2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm9615_i2s_tx_ch  = %d\n", __func__,
+		 msm9615_i2s_tx_ch);
+	ucontrol->value.integer.value[0] = msm9615_i2s_tx_ch - 1;
+	return 0;
+}
+
+static int msm9615_i2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	msm9615_i2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
+		 msm9615_i2s_tx_ch);
+	return 1;
+}
+
+static int msm9615_i2s_get_spk(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm9615_spk_control = %d", __func__, mdm9615_spk_control);
+	ucontrol->value.integer.value[0] = msm9615_i2s_spk_control;
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm9615_i2s_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], msm9615_i2s_get_spk,
+		     msm9615_i2s_set_spk),
+	SOC_ENUM_EXT("PRI_RX Channels", mdm9615_enum[1],
+		     msm9615_i2s_rx_ch_get, msm9615_i2s_rx_ch_put),
+	SOC_ENUM_EXT("PRI_TX Channels", mdm9615_enum[2],
+		     msm9615_i2s_tx_ch_get, msm9615_i2s_tx_ch_put),
+};
+
+static int msm9615_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	err = snd_soc_add_controls(codec, tabla_msm9615_i2s_controls,
+		ARRAY_SIZE(tabla_msm9615_i2s_controls));
+	if (err < 0) {
+		pr_err("returning loc 1 err = %d\n", err);
+		return err;
+	}
+
+	snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
+				  ARRAY_SIZE(mdm9615_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, common_audio_map,
+		ARRAY_SIZE(common_audio_map));
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL|
+			       SND_JACK_OC_HPHR), &hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	err = snd_soc_jack_new(codec, "Button Jack",
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+	err = tabla_hs_detect(codec, &mbhc_cfg);
+	return err;
+}
+
+static int msm9615_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					     struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm9615_i2s_rx_ch;
+
+	return 0;
+}
+
+static int msm9615_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					     struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+	rate->min = rate->max = 48000;
+
+	channels->min = channels->max = msm9615_i2s_tx_ch;
+
+	return 0;
+}
+
+static int mdm9615_i2s_free_gpios(u8 i2s_intf, u8 i2s_dir)
+{
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	if (i2s_intf == MSM_INTF_PRIM) {
+		if (i2s_dir == MSM_DIR_RX)
+			gpio_free(GPIO_PRIM_I2S_DOUT);
+		if (i2s_dir == MSM_DIR_TX)
+			gpio_free(GPIO_PRIM_I2S_DIN);
+		if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			gpio_free(GPIO_PRIM_I2S_SCK);
+			gpio_free(GPIO_PRIM_I2S_WS);
+		}
+	} else if (i2s_intf == MSM_INTF_SECN) {
+		if (i2s_dir == MSM_DIR_RX)
+			gpio_free(GPIO_SEC_I2S_DOUT);
+		if (i2s_dir == MSM_DIR_TX)
+			gpio_free(GPIO_SEC_I2S_DIN);
+		if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			gpio_free(GPIO_SEC_I2S_WS);
+			gpio_free(GPIO_SEC_I2S_SCK);
+		}
+	}
+	return 0;
+}
+
+int msm9615_i2s_intf_dir_sel(const char *cpu_dai_name,
+			     u8 *i2s_intf, u8 *i2s_dir)
+{
+	int ret = 0;
+	if (i2s_intf == NULL || i2s_dir == NULL || cpu_dai_name == NULL) {
+		ret = 1;
+		goto err;
+	}
+	if (!strncmp(cpu_dai_name, "msm-dai-q6.0", 12)) {
+		*i2s_intf = MSM_INTF_PRIM;
+		*i2s_dir = MSM_DIR_RX;
+	} else if (!strncmp(cpu_dai_name, "msm-dai-q6.1", 12)) {
+		*i2s_intf = MSM_INTF_PRIM;
+		*i2s_dir = MSM_DIR_TX;
+	} else if (!strncmp(cpu_dai_name, "msm-dai-q6.4", 12)) {
+		*i2s_intf = MSM_INTF_SECN;
+		*i2s_dir = MSM_DIR_RX;
+	} else if (!strncmp(cpu_dai_name, "msm-dai-q6.5", 12)) {
+		*i2s_intf = MSM_INTF_SECN;
+		*i2s_dir = MSM_DIR_TX;
+	} else {
+		pr_err("Error in I2S cpu dai name\n");
+		ret = 1;
+	}
+err:
+	return ret;
+}
+
+int msm9615_enable_i2s_gpio(u8 i2s_intf, u8 i2s_dir)
+{
+	u8 ret = 0;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	if (i2s_intf == MSM_INTF_PRIM) {
+		if (i2s_dir == MSM_DIR_TX) {
+			ret = gpio_request(GPIO_PRIM_I2S_DIN, "I2S_PRIM_DIN");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_DIN);
+				goto err;
+			}
+		} else if (i2s_dir == MSM_DIR_RX) {
+			ret = gpio_request(GPIO_PRIM_I2S_DOUT,
+					       "I2S_PRIM_DOUT");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_DOUT);
+				goto err;
+			}
+		} else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			   pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			ret = gpio_request(GPIO_PRIM_I2S_SCK, "I2S_PRIM_SCK");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_SCK);
+				goto err;
+			}
+			ret = gpio_request(GPIO_PRIM_I2S_WS, "I2S_PRIM_WS");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_PRIM_I2S_WS);
+				goto err;
+			}
+		}
+	} else if (i2s_intf == MSM_INTF_SECN) {
+		if (i2s_dir == MSM_DIR_RX) {
+			ret = gpio_request(GPIO_SEC_I2S_DOUT, "I2S_SEC_DOUT");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_DOUT);
+				goto err;
+			}
+		} else if (i2s_dir == MSM_DIR_TX) {
+			ret = gpio_request(GPIO_SEC_I2S_DIN, "I2S_SEC_DIN");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_DIN);
+				goto err;
+			}
+		} else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+			   pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+			ret = gpio_request(GPIO_SEC_I2S_SCK, "I2S_SEC_SCK");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_SCK);
+				goto err;
+			}
+			ret = gpio_request(GPIO_SEC_I2S_WS, "I2S_SEC_WS");
+			if (ret) {
+				pr_err("%s: Failed to request gpio %d\n",
+				       __func__, GPIO_SEC_I2S_WS);
+				goto err;
+			}
+		}
+	}
+err:
+	return ret;
+}
+
+static int msm9615_set_i2s_osr_bit_clk(struct snd_soc_dai *cpu_dai,
+				       u8 i2s_intf, u8 i2s_dir,
+				       enum msm9x15_set_i2s_clk enable)
+{
+
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	struct msm_i2s_clk *pclk = &pintf->prim_clk;
+	struct msm_clk *clk_ctl = &pclk->rx_clk;
+	u8 ret = 0;
+	pr_debug("Dev name %s Intf =%d, Dir = %d, Enable=%d\n",
+		cpu_dai->name, i2s_intf, i2s_dir, enable);
+	if (i2s_intf == MSM_INTF_PRIM)
+		pclk = &pintf->prim_clk;
+	else if (i2s_intf == MSM_INTF_SECN)
+		pclk = &pintf->sec_clk;
+
+	if (i2s_dir == MSM_DIR_TX)
+		clk_ctl = &pclk->tx_clk;
+	else if (i2s_dir == MSM_DIR_RX)
+		clk_ctl = &pclk->rx_clk;
+
+	if (enable == MSM_I2S_CLK_SET_TRUE ||
+	    enable == MSM_I2S_CLK_SET_RATE0) {
+		if (clk_ctl->clk_enable != 0) {
+			pr_info("%s: I2S Clk is already enabled"
+				"clk users %d\n", __func__,
+				clk_ctl->clk_enable);
+			ret = 0;
+			goto err;
+		}
+		clk_ctl->osr_clk = clk_get(cpu_dai->dev, "osr_clk");
+		if (IS_ERR(clk_ctl->osr_clk)) {
+			pr_err("%s: Fail to get OSR CLK\n", __func__);
+			ret = -EINVAL;
+			goto err;
+		}
+		ret = clk_prepare(clk_ctl->osr_clk);
+		if (ret != 0) {
+			pr_err("Unable to prepare i2s_spkr_osr_clk\n");
+			goto err;
+		}
+		clk_set_rate(clk_ctl->osr_clk, TABLA_EXT_CLK_RATE);
+		ret = clk_enable(clk_ctl->osr_clk);
+		if (ret != 0) {
+			pr_err("Fail to enable i2s_spkr_osr_clk\n");
+			clk_unprepare(clk_ctl->osr_clk);
+			goto err;
+		}
+		clk_ctl->bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+		if (IS_ERR(clk_ctl->bit_clk)) {
+			pr_err("Fail to get i2s_spkr_bit_clk\n");
+			clk_disable(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->osr_clk);
+			clk_put(clk_ctl->osr_clk);
+			ret = -EINVAL;
+			goto err;
+		}
+		ret = clk_prepare(clk_ctl->bit_clk);
+		if (ret != 0) {
+			clk_disable(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->osr_clk);
+			clk_put(clk_ctl->osr_clk);
+			pr_err("Fail to prepare i2s_spkr_osr_clk\n");
+			goto err;
+		}
+		if (enable == MSM_I2S_CLK_SET_RATE0)
+			clk_set_rate(clk_ctl->bit_clk, 0);
+		else
+			clk_set_rate(clk_ctl->bit_clk, 8);
+		ret = clk_enable(clk_ctl->bit_clk);
+		if (ret != 0) {
+			clk_disable(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->osr_clk);
+			clk_put(clk_ctl->osr_clk);
+			clk_unprepare(clk_ctl->bit_clk);
+			pr_err("Unable to enable i2s_spkr_osr_clk\n");
+			goto err;
+		}
+		clk_ctl->clk_enable++;
+	} else if (enable == MSM_I2S_CLK_SET_FALSE &&
+		   clk_ctl->clk_enable != 0) {
+		clk_disable(clk_ctl->osr_clk);
+		clk_disable(clk_ctl->bit_clk);
+		clk_unprepare(clk_ctl->osr_clk);
+		clk_unprepare(clk_ctl->bit_clk);
+		clk_put(clk_ctl->bit_clk);
+		clk_put(clk_ctl->osr_clk);
+		clk_ctl->bit_clk = NULL;
+		clk_ctl->osr_clk = NULL;
+		clk_ctl->clk_enable--;
+		ret = 0;
+	}
+err:
+	return ret;
+}
+
+void msm9615_config_i2s_sif_mux(u8 value)
+{
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	sif_shadow  = 0x00000;
+	sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
+		     (value << LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT);
+	iowrite32(sif_shadow, pintf->sif_virt_addr);
+	/* Dont read SIF register. Device crashes. */
+	pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
+}
+
+void msm9615_config_i2s_spare_mux(u8 value, u8 i2s_intf)
+{
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	if (i2s_intf == MSM_INTF_PRIM) {
+		/* Configure Primary SIF */
+	    spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK
+			   ) | (value << LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT);
+	}
+	if (i2s_intf == MSM_INTF_SECN) {
+		/*Secondary interface configuration*/
+	    spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK
+			   ) | (value << LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT);
+	}
+	iowrite32(spare_shadow, pintf->spare_virt_addr);
+	/* Dont read SPARE register. Device crashes. */
+	pr_debug("%s( ): SPARE Reg =0x%x\n", __func__, spare_shadow);
+}
+
+static int msm9615_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	int rate = params_rate(params);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	struct msm_i2s_clk *pclk = &pintf->prim_clk;
+	struct msm_clk *clk_ctl = &pclk->rx_clk;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int bit_clk_set = 0;
+	u8 i2s_intf, i2s_dir;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!msm9615_i2s_intf_dir_sel(cpu_dai->name,
+		    &i2s_intf, &i2s_dir)) {
+			bit_clk_set = TABLA_EXT_CLK_RATE /
+				      (rate * 2 * NO_OF_BITS_PER_SAMPLE);
+			 if (bit_clk_set != 8) {
+				if (i2s_intf == MSM_INTF_PRIM)
+					pclk = &pintf->prim_clk;
+				else if (i2s_intf == MSM_INTF_SECN)
+					pclk = &pintf->sec_clk;
+				clk_ctl = &pclk->rx_clk;
+				pr_debug("%s( ): New rate = %d",
+					__func__, bit_clk_set);
+				clk_set_rate(clk_ctl->bit_clk, bit_clk_set);
+			 }
+		}
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		bit_clk_set = I2S_MIC_SCLK_RATE / (rate * 2 *
+						NO_OF_BITS_PER_SAMPLE);
+		/* Not required to modify TX rate.
+		  * Speaker clock are looped back
+		  * to Mic.
+		  */
+	}
+	return 1;
+}
+
+static int msm9615_i2s_startup(struct snd_pcm_substream *substream)
+{
+	u8 ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	u8 i2s_intf, i2s_dir;
+	if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+		pr_debug("%s( ): cpu name = %s intf =%d dir = %d\n",
+			 __func__, cpu_dai->name, i2s_intf, i2s_dir);
+		pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+			 pintf->intf_status[i2s_intf][MSM_DIR_RX],
+			 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+		msm9615_enable_i2s_gpio(i2s_intf, i2s_dir);
+		if (i2s_dir == MSM_DIR_TX) {
+			if (pintf->intf_status[i2s_intf][MSM_DIR_RX] > 0) {
+				/* This means that Rx is enabled before */
+				ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+						    i2s_intf, i2s_dir,
+						    MSM_I2S_CLK_SET_RATE0);
+				if (ret != 0) {
+					pr_err("%s: Fail enable I2S clock\n",
+					       __func__);
+					return -EINVAL;
+				}
+				msm9615_config_i2s_sif_mux(
+				       pintf->mux_ctl[MSM_DIR_BOTH].sifconfig);
+				msm9615_config_i2s_spare_mux(
+				      pintf->mux_ctl[MSM_DIR_BOTH].spareconfig,
+				      i2s_intf);
+				ret = snd_soc_dai_set_fmt(cpu_dai,
+						       SND_SOC_DAIFMT_CBM_CFM);
+				if (ret < 0)
+					pr_err("set fmt cpu dai failed\n");
+					ret = snd_soc_dai_set_fmt(codec_dai,
+						       SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt codec dai failed\n");
+			} else if (pintf->intf_status[i2s_intf][i2s_dir] == 0) {
+				/* This means that Rx is
+				 * not enabled before.
+				 * only Tx will be used.
+				 */
+				ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+							i2s_intf, i2s_dir,
+							MSM_I2S_CLK_SET_TRUE);
+				if (ret != 0) {
+					pr_err("%s: Fail Tx I2S clock\n",
+					       __func__);
+					return -EINVAL;
+				}
+				msm9615_config_i2s_sif_mux(
+					pintf->mux_ctl[MSM_DIR_TX].sifconfig);
+				msm9615_config_i2s_spare_mux(
+					pintf->mux_ctl[MSM_DIR_TX].spareconfig,
+					i2s_intf);
+				ret = snd_soc_dai_set_fmt(cpu_dai,
+						       SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt cpu dai failed\n");
+					ret = snd_soc_dai_set_fmt(codec_dai,
+						       SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt codec dai failed\n");
+	}
+		} else if (i2s_dir == MSM_DIR_RX) {
+			if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0) {
+				pr_err("%s: Error shutdown Tx first\n",
+				       __func__);
+				return -EINVAL;
+			} else if (pintf->intf_status[i2s_intf][i2s_dir]
+				   == 0) {
+				ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+						i2s_intf, i2s_dir,
+						MSM_I2S_CLK_SET_TRUE);
+				if (ret != 0) {
+					pr_err("%s: Fail Rx I2S clock\n",
+						__func__);
+					return -EINVAL;
+				}
+				msm9615_config_i2s_sif_mux(
+					pintf->mux_ctl[MSM_DIR_RX].sifconfig);
+				msm9615_config_i2s_spare_mux(
+					pintf->mux_ctl[MSM_DIR_RX].spareconfig,
+					i2s_intf);
+				ret = snd_soc_dai_set_fmt(cpu_dai,
+						SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt cpu dai failed\n");
+				ret = snd_soc_dai_set_fmt(codec_dai,
+					SND_SOC_DAIFMT_CBS_CFS);
+				if (ret < 0)
+					pr_err("set fmt codec dai failed\n");
+			}
+		}
+		pintf->intf_status[i2s_intf][i2s_dir]++;
+	} else {
+		pr_err("%s: Err in i2s_intf_dir_sel\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("Exit %s() Enable status Rx =%d Tx = %d\n", __func__,
+		 pintf->intf_status[i2s_intf][MSM_DIR_RX],
+		 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+	return ret;
+}
+
+static void msm9615_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+	u8 i2s_intf = 0, i2s_dir = 0, ret = 0;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	pr_debug("%s( ): Enable status Rx =%d Tx = %d\n",
+		__func__, pintf->intf_status[i2s_intf][MSM_DIR_RX],
+		pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+	if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+		pr_debug("%s( ): intf =%d dir = %d\n", __func__,
+			 i2s_intf, i2s_dir);
+		if (i2s_dir == MSM_DIR_RX)
+			if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0)
+				pr_err("%s: Shutdown Tx First then by RX\n",
+				       __func__);
+		ret = msm9615_set_i2s_osr_bit_clk(cpu_dai, i2s_intf, i2s_dir,
+							MSM_I2S_CLK_SET_FALSE);
+		if (ret != 0)
+			pr_err("%s: Cannot disable I2S clock\n",
+			       __func__);
+		pintf->intf_status[i2s_intf][i2s_dir]--;
+		mdm9615_i2s_free_gpios(i2s_intf, i2s_dir);
+	}
+	pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+		 pintf->intf_status[i2s_intf][MSM_DIR_RX],
+		 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+}
+
+static struct snd_soc_ops msm9615_i2s_be_ops = {
+	.startup = msm9615_i2s_startup,
+	.shutdown = msm9615_i2s_shutdown,
+	.hw_params = msm9615_i2s_hw_params,
+};
+
 static int mdm9615_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -896,6 +1646,7 @@
 
 	return 0;
 }
+
 static int mdm9615_startup(struct snd_pcm_substream *substream)
 {
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
@@ -1107,8 +1858,37 @@
 
 };
 
-static struct snd_soc_dai_link mdm9615_dai_delta_tabla[] = {
-	/* Backend DAI Links */
+static struct snd_soc_dai_link mdm9615_dai_i2s_tabla[] = {
+	/* Backend I2S DAI Links */
+	{
+		.name = LPASS_BE_PRI_I2S_RX,
+		.stream_name = "Primary I2S Playback",
+		.cpu_dai_name = "msm-dai-q6.0",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
+		.init = &msm9615_i2s_audrx_init,
+		.be_hw_params_fixup = msm9615_i2s_rx_be_hw_params_fixup,
+		.ops = &msm9615_i2s_be_ops,
+	},
+	{
+		.name = LPASS_BE_PRI_I2S_TX,
+		.stream_name = "Primary I2S Capture",
+		.cpu_dai_name = "msm-dai-q6.1",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_i2s_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
+		.be_hw_params_fixup = msm9615_i2s_tx_be_hw_params_fixup,
+		.ops = &msm9615_i2s_be_ops,
+	},
+};
+
+static struct snd_soc_dai_link mdm9615_dai_slimbus_tabla[] = {
+	/* Backend SlimBus DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
 		.stream_name = "Slimbus Playback",
@@ -1136,14 +1916,17 @@
 	},
 };
 
-static struct snd_soc_dai_link mdm9615_dai[
+static struct snd_soc_dai_link mdm9615_i2s_dai[
 					 ARRAY_SIZE(mdm9615_dai_common) +
-					 ARRAY_SIZE(mdm9615_dai_delta_tabla)];
+					 ARRAY_SIZE(mdm9615_dai_i2s_tabla)];
+
+static struct snd_soc_dai_link mdm9615_slimbus_dai[
+					 ARRAY_SIZE(mdm9615_dai_common) +
+					 ARRAY_SIZE(mdm9615_dai_slimbus_tabla)];
+
 
 static struct snd_soc_card snd_soc_card_mdm9615 = {
 		.name		= "mdm9615-tabla-snd-card",
-		.dai_link	= mdm9615_dai,
-		.num_links	= ARRAY_SIZE(mdm9615_dai),
 };
 
 static struct platform_device *mdm9615_snd_device;
@@ -1199,6 +1982,11 @@
 	}
 }
 
+void  __init install_codec_i2s_gpio(void)
+{
+	msm_gpiomux_install(msm9615_audio_prim_i2s_codec_configs,
+			ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
+}
 static int __init mdm9615_audio_init(void)
 {
 	int ret;
@@ -1220,11 +2008,28 @@
 		kfree(mbhc_cfg.calibration);
 		return -ENOMEM;
 	}
-
-	memcpy(mdm9615_dai, mdm9615_dai_common, sizeof(mdm9615_dai_common));
-	memcpy(mdm9615_dai + ARRAY_SIZE(mdm9615_dai_common),
-		mdm9615_dai_delta_tabla, sizeof(mdm9615_dai_delta_tabla));
-
+	pr_err("%s: Interface Type = %d\n", __func__,
+			wcd9xxx_get_intf_type());
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		memcpy(mdm9615_slimbus_dai, mdm9615_dai_common,
+			sizeof(mdm9615_dai_common));
+		memcpy(mdm9615_slimbus_dai + ARRAY_SIZE(mdm9615_dai_common),
+		       mdm9615_dai_slimbus_tabla,
+		       sizeof(mdm9615_dai_slimbus_tabla));
+		snd_soc_card_mdm9615.dai_link = mdm9615_slimbus_dai;
+		snd_soc_card_mdm9615.num_links =
+				ARRAY_SIZE(mdm9615_slimbus_dai);
+	} else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+		install_codec_i2s_gpio();
+		memcpy(mdm9615_i2s_dai, mdm9615_dai_common,
+		       sizeof(mdm9615_dai_common));
+		memcpy(mdm9615_i2s_dai + ARRAY_SIZE(mdm9615_dai_common),
+		       mdm9615_dai_i2s_tabla,
+		       sizeof(mdm9615_dai_i2s_tabla));
+		snd_soc_card_mdm9615.dai_link = mdm9615_i2s_dai;
+		snd_soc_card_mdm9615.num_links =
+				ARRAY_SIZE(mdm9615_i2s_dai);
+	}
 	platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
 	ret = platform_device_add(mdm9615_snd_device);
 	if (ret) {
@@ -1232,13 +2037,15 @@
 		kfree(mbhc_cfg.calibration);
 		return ret;
 	}
-
 	if (mdm9615_configure_headset_mic_gpios()) {
 		pr_err("%s Fail to configure headset mic gpios\n", __func__);
 		mdm9615_headset_gpios_configured = 0;
 	} else
 		mdm9615_headset_gpios_configured = 1;
 
+	msm9x15_i2s_ctl.sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
+	msm9x15_i2s_ctl.spare_virt_addr = ioremap(LPAIF_SPARE_ADDR, 4);
+
 	return ret;
 
 }
@@ -1253,6 +2060,9 @@
 	mdm9615_free_headset_mic_gpios();
 	platform_device_unregister(mdm9615_snd_device);
 	kfree(mbhc_cfg.calibration);
+	iounmap(msm9x15_i2s_ctl.sif_virt_addr);
+	iounmap(msm9x15_i2s_ctl.spare_virt_addr);
+
 }
 module_exit(mdm9615_audio_exit);