Merge "video: msm: wfd: Set last encoded buffer in input thread" into msm-3.0
diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index 93dd7a7..a9ba672 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -4,3 +4,5 @@
         - info on SD and MMC device attributes
 mmc-dev-parts.txt
         - info on SD and MMC device partitions
+mmc-async-req.txt
+        - info on mmc asynchronous requests
diff --git a/Documentation/mmc/mmc-async-req.txt b/Documentation/mmc/mmc-async-req.txt
new file mode 100644
index 0000000..ae1907b
--- /dev/null
+++ b/Documentation/mmc/mmc-async-req.txt
@@ -0,0 +1,87 @@
+Rationale
+=========
+
+How significant is the cache maintenance overhead?
+It depends. Fast eMMC and multiple cache levels with speculative cache
+pre-fetch makes the cache overhead relatively significant. If the DMA
+preparations for the next request are done in parallel with the current
+transfer, the DMA preparation overhead would not affect the MMC performance.
+The intention of non-blocking (asynchronous) MMC requests is to minimize the
+time between when an MMC request ends and another MMC request begins.
+Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
+dma_unmap_sg are processing. Using non-blocking MMC requests makes it
+possible to prepare the caches for next job in parallel with an active
+MMC request.
+
+MMC block driver
+================
+
+The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
+The increase in throughput is proportional to the time it takes to
+prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
+a request and how fast the memory is. The faster the MMC/SD is the
+more significant the prepare request time becomes. Roughly the expected
+performance gain is 5% for large writes and 10% on large reads on a L2 cache
+platform. In power save mode, when clocks run on a lower frequency, the DMA
+preparation may cost even more. As long as these slower preparations are run
+in parallel with the transfer performance won't be affected.
+
+Details on measurements from IOZone and mmc_test
+================================================
+
+https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
+
+MMC core API extension
+======================
+
+There is one new public function mmc_start_req().
+It starts a new MMC command request for a host. The function isn't
+truly non-blocking. If there is an ongoing async request it waits
+for completion of that request and starts the new one and returns. It
+doesn't wait for the new request to complete. If there is no ongoing
+request it starts the new request and returns immediately.
+
+MMC host extensions
+===================
+
+There are two optional members in the mmc_host_ops -- pre_req() and
+post_req() -- that the host driver may implement in order to move work
+to before and after the actual mmc_host_ops.request() function is called.
+In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
+descriptor, and post_req() runs the dma_unmap_sg().
+
+Optimize for the first request
+==============================
+
+The first request in a series of requests can't be prepared in parallel
+with the previous transfer, since there is no previous request.
+The argument is_first_req in pre_req() indicates that there is no previous
+request. The host driver may optimize for this scenario to minimize
+the performance loss. A way to optimize for this is to split the current
+request in two chunks, prepare the first chunk and start the request,
+and finally prepare the second chunk and start the transfer.
+
+Pseudocode to handle is_first_req scenario with minimal prepare overhead:
+
+if (is_first_req && req->size > threshold)
+   /* start MMC transfer for the complete transfer size */
+   mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
+
+   /*
+    * Begin to prepare DMA while cmd is being processed by MMC.
+    * The first chunk of the request should take the same time
+    * to prepare as the "MMC process command time".
+    * If prepare time exceeds MMC cmd time
+    * the transfer is delayed, guesstimate max 4k as first chunk size.
+    */
+    prepare_1st_chunk_for_dma(req);
+    /* flush pending desc to the DMAC (dmaengine.h) */
+    dma_issue_pending(req->dma_desc);
+
+    prepare_2nd_chunk_for_dma(req);
+    /*
+     * The second issue_pending should be called before MMC runs out
+     * of the first chunk. If the MMC runs out of the first data chunk
+     * before this call, the transfer is delayed.
+     */
+    dma_issue_pending(req->dma_desc);
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 9672d2c..58aece2 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -176,3 +176,5 @@
 CONFIG_MSM_N_WAY_SMD=y
 CONFIG_MSM_N_WAY_SMSM=y
 CONFIG_MSM_SMD_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f1b1fa5..152cb86 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -301,6 +301,7 @@
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
@@ -319,6 +320,7 @@
 CONFIG_OV2720=y
 CONFIG_S5K3L1YX=y
 CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -336,8 +338,9 @@
 CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
 CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
 CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
-CONFIG_FB_MSM_HDMI_MSM_PANEL=y
 CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
+CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_SOUND=y
@@ -351,7 +354,6 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
@@ -374,6 +376,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index e58b94b..a326de6 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -297,12 +297,11 @@
 CONFIG_SENSORS_PM8XXX_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
-CONFIG_THERMAL_PM8XXX=y
-CONFIG_THERMAL_MONITOR=y
 CONFIG_MFD_PM8921_CORE=y
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
@@ -353,7 +352,6 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
@@ -376,6 +374,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 7e5e2f8..5bef079 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -65,6 +65,9 @@
 static uint32_t bam_dmux_write_cpy_bytes;
 static uint32_t bam_dmux_tx_sps_failure_cnt;
 static uint32_t bam_dmux_tx_stall_cnt;
+static atomic_t bam_dmux_ack_out_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_ack_in_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_a2_pwr_cntl_in_cnt = ATOMIC_INIT(0);
 
 #define DBG(x...) do {		                 \
 		if (msm_bam_dmux_debug_enable)  \
@@ -102,6 +105,14 @@
 	bam_dmux_tx_stall_cnt++; \
 } while (0)
 
+#define DBG_INC_ACK_OUT_CNT() \
+	atomic_inc(&bam_dmux_ack_out_cnt)
+
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	atomic_inc(&bam_dmux_a2_pwr_cntl_in_cnt)
+
+#define DBG_INC_ACK_IN_CNT() \
+	atomic_inc(&bam_dmux_ack_in_cnt)
 #else
 #define DBG(x...) do { } while (0)
 #define DBG_INC_READ_CNT(x...) do { } while (0)
@@ -109,6 +120,10 @@
 #define DBG_INC_WRITE_CPY(x...) do { } while (0)
 #define DBG_INC_TX_SPS_FAILURE_CNT() do { } while (0)
 #define DBG_INC_TX_STALL_CNT() do { } while (0)
+#define DBG_INC_ACK_OUT_CNT() do { } while (0)
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	do { } while (0)
+#define DBG_INC_ACK_IN_CNT() do { } while (0)
 #endif
 
 struct bam_ch_info {
@@ -1200,14 +1215,20 @@
 			"skb copy bytes:  %u\n"
 			"sps tx failures: %u\n"
 			"sps tx stalls:   %u\n"
-			"rx queue len:    %d\n",
+			"rx queue len:    %d\n"
+			"a2 ack out cnt:  %d\n"
+			"a2 ack in cnt:   %d\n"
+			"a2 pwr cntl in:  %d\n",
 			bam_dmux_read_cnt,
 			bam_dmux_write_cnt,
 			bam_dmux_write_cpy_cnt,
 			bam_dmux_write_cpy_bytes,
 			bam_dmux_tx_sps_failure_cnt,
 			bam_dmux_tx_stall_cnt,
-			bam_rx_pool_len
+			bam_rx_pool_len,
+			atomic_read(&bam_dmux_ack_out_cnt),
+			atomic_read(&bam_dmux_ack_in_cnt),
+			atomic_read(&bam_dmux_a2_pwr_cntl_in_cnt)
 			);
 
 	return i;
@@ -1512,21 +1533,11 @@
 
 static int ssrestart_check(void)
 {
-	/*
-	 * if the restart level is RESET_SOC, SSR is not on
-	 * so the crashed modem will end up crashing the system
-	 * anyways, so use BUG() to report the error
-	 * else prepare for the restart event which should
-	 * happen soon
-	 */
-	DMUX_LOG_KERR("%s: modem timeout\n", __func__);
-	if (get_restart_level() <= RESET_SOC) {
-		BUG();
-		return 0;
-	} else {
-		in_global_reset = 1;
-		return 1;
-	}
+	DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
+	in_global_reset = 1;
+	if (get_restart_level() <= RESET_SOC)
+		DMUX_LOG_KERR("%s: ssrestart not enabled\n", __func__);
+	return 1;
 }
 
 static void ul_wakeup(void)
@@ -2047,11 +2058,13 @@
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
 				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
 	clear_bit = ~clear_bit;
+	DBG_INC_ACK_OUT_CNT();
 }
 
 static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
 {
 	bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
+	DBG_INC_A2_POWER_CONTROL_IN_CNT();
 	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 
@@ -2090,6 +2103,7 @@
 static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
 						uint32_t new_state)
 {
+	DBG_INC_ACK_IN_CNT();
 	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 	complete_all(&ul_wakeup_ack_completion);
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 4287153..ea2a9f6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,19 +12,19 @@
 
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 
-static struct single_row_lut fcc_temp = {
+static struct single_row_lut palladium_1500_fcc_temp = {
 	.x	= {-30, -20, -10, 0, 10, 25, 40, 60},
 	.y	= {1103, 1179, 1284, 1330, 1420, 1511, 1541, 1571},
 	.cols	= 8,
 };
 
-static struct single_row_lut fcc_sf = {
+static struct single_row_lut palladium_1500_fcc_sf = {
 	.x	= {100, 200, 300, 400, 500},
 	.y	= {97, 93, 93, 90, 87},
 	.cols	= 5,
 };
 
-static struct pc_sf_lut pc_sf = {
+static struct pc_sf_lut palladium_1500_pc_sf = {
 	.rows		= 10,
 	.cols		= 5,
 	.cycles		= {100, 200, 300, 400, 500},
@@ -43,7 +43,7 @@
 	},
 };
 
-static struct pc_temp_ocv_lut  pc_temp_ocv = {
+static struct pc_temp_ocv_lut palladium_1500_pc_temp_ocv = {
 	.rows		= 29,
 	.cols		= 8,
 	.temp		= {-30, -20, -10, 0, 10, 25, 40, 60},
@@ -84,10 +84,81 @@
 	},
 };
 
-struct pm8921_bms_battery_data  palladium_1500_data = {
+struct pm8921_bms_battery_data palladium_1500_data = {
 	.fcc			= 1500,
-	.fcc_temp_lut		= &fcc_temp,
-	.fcc_sf_lut		= &fcc_sf,
-	.pc_temp_ocv_lut	= &pc_temp_ocv,
-	.pc_sf_lut		= &pc_sf,
+	.fcc_temp_lut		= &palladium_1500_fcc_temp,
+	.fcc_sf_lut		= &palladium_1500_fcc_sf,
+	.pc_temp_ocv_lut	= &palladium_1500_pc_temp_ocv,
+	.pc_sf_lut		= &palladium_1500_pc_sf,
+};
+
+static struct single_row_lut desay_5200_fcc_temp = {
+	.x		= {-20, 0, 25, 40},
+	.y		= {5690, 5722, 5722, 5727},
+	.cols	= 4
+};
+
+static struct single_row_lut desay_5200_fcc_sf = {
+	.x		= {0},
+	.y		= {100},
+	.cols	= 1
+};
+
+static struct pc_temp_ocv_lut desay_5200_pc_temp_ocv = {
+	.rows		= 29,
+	.cols		= 4,
+	.temp		= {-20, 0, 25, 40},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
+				50, 45, 40, 35, 30, 25, 20, 15, 10, 9, 8,
+				7, 6, 5, 4, 3, 2, 1, 0
+	},
+	.ocv		= {
+				{4185, 4184, 4181, 4178},
+				{4103, 4117, 4120, 4119},
+				{4044, 4067, 4074, 4073},
+				{3987, 4019, 4031, 4030},
+				{3941, 3974, 3992, 3992},
+				{3902, 3936, 3958, 3957},
+				{3866, 3901, 3926, 3926},
+				{3835, 3870, 3891, 3896},
+				{3811, 3842, 3855, 3858},
+				{3792, 3818, 3827, 3827},
+				{3776, 3795, 3806, 3806},
+				{3762, 3778, 3789, 3790},
+				{3748, 3765, 3777, 3777},
+				{3735, 3752, 3767, 3765},
+				{3720, 3739, 3756, 3754},
+				{3704, 3726, 3743, 3736},
+				{3685, 3712, 3723, 3716},
+				{3664, 3697, 3695, 3689},
+				{3623, 3672, 3669, 3664},
+				{3611, 3666, 3666, 3661},
+				{3597, 3659, 3662, 3658},
+				{3579, 3648, 3657, 3653},
+				{3559, 3630, 3644, 3639},
+				{3532, 3600, 3612, 3606},
+				{3497, 3558, 3565, 3559},
+				{3450, 3500, 3504, 3498},
+				{3380, 3417, 3421, 3416},
+				{3265, 3287, 3296, 3293},
+				{3000, 3000, 3000, 3000}
+	},
+};
+
+static struct pc_sf_lut desay_5200_pc_sf = {
+	.rows		= 1,
+	.cols		= 1,
+	.cycles		= {0},
+	.percent	= {100},
+	.sf			= {
+				{100}
+	},
+};
+
+struct pm8921_bms_battery_data desay_5200_data = {
+	.fcc			= 5200,
+	.fcc_temp_lut		= &desay_5200_fcc_temp,
+	.fcc_sf_lut		= &desay_5200_fcc_sf,
+	.pc_temp_ocv_lut	= &desay_5200_pc_temp_ocv,
+	.pc_sf_lut		= &desay_5200_pc_sf,
 };
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 73221b5..486ebd3 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -332,15 +332,15 @@
 };
 
 static struct camera_vreg_t apq_8064_back_cam_vreg[] = {
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
 
 static struct camera_vreg_t apq_8064_front_cam_vreg[] = {
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
@@ -418,7 +418,6 @@
 	.i2c_mux_mode = MODE_L,
 };
 
-#ifdef CONFIG_IMX074
 static struct msm_camera_sensor_flash_data flash_imx074 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
@@ -440,9 +439,35 @@
 	.camera_type = BACK_CAMERA_2D,
 	.actuator_info = &imx074_actuator_info
 };
-#endif
 
-#ifdef CONFIG_OV2720
+static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+	.flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+	.mount_angle = 90,
+	.cam_vreg = apq_8064_mt9m114_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_mt9m114_vreg),
+	.gpio_conf = &apq8064_front_cam_gpio_conf,
+	.i2c_conf = &apq8064_front_cam_i2c_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+	.sensor_name = "mt9m114",
+	.pdata = &msm_camera_csi_device_data[1],
+	.flash_data = &flash_mt9m114,
+	.sensor_platform_info = &sensor_board_info_mt9m114,
+	.csi_if = 1,
+	.camera_type = FRONT_CAMERA_2D,
+};
+
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
@@ -463,8 +488,6 @@
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
 };
-#endif
-
 
 void __init apq8064_init_cam(void)
 {
@@ -483,18 +506,18 @@
 
 #ifdef CONFIG_I2C
 static struct i2c_board_info apq8064_camera_i2c_boardinfo[] = {
-#ifdef CONFIG_IMX074
 	{
 	I2C_BOARD_INFO("imx074", 0x1A),
 	.platform_data = &msm_camera_sensor_imx074_data,
 	},
-#endif
-#ifdef CONFIG_OV2720
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
 	{
 	I2C_BOARD_INFO("ov2720", 0x6C),
 	.platform_data = &msm_camera_sensor_ov2720_data,
 	},
-#endif
 };
 
 struct msm_camera_board_info apq8064_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 213215e..e9b497b 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -150,14 +150,14 @@
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
-			.gpu_freq = 192000000,
-			.bus_freq = 2,
-			.io_fraction = 100,
+			.gpu_freq = 400000000,
+			.bus_freq = 4,
+			.io_fraction = 0,
 		},
 		{
-			.gpu_freq = 192000000,
-			.bus_freq = 2,
-			.io_fraction = 100,
+			.gpu_freq = 320000000,
+			.bus_freq = 3,
+			.io_fraction = 33,
 		},
 		{
 			.gpu_freq = 1920000000,
@@ -165,9 +165,8 @@
 			.io_fraction = 100,
 		},
 		{
-			.gpu_freq = 192000000,
-			.bus_freq = 2,
-			.io_fraction = 100,
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
 		},
 	},
 	.init_level = 0,
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 364df81..bd5f703 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -356,6 +356,7 @@
 
 static struct pm8921_bms_platform_data
 apq8064_pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -428,5 +429,9 @@
 	if (machine_is_apq8064_rumi3()) {
 		apq8064_pm8921_irq_pdata.devirq = 0;
 		apq8064_pm8821_irq_pdata.devirq = 0;
+	} else if (machine_is_apq8064_mtp()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	} else if (machine_is_apq8064_liquid()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 0d12bb5..247b230 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -59,6 +59,7 @@
 VREG_CONSUMERS(L8) = {
 	REGULATOR_SUPPLY("8921_l8",		NULL),
 	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
 };
 VREG_CONSUMERS(L9) = {
@@ -75,6 +76,7 @@
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
 	REGULATOR_SUPPLY("8921_l12",		NULL),
 };
@@ -87,6 +89,7 @@
 VREG_CONSUMERS(L16) = {
 	REGULATOR_SUPPLY("8921_l16",		NULL),
 	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
 };
 VREG_CONSUMERS(L17) = {
@@ -187,6 +190,7 @@
 VREG_CONSUMERS(LVS5) = {
 	REGULATOR_SUPPLY("8921_lvs5",		NULL),
 	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
 };
 VREG_CONSUMERS(LVS6) = {
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 8e7fb1a..3848262 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -16,8 +16,8 @@
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
 #include <linux/mfd/pm8xxx/misc.h>
 #include <linux/msm_ssbi.h>
 #include <linux/spi/spi.h>
@@ -499,14 +499,14 @@
  * does not need to be as high as 2.85V. It is choosen for
  * microphone sensitivity purpose.
  */
-static struct tabla_pdata apq8064_tabla_platform_data = {
+static struct wcd9xxx_pdata apq8064_tabla_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(42),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -517,7 +517,45 @@
 		.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 slim_device apq8064_slim_tabla = {
@@ -528,14 +566,14 @@
 	},
 };
 
-static struct tabla_pdata apq8064_tabla20_platform_data = {
+static struct wcd9xxx_pdata apq8064_tabla20_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(42),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -546,7 +584,45 @@
 		.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 slim_device apq8064_slim_tabla20 = {
@@ -642,7 +718,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	14, 0, 0, 24, 1, 12, 0, 0, 0, 0,
+	14, 1, 0, 22, 2, 12, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -650,14 +726,14 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T7 Object */
-	100, 16, 50,
+	100, 10, 50,
 	/* T8 Object */
-	25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
 	/* T9 Object */
 	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
 	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
-	85, 5, 10, 10, 10, 10, 135, 55, 70, 40,
-	10, 5, 0, 0, 0,
+	85, 5, 0, 5, 9, 5, 12, 35, 70, 40,
+	20, 5, 0, 0, 0,
 	/* T18 Object */
 	0, 0,
 	/* T24 Object */
@@ -675,14 +751,14 @@
 	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
 	16,
 	/* T46 Object */
-	64, 0, 20, 20, 0, 0, 0, 0, 0,
+	68, 0, 16, 16, 0, 0, 0, 0, 0,
 	/* T47 Object */
 	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
 	/* T48 Object */
 	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
-	48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
-	0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
-	52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
+	32, 40, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 10,
+	52, 10, 12, 0, 33, 0, 1, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T56 Object */
@@ -690,8 +766,8 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	2, 99, 33, 0, 149, 24, 193, 255, 255, 255,
-	255,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
 };
 
 #define MXT_TS_GPIO_IRQ			6
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index f82c43c..1d743d8 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -458,16 +458,16 @@
 	.mount_angle = 90,
 	.cam_vreg = msm_8930_mt9m114_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8930_mt9m114_vreg),
-	.gpio_conf = &msm_8930_back_cam_gpio_conf,
+	.gpio_conf = &msm_8930_front_cam_gpio_conf,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
 	.sensor_name = "mt9m114",
-	.pdata = &msm_camera_csi_device_data[0],
+	.pdata = &msm_camera_csi_device_data[1],
 	.flash_data = &flash_mt9m114,
 	.sensor_platform_info = &sensor_board_info_mt9m114,
 	.csi_if = 1,
-	.camera_type = BACK_CAMERA_2D,
+	.camera_type = FRONT_CAMERA_2D,
 };
 
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 3f9f976..e19cde0 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -273,6 +273,7 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -310,4 +311,8 @@
 				&msm8930_ssbi_pm8038_pdata;
 	pm8038_platform_data.num_regulators
 		= msm8930_pm8038_regulator_pdata_len;
+	if (machine_is_apq8064_mtp())
+		pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	else if (machine_is_apq8064_liquid())
+		pm8921_bms_pdata.battery_type = BATT_DESAY;
 }
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index ad71007..278c08c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -42,6 +42,10 @@
 #include <linux/gpio_keys.h>
 #include <linux/memory.h>
 
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/setup.h>
@@ -68,12 +72,6 @@
 #include <mach/msm_xo.h>
 #include <mach/restart.h>
 
-#ifdef CONFIG_WCD9310_CODEC
-#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
-#endif
-
 #include <linux/ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
@@ -518,9 +516,9 @@
 	msm8930_allocate_fb_region();
 }
 
-#ifdef CONFIG_WCD9310_CODEC
+#ifdef CONFIG_WCD9304_CODEC
 
-#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+#define SITAR_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
 
 /* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
  * 4 micbiases are used to power various analog and digital
@@ -531,82 +529,77 @@
  * does not need to be as high as 2.85V. It is choosen for
  * microphone sensitivity purpose.
  */
-static struct tabla_pdata tabla_platform_data = {
-	.slimbus_slave_device = {
-		.name = "tabla-slave",
-		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
+static struct wcd9xxx_pdata sitar_platform_data = {
+		.slimbus_slave_device = {
+		.name = "sitar-slave",
+		.e_addr = {0, 0, 0x00, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(62),
-	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
-
-/*TODO: Replace this with right PM8038 gpio */
-#ifndef MSM8930_PHASE_2
-	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
-#endif
+	.irq_base = SITAR_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = 42,
 	.micbias = {
-		.ldoh_v = TABLA_LDOH_2P85_V,
+		.ldoh_v = SITAR_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,
-	}
-};
-
-static struct slim_device msm_slim_tabla = {
-	.name = "tabla-slim",
-	.e_addr = {0, 1, 0x10, 0, 0x17, 2},
-	.dev = {
-		.platform_data = &tabla_platform_data,
+		.bias1_cfilt_sel = SITAR_CFILT1_SEL,
+		.bias2_cfilt_sel = SITAR_CFILT2_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 2200000,
+		.max_uV = 2200000,
+		.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 = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
 	},
 };
 
-static struct tabla_pdata tabla20_platform_data = {
-	.slimbus_slave_device = {
-		.name = "tabla-slave",
-		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
-	},
-	.irq = MSM_GPIO_TO_INT(62),
-	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
-
-/*TODO: Replace this with right PM8038 gpio */
-#ifndef MSM8930_PHASE_2
-	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
-#endif
-	.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,
-	}
-};
-
-static struct slim_device msm_slim_tabla20 = {
-	.name = "tabla2x-slim",
-	.e_addr = {0, 1, 0x60, 0, 0x17, 2},
+static struct slim_device msm_slim_sitar = {
+	.name = "sitar-slim",
+	.e_addr = {0, 1, 0x00, 0, 0x17, 2},
 	.dev = {
-		.platform_data = &tabla20_platform_data,
+	.platform_data = &sitar_platform_data,
 	},
 };
 #endif
 
+
 static struct slim_boardinfo msm_slim_devices[] = {
-#ifdef CONFIG_WCD9310_CODEC
+#ifdef CONFIG_WCD9304_CODEC
 	{
 		.bus_num = 1,
-		.slim_slave = &msm_slim_tabla,
-	},
-	{
-		.bus_num = 1,
-		.slim_slave = &msm_slim_tabla20,
+		.slim_slave = &msm_slim_sitar,
 	},
 #endif
 	/* add more slimbus slaves as needed */
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 42c09fb..3a697bf 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -529,16 +529,16 @@
 	.mount_angle = 90,
 	.cam_vreg = msm_8960_mt9m114_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8960_mt9m114_vreg),
-	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.gpio_conf = &msm_8960_front_cam_gpio_conf,
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
 	.sensor_name = "mt9m114",
-	.pdata = &msm_camera_csi_device_data[0],
+	.pdata = &msm_camera_csi_device_data[1],
 	.flash_data = &flash_mt9m114,
 	.sensor_platform_info = &sensor_board_info_mt9m114,
 	.csi_if = 1,
-	.camera_type = BACK_CAMERA_2D,
+	.camera_type = FRONT_CAMERA_2D,
 };
 
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 5f8f90b..4e18f89 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -439,6 +439,7 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -563,6 +564,17 @@
 	.r_sense		= 10,
 };
 
+/**
+ * PM8XXX_PWM_DTEST_CHANNEL_NONE shall be used when no LPG
+ * channel should be in DTEST mode.
+ */
+
+#define PM8XXX_PWM_DTEST_CHANNEL_NONE   (-1)
+
+static struct pm8xxx_pwm_platform_data pm8xxx_pwm_pdata = {
+	.dtest_channel	= PM8XXX_PWM_DTEST_CHANNEL_NONE,
+};
+
 static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
 	.irq_pdata		= &pm8xxx_irq_pdata,
 	.gpio_pdata		= &pm8xxx_gpio_pdata,
@@ -577,6 +589,7 @@
 	.adc_pdata		= &pm8xxx_adc_pdata,
 	.leds_pdata		= &pm8xxx_leds_pdata,
 	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
+	.pwm_pdata		= &pm8xxx_pwm_pdata,
 };
 
 static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
@@ -601,5 +614,8 @@
 	if (machine_is_msm8960_liquid()) {
 		pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
 		pm8921_platform_data.leds_pdata = &pm8xxx_leds_pdata_liquid;
+		pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
+	} else if (machine_is_msm8960_mtp()) {
+		pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index e843a39..7fd6820 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -70,9 +70,8 @@
 #include <mach/restart.h>
 
 #ifdef CONFIG_WCD9310_CODEC
-#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
 #endif
 
 #include <linux/ion.h>
@@ -664,14 +663,14 @@
  * does not need to be as high as 2.85V. It is choosen for
  * microphone sensitivity purpose.
  */
-static struct tabla_pdata tabla_platform_data = {
+static struct wcd9xxx_pdata tabla_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(62),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -682,7 +681,45 @@
 		.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 slim_device msm_slim_tabla = {
@@ -693,14 +730,14 @@
 	},
 };
 
-static struct tabla_pdata tabla20_platform_data = {
+static struct wcd9xxx_pdata tabla20_platform_data = {
 	.slimbus_slave_device = {
 		.name = "tabla-slave",
 		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
 	},
 	.irq = MSM_GPIO_TO_INT(62),
 	.irq_base = TABLA_INTERRUPT_BASE,
-	.num_irqs = NR_TABLA_IRQS,
+	.num_irqs = NR_WCD9XXX_IRQS,
 	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
@@ -711,7 +748,45 @@
 		.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 slim_device msm_slim_tabla20 = {
@@ -1721,7 +1796,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	13, 0, 0, 6, 2, 12, 0, 0, 0, 0,
+	13, 1, 0, 23, 2, 12, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1729,39 +1804,39 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T7 Object */
-	100, 16, 50,
+	100, 10, 50,
 	/* T8 Object */
-	25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
 	/* T9 Object */
 	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
 	0, 5, 5, 0, 10, 30, 10, 10, 175, 4,
-	127, 7, 10, 10, 10, 10, 135, 55, 70, 40,
-	10, 5, 0, 0, 0,
+	127, 7, 26, 21, 17, 19, 143, 35, 207, 40,
+	20, 5, 54, 49, 0,
 	/* T18 Object */
 	0, 0,
 	/* T24 Object */
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* T25 Object */
-	3, 0, 60, 115, 156, 99,
+	0, 0, 72, 113, 168, 97,
 	/* T27 Object */
 	0, 0, 0, 0, 0, 0, 0,
 	/* T40 Object */
 	0, 0, 0, 0, 0,
 	/* T42 Object */
-	2, 0, 255, 0, 255, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* T43 Object */
-	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
-	16,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
 	/* T46 Object */
-	64, 0, 20, 20, 0, 0, 0, 0, 0,
+	68, 0, 16, 16, 0, 0, 0, 0, 0,
 	/* T47 Object */
 	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
 	/* T48 Object */
 	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
-	48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
-	0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
-	52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
+	32, 50, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 30,
+	52, 10, 5, 0, 33, 0, 1, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T56 Object */
@@ -1769,8 +1844,8 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	2, 99, 33, 0, 149, 24, 193, 255, 255, 255,
-	255,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
 };
 
 #define MXT_TS_GPIO_IRQ			11
@@ -2266,62 +2341,62 @@
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		100, 8000, 100000, 1,
+		100, 650, 801, 200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		2000, 6000, 60100000, 3000,
+		2000, 200, 576000, 2000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
 		false,
-		4200, 5000, 60350000, 3500,
+		8500, 51, 1122000, 8500,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		6300, 4500, 65350000, 4800,
+		9000, 51, 1130300, 9000,
 	},
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		7000, 3500, 66600000, 5150,
+		10000, 51, 1130300, 10000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
 		false,
-		11700, 2500, 67850000, 5500,
+		12000, 14, 2205900, 12000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		13800, 2000, 71850000, 6800,
+		18000, 12, 2364250, 18000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		29700, 500, 75850000, 8800,
+		23500, 10, 2667000, 23500,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
 		false,
-		29700, 0, 76350000, 9800,
+		29700, 5, 2867000, 30000,
 	},
 };
 
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d5d8edc..34ae4c8 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -92,6 +92,7 @@
 
 #define PMEM_KERNEL_EBI1_SIZE	0x1C000
 #endif
+#define ADSP_RPC_PROG           0x3000000a
 
 static struct resource smc91x_resources[] = {
 	[0] = {
@@ -1731,6 +1732,25 @@
 	}
 }
 
+static void msm_adsp_add_pdev(void)
+{
+	int rc = 0;
+	struct rpc_board_dev *rpc_adsp_pdev;
+
+	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+	if (rpc_adsp_pdev == NULL) {
+		pr_err("%s: Memory Allocation failure\n", __func__);
+		return;
+	}
+	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+	rpc_adsp_pdev->pdev = msm_adsp_device;
+	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+	if (rc < 0) {
+		pr_err("%s: return val: %d\n",	__func__, rc);
+		kfree(rpc_adsp_pdev);
+	}
+}
+
 static void __init msm7x2x_init(void)
 {
 
@@ -1797,6 +1817,7 @@
 #ifdef CONFIG_MSM_CAMERA
 	config_camera_off_gpios(); /* might not be necessary */
 #endif
+	msm_adsp_add_pdev();
 	msm_device_i2c_init();
 	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index a6b29dc..d059b8d 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -60,6 +60,7 @@
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
+#define ADSP_RPC_PROG           0x3000000a
 
 #if defined(CONFIG_GPIO_SX150X)
 enum {
@@ -1115,6 +1116,44 @@
 	}
 };
 
+static void msm_adsp_add_pdev(void)
+{
+	int rc = 0;
+	struct rpc_board_dev *rpc_adsp_pdev;
+
+	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+	if (rpc_adsp_pdev == NULL) {
+		pr_err("%s: Memory Allocation failure\n", __func__);
+		return;
+	}
+	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+	rpc_adsp_pdev->pdev = msm_adsp_device;
+	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+	if (rc < 0) {
+		pr_err("%s: return val: %d\n",	__func__, rc);
+		kfree(rpc_adsp_pdev);
+	}
+}
+
+static void msm_adsp_8625_add_pdev(void)
+{
+	int rc = 0;
+	struct rpc_board_dev *rpc_adsp_pdev;
+
+	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+	if (rpc_adsp_pdev == NULL) {
+		pr_err("%s: Memory Allocation failure\n", __func__);
+		return;
+	}
+	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+	rpc_adsp_pdev->pdev = msm8625_device_adsp;
+	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+	if (rc < 0) {
+		pr_err("%s: return val: %d\n", __func__, rc);
+		kfree(rpc_adsp_pdev);
+	}
+}
+
 static void __init msm7627a_rumi3_init(void)
 {
 	msm7x27a_init_ebi2();
@@ -1125,6 +1164,7 @@
 static void __init msm8625_rumi3_init(void)
 {
 	msm7x2x_misc_init();
+	msm_adsp_8625_add_pdev();
 	msm_device_i2c_init();
 	platform_add_devices(msm8625_rumi3_devices,
 			ARRAY_SIZE(msm8625_rumi3_devices));
@@ -1159,6 +1199,7 @@
 	msm7x27a_init_regulators();
 
 	/* Common functions for SURF/FFA/RUMI3 */
+	msm_adsp_add_pdev();
 	msm_device_i2c_init();
 	msm7x27a_init_ebi2();
 	msm7x27a_cfg_uart2dm_serial();
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 7c2788de..5996388 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4982,6 +4982,7 @@
 	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
 	CLK_LOOKUP("core_clk",		amp_clk.c,		""),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-0048"),
 	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-006c"),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 8ec4633..19a8db7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2422,7 +2422,7 @@
 };
 
 static const char *kgsl_2d1_iommu_ctx_names[] = {
-	"gfx2d0_2d1",
+	"gfx2d1_2d1",
 };
 
 static struct kgsl_device_iommu_data kgsl_2d1_iommu_data[] = {
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index b895870..26f246d 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -76,6 +76,21 @@
 	.resource	= resources_uart2,
 };
 
+static struct resource resources_adsp[] = {
+	{
+		.start  = INT_ADSP_A9_A11,
+		.end    = INT_ADSP_A9_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_adsp_device = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_adsp),
+	.resource       = resources_adsp,
+};
+
 #define MSM_UART1DM_PHYS      0xA0200000
 #define MSM_UART2DM_PHYS      0xA0300000
 static struct resource msm_uart1_dm_resources[] = {
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index c18b6b2..cc1e7c5 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -210,6 +210,21 @@
 	.id	= -1,
 };
 
+static struct resource resources_adsp[] = {
+	{
+		.start  = INT_ADSP_A9_A11,
+		.end    = INT_ADSP_A9_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_adsp_device = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_adsp),
+	.resource       = resources_adsp,
+};
+
 static struct resource resources_uart1[] = {
 	{
 		.start	= INT_UART1,
@@ -843,6 +858,21 @@
 	.resource	= msm8625_uart2dm_resources,
 };
 
+static struct resource msm8625_resources_adsp[] = {
+	{
+		.start  = MSM8625_INT_ADSP_A9_A11,
+		.end    = MSM8625_INT_ADSP_A9_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_adsp = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(msm8625_resources_adsp),
+	.resource       = msm8625_resources_adsp,
+};
+
 static struct resource msm8625_dmov_resource[] = {
 	{
 		.start	= MSM8625_INT_ADM_AARM,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 6da7b8f..ed48659 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -38,6 +38,7 @@
 extern struct platform_device msm_ebi0_thermal;
 extern struct platform_device msm_ebi1_thermal;
 
+extern struct platform_device msm_adsp_device;
 extern struct platform_device msm_device_uart1;
 extern struct platform_device msm_device_uart2;
 extern struct platform_device msm_device_uart3;
@@ -139,6 +140,7 @@
 extern struct platform_device msm8625_device_hsusb_host;
 extern struct platform_device msm8625_device_otg;
 extern struct platform_device msm8625_kgsl_3d0;
+extern struct platform_device msm8625_device_adsp;
 
 extern struct platform_device msm_slim_ctrl;
 extern struct platform_device msm_device_sps;
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 954b673..1ae7454 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -42,10 +42,11 @@
 #define NR_GPIO_IRQS 152
 #define NR_PM8921_IRQS 256
 #define NR_PM8821_IRQS 64
-#define NR_TABLA_IRQS 49
+#define NR_WCD9XXX_IRQS 49
+#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
 #define NR_GPIO_EXPANDER_IRQS 8
 #define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
-		NR_TABLA_IRQS + NR_GPIO_EXPANDER_IRQS)
+		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 
diff --git a/arch/arm/mach-msm/include/mach/msm_adsp.h b/arch/arm/mach-msm/include/mach/msm_adsp.h
index bbae6c1..e40c07d 100644
--- a/arch/arm/mach-msm/include/mach/msm_adsp.h
+++ b/arch/arm/mach-msm/include/mach/msm_adsp.h
@@ -1,7 +1,7 @@
 /* include/asm-arm/arch-msm/msm_adsp.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, 2012 Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -52,6 +52,14 @@
 		   unsigned queue_id,
 		   void *data, size_t len);
 
+/*Explicitly gererate adsp event */
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg);
+
 #define ADSP_MESSAGE_ID 0xFFFF
 
 /* Command Queue Indexes */
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
index 59352d1..5eea63f 100644
--- a/arch/arm/mach-msm/include/mach/msm_rtb.h
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -13,14 +13,18 @@
 #ifndef __MSM_RTB_H__
 #define __MSM_RTB_H__
 
+/*
+ * These numbers are used from the kernel command line and sysfs
+ * to control filtering. Remove items from here with extreme caution
+ */
 enum logk_event_type {
 	LOGK_NONE = 0,
-	LOGK_READL,
-	LOGK_WRITEL,
-	LOGK_LOGBUF,
-	LOGK_HOTPLUG,
-	LOGK_CTXID,
-	LOGK_OTHER,
+	LOGK_READL = 1,
+	LOGK_WRITEL = 2,
+	LOGK_LOGBUF = 3,
+	LOGK_HOTPLUG = 4,
+	LOGK_CTXID = 5,
+	LOGK_OTHER = 31,
 };
 
 struct msm_rtb_platform_data {
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 463d6c9..853888a 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -56,7 +56,7 @@
 
 static int msm_iommu_tex_class[4];
 
-DEFINE_SPINLOCK(msm_iommu_lock);
+DEFINE_MUTEX(msm_iommu_lock);
 
 struct msm_priv {
 	unsigned long *pgtable;
@@ -68,14 +68,14 @@
 {
 	int ret;
 
-	ret = clk_enable(drvdata->pclk);
+	ret = clk_prepare_enable(drvdata->pclk);
 	if (ret)
 		goto fail;
 
 	if (drvdata->clk) {
-		ret = clk_enable(drvdata->clk);
+		ret = clk_prepare_enable(drvdata->clk);
 		if (ret)
-			clk_disable(drvdata->pclk);
+			clk_disable_unprepare(drvdata->pclk);
 	}
 fail:
 	return ret;
@@ -84,8 +84,8 @@
 static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
 {
 	if (drvdata->clk)
-		clk_disable(drvdata->clk);
-	clk_disable(drvdata->pclk);
+		clk_disable_unprepare(drvdata->clk);
+	clk_disable_unprepare(drvdata->pclk);
 }
 
 static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
@@ -299,11 +299,10 @@
 static void msm_iommu_domain_destroy(struct iommu_domain *domain)
 {
 	struct msm_priv *priv;
-	unsigned long flags;
 	unsigned long *fl_table;
 	int i;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 	priv = domain->priv;
 	domain->priv = NULL;
 
@@ -320,7 +319,7 @@
 	}
 
 	kfree(priv);
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 }
 
 static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -331,9 +330,8 @@
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	struct msm_iommu_ctx_drvdata *tmp_drvdata;
 	int ret = 0;
-	unsigned long flags;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 
@@ -373,7 +371,7 @@
 	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
 
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -384,10 +382,9 @@
 	struct msm_iommu_ctx_dev *ctx_dev;
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
-	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 	priv = domain->priv;
 
 	if (!priv || !dev)
@@ -412,7 +409,7 @@
 	list_del_init(&ctx_drvdata->attached_elm);
 
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 }
 
 static int __get_pgprot(int prot, int len)
@@ -447,7 +444,6 @@
 			 phys_addr_t pa, int order, int prot)
 {
 	struct msm_priv *priv;
-	unsigned long flags;
 	unsigned long *fl_table;
 	unsigned long *fl_pte;
 	unsigned long fl_offset;
@@ -458,7 +454,7 @@
 	size_t len = 0x1000UL << order;
 	int ret = 0;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 	if (!priv) {
@@ -525,7 +521,7 @@
 
 		if (*fl_pte == 0) {
 			unsigned long *sl;
-			sl = (unsigned long *) __get_free_pages(GFP_ATOMIC,
+			sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
 							get_order(SZ_4K));
 
 			if (!sl) {
@@ -583,7 +579,7 @@
 
 	ret = __flush_iotlb_va(domain, va);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -591,7 +587,6 @@
 			    int order)
 {
 	struct msm_priv *priv;
-	unsigned long flags;
 	unsigned long *fl_table;
 	unsigned long *fl_pte;
 	unsigned long fl_offset;
@@ -601,7 +596,7 @@
 	size_t len = 0x1000UL << order;
 	int i, ret = 0;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 
@@ -686,7 +681,7 @@
 
 	ret = __flush_iotlb_va(domain, va);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -702,13 +697,12 @@
 	unsigned long fl_offset;
 	unsigned long *sl_table;
 	unsigned long sl_offset, sl_start;
-	unsigned long flags;
 	unsigned int chunk_offset = 0;
 	unsigned int chunk_pa;
 	int ret = 0;
 	struct msm_priv *priv;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	BUG_ON(len & (SZ_4K - 1));
 
@@ -734,7 +728,7 @@
 		/* Set up a 2nd level page table if one doesn't exist */
 		if (*fl_pte == 0) {
 			sl_table = (unsigned long *)
-				 __get_free_pages(GFP_ATOMIC, get_order(SZ_4K));
+				 __get_free_pages(GFP_KERNEL, get_order(SZ_4K));
 
 			if (!sl_table) {
 				pr_debug("Could not allocate second level table\n");
@@ -782,7 +776,7 @@
 	}
 	__flush_iotlb(domain);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -796,11 +790,10 @@
 	unsigned long fl_offset;
 	unsigned long *sl_table;
 	unsigned long sl_start, sl_end;
-	unsigned long flags;
 	int used, i;
 	struct msm_priv *priv;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	BUG_ON(len & (SZ_4K - 1));
 
@@ -854,7 +847,7 @@
 	}
 
 	__flush_iotlb(domain);
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return 0;
 }
 
@@ -865,12 +858,11 @@
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	unsigned int par;
-	unsigned long flags;
 	void __iomem *base;
 	phys_addr_t ret = 0;
 	int ctx;
 
-	spin_lock_irqsave(&msm_iommu_lock, flags);
+	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 	if (list_empty(&priv->list_attached))
@@ -903,7 +895,7 @@
 
 	__disable_clocks(iommu_drvdata);
 fail:
-	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
 
@@ -947,7 +939,7 @@
 	unsigned int fsr;
 	int i, ret;
 
-	spin_lock(&msm_iommu_lock);
+	mutex_lock(&msm_iommu_lock);
 
 	if (!drvdata) {
 		pr_err("Invalid device ID in context interrupt handler\n");
@@ -975,7 +967,7 @@
 	}
 	__disable_clocks(drvdata);
 fail:
-	spin_unlock(&msm_iommu_lock);
+	mutex_unlock(&msm_iommu_lock);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index 1982082..70e96b0 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -156,7 +156,7 @@
 		goto fail;
 	}
 
-	ret = clk_enable(iommu_pclk);
+	ret = clk_prepare_enable(iommu_pclk);
 	if (ret)
 		goto fail_enable;
 
@@ -168,7 +168,7 @@
 			clk_set_rate(iommu_clk, ret);
 		}
 
-		ret = clk_enable(iommu_clk);
+		ret = clk_prepare_enable(iommu_clk);
 		if (ret) {
 			clk_put(iommu_clk);
 			goto fail_pclk;
@@ -226,8 +226,8 @@
 		goto fail_io;
 	}
 
-	ret = request_irq(irq, msm_iommu_fault_handler, 0,
-			"msm_iommu_secure_irpt_handler", drvdata);
+	ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+			IRQF_ONESHOT, "msm_iommu_secure_irpt_handler", drvdata);
 	if (ret) {
 		pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
 		goto fail_io;
@@ -247,9 +247,9 @@
 	platform_set_drvdata(pdev, drvdata);
 
 	if (iommu_clk)
-		clk_disable(iommu_clk);
+		clk_disable_unprepare(iommu_clk);
 
-	clk_disable(iommu_pclk);
+	clk_disable_unprepare(iommu_pclk);
 
 	return 0;
 fail_io:
@@ -258,11 +258,11 @@
 	release_mem_region(r->start, len);
 fail_clk:
 	if (iommu_clk) {
-		clk_disable(iommu_clk);
+		clk_disable_unprepare(iommu_clk);
 		clk_put(iommu_clk);
 	}
 fail_pclk:
-	clk_disable(iommu_pclk);
+	clk_disable_unprepare(iommu_pclk);
 fail_enable:
 	clk_put(iommu_pclk);
 fail:
@@ -315,14 +315,14 @@
 	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
 	platform_set_drvdata(pdev, ctx_drvdata);
 
-	ret = clk_enable(drvdata->pclk);
+	ret = clk_prepare_enable(drvdata->pclk);
 	if (ret)
 		goto fail;
 
 	if (drvdata->clk) {
-		ret = clk_enable(drvdata->clk);
+		ret = clk_prepare_enable(drvdata->clk);
 		if (ret) {
-			clk_disable(drvdata->pclk);
+			clk_disable_unprepare(drvdata->pclk);
 			goto fail;
 		}
 	}
@@ -357,8 +357,8 @@
 	mb();
 
 	if (drvdata->clk)
-		clk_disable(drvdata->clk);
-	clk_disable(drvdata->pclk);
+		clk_disable_unprepare(drvdata->clk);
+	clk_disable_unprepare(drvdata->pclk);
 
 	dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
 	return 0;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 15ea8ba..538dbbe 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -756,7 +756,7 @@
 	pkt->length = pkt_size;
 
 	mutex_lock(&xprt_info->tx_lock);
-	ret = xprt_info->xprt->write(pkt, pkt_size, 0);
+	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock);
 
 	release_pkt(pkt);
@@ -933,7 +933,8 @@
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
 		mutex_lock(&fwd_xprt_info->tx_lock);
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+			fwd_xprt_info->xprt->write(pkt, pkt->length,
+						   fwd_xprt_info->xprt);
 		mutex_unlock(&fwd_xprt_info->tx_lock);
 	}
 	mutex_unlock(&xprt_info_list_lock);
@@ -984,7 +985,7 @@
 		pr_err("%s: DST in the same cluster\n", __func__);
 		return 0;
 	}
-	fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
 	mutex_unlock(&fwd_xprt_info->tx_lock);
 	mutex_unlock(&rt_entry->lock);
 	mutex_unlock(&routing_table_lock);
@@ -1713,7 +1714,7 @@
 	mutex_lock(&rt_entry->lock);
 	xprt_info = rt_entry->xprt_info;
 	mutex_lock(&xprt_info->tx_lock);
-	ret = xprt_info->xprt->write(pkt, pkt->length, 0);
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock);
 	mutex_unlock(&rt_entry->lock);
 	mutex_unlock(&routing_table_lock);
@@ -2070,7 +2071,7 @@
 	mutex_lock(&xprt_info_list_lock);
 	list_for_each_entry_safe(xprt_info, tmp_xprt_info,
 				 &xprt_info_list, list) {
-		xprt_info->xprt->close();
+		xprt_info->xprt->close(xprt_info->xprt);
 		list_del(&xprt_info->list);
 		kfree(xprt_info);
 	}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index b125185..bd10ea7 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.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
@@ -150,11 +150,13 @@
 	uint32_t link_id;
 	void *priv;
 
-	int (*read_avail)(void);
-	int (*read)(void *data, uint32_t len);
-	int (*write_avail)(void);
-	int (*write)(void *data, uint32_t len, enum write_data_type type);
-	int (*close)(void);
+	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*read)(void *data, uint32_t len,
+		    struct msm_ipc_router_xprt *xprt);
+	int (*write_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*write)(void *data, uint32_t len,
+		     struct msm_ipc_router_xprt *xprt);
+	int (*close)(struct msm_ipc_router_xprt *xprt);
 };
 
 extern struct completion msm_ipc_remote_router_up;
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 997d4b5..6960d2e 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,14 +38,21 @@
 
 #define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
 
+#define NUM_SMD_XPRTS 2
+#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
+
 struct msm_ipc_router_smd_xprt {
 	struct msm_ipc_router_xprt xprt;
-
 	smd_channel_t *channel;
+	struct workqueue_struct *smd_xprt_wq;
+	wait_queue_head_t write_avail_wait_q;
+	struct rr_packet *in_pkt;
+	int is_partial_in_pkt;
+	struct delayed_work read_work;
+	spinlock_t ss_reset_lock;	/*Subsystem reset lock*/
+	int ss_reset;
 };
 
-static struct msm_ipc_router_smd_xprt smd_remote_xprt;
-
 struct msm_ipc_router_smd_xprt_work {
 	struct msm_ipc_router_xprt *xprt;
 	struct work_struct work;
@@ -54,24 +61,45 @@
 static void smd_xprt_read_data(struct work_struct *work);
 static void smd_xprt_open_event(struct work_struct *work);
 static void smd_xprt_close_event(struct work_struct *work);
-static DECLARE_DELAYED_WORK(work_read_data, smd_xprt_read_data);
-static struct workqueue_struct *smd_xprt_workqueue;
 
-static wait_queue_head_t write_avail_wait_q;
-static struct rr_packet *in_pkt;
-static int is_partial_in_pkt;
+struct msm_ipc_router_smd_xprt_config {
+	char ch_name[SMD_MAX_CH_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	uint32_t edge;
+	uint32_t link_id;
+};
 
-static DEFINE_SPINLOCK(modem_reset_lock);
-static int modem_reset;
+struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
+};
 
-static int msm_ipc_router_smd_remote_write_avail(void)
+static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
+
+static int find_smd_xprt_cfg(const char *name)
 {
-	return smd_write_avail(smd_remote_xprt.channel);
+	int i;
+
+	for (i = 0; i < NUM_SMD_XPRTS; i++) {
+		if (!strncmp(name, smd_xprt_cfg[i].ch_name, 20))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static int msm_ipc_router_smd_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_write_avail(smd_xprtp->channel);
 }
 
 static int msm_ipc_router_smd_remote_write(void *data,
 					   uint32_t len,
-					   uint32_t type)
+					   struct msm_ipc_router_xprt *xprt)
 {
 	struct rr_packet *pkt = (struct rr_packet *)data;
 	struct sk_buff *ipc_rtr_pkt;
@@ -79,6 +107,8 @@
 	int offset, sz_written = 0;
 	int ret, num_retries = 0;
 	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
 
 	if (!pkt)
 		return -EINVAL;
@@ -87,81 +117,92 @@
 		return -EINVAL;
 
 	align_sz = ALIGN_SIZE(pkt->length);
-	while ((ret = smd_write_start(smd_remote_xprt.channel,
+	while ((ret = smd_write_start(smd_xprtp->channel,
 				      (len + align_sz))) < 0) {
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		if (modem_reset) {
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
-			pr_err("%s: Modem reset\n", __func__);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
+			pr_err("%s: %s chnl reset\n", __func__, xprt->name);
 			return -ENETRESET;
 		}
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 		if (num_retries >= 5) {
-			pr_err("%s: Error %d @ smd_write_start\n",
-				__func__, ret);
+			pr_err("%s: Error %d @smd_write_start for %s\n",
+				__func__, ret, xprt->name);
 			return ret;
 		}
 		msleep(50);
+		num_retries++;
 	}
 
 	D("%s: Ready to write\n", __func__);
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
-			if (!smd_write_avail(smd_remote_xprt.channel))
-				smd_enable_read_intr(smd_remote_xprt.channel);
+			if (!smd_write_avail(smd_xprtp->channel))
+				smd_enable_read_intr(smd_xprtp->channel);
 
-			wait_event(write_avail_wait_q,
-				(smd_write_avail(smd_remote_xprt.channel) ||
-				modem_reset));
-			smd_disable_read_intr(smd_remote_xprt.channel);
-			spin_lock_irqsave(&modem_reset_lock, flags);
-			if (modem_reset) {
-				spin_unlock_irqrestore(&modem_reset_lock,
-							flags);
-				pr_err("%s: Modem reset\n", __func__);
+			wait_event(smd_xprtp->write_avail_wait_q,
+				(smd_write_avail(smd_xprtp->channel) ||
+				smd_xprtp->ss_reset));
+			smd_disable_read_intr(smd_xprtp->channel);
+			spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+			if (smd_xprtp->ss_reset) {
+				spin_unlock_irqrestore(
+					&smd_xprtp->ss_reset_lock, flags);
+				pr_err("%s: %s chnl reset\n",
+					__func__, xprt->name);
 				return -ENETRESET;
 			}
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
 
-			sz_written = smd_write_segment(smd_remote_xprt.channel,
-					  ipc_rtr_pkt->data + offset,
-					  (ipc_rtr_pkt->len - offset), 0);
+			sz_written = smd_write_segment(smd_xprtp->channel,
+					ipc_rtr_pkt->data + offset,
+					(ipc_rtr_pkt->len - offset), 0);
 			offset += sz_written;
 			sz_written = 0;
 		}
-		D("%s: Wrote %d bytes\n", __func__, offset);
+		D("%s: Wrote %d bytes over %s\n",
+		  __func__, offset, xprt->name);
 	}
 
 	if (align_sz) {
-		if (smd_write_avail(smd_remote_xprt.channel) < align_sz)
-			smd_enable_read_intr(smd_remote_xprt.channel);
+		if (smd_write_avail(smd_xprtp->channel) < align_sz)
+			smd_enable_read_intr(smd_xprtp->channel);
 
-		wait_event(write_avail_wait_q,
-			((smd_write_avail(smd_remote_xprt.channel) >=
-			 align_sz) || modem_reset));
-		smd_disable_read_intr(smd_remote_xprt.channel);
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		if (modem_reset) {
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
-			pr_err("%s: Modem reset\n", __func__);
+		wait_event(smd_xprtp->write_avail_wait_q,
+			((smd_write_avail(smd_xprtp->channel) >=
+			 align_sz) || smd_xprtp->ss_reset));
+		smd_disable_read_intr(smd_xprtp->channel);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(
+				&smd_xprtp->ss_reset_lock, flags);
+			pr_err("%s: %s chnl reset\n",
+				__func__, xprt->name);
 			return -ENETRESET;
 		}
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+					flags);
 
-		smd_write_segment(smd_remote_xprt.channel,
+		smd_write_segment(smd_xprtp->channel,
 				  &align_data, align_sz, 0);
-		D("%s: Wrote %d align bytes\n", __func__, align_sz);
+		D("%s: Wrote %d align bytes over %s\n",
+		  __func__, align_sz, xprt->name);
 	}
-	if (!smd_write_end(smd_remote_xprt.channel))
+	if (!smd_write_end(smd_xprtp->channel))
 		D("%s: Finished writing\n", __func__);
 	return len;
 }
 
-static int msm_ipc_router_smd_remote_close(void)
+static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
 {
-	smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
-	return smd_close(smd_remote_xprt.channel);
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_close(smd_xprtp->channel);
 }
 
 static void smd_xprt_read_data(struct work_struct *work)
@@ -170,90 +211,97 @@
 	struct sk_buff *ipc_rtr_pkt;
 	void *data;
 	unsigned long flags;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(rwork, struct msm_ipc_router_smd_xprt, read_work);
 
-	spin_lock_irqsave(&modem_reset_lock, flags);
-	if (modem_reset) {
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
-		release_pkt(in_pkt);
-		is_partial_in_pkt = 0;
-		pr_err("%s: Modem reset\n", __func__);
+	spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+	if (smd_xprtp->ss_reset) {
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->in_pkt)
+			release_pkt(smd_xprtp->in_pkt);
+		smd_xprtp->is_partial_in_pkt = 0;
+		pr_err("%s: %s channel reset\n",
+			__func__, smd_xprtp->xprt.name);
 		return;
 	}
-	spin_unlock_irqrestore(&modem_reset_lock, flags);
+	spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 
 	D("%s pkt_size: %d, read_avail: %d\n", __func__,
-		smd_cur_packet_size(smd_remote_xprt.channel),
-		smd_read_avail(smd_remote_xprt.channel));
-	while ((pkt_size = smd_cur_packet_size(smd_remote_xprt.channel)) &&
-		smd_read_avail(smd_remote_xprt.channel)) {
-		if (!is_partial_in_pkt) {
-			in_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
-			if (!in_pkt) {
+		smd_cur_packet_size(smd_xprtp->channel),
+		smd_read_avail(smd_xprtp->channel));
+	while ((pkt_size = smd_cur_packet_size(smd_xprtp->channel)) &&
+		smd_read_avail(smd_xprtp->channel)) {
+		if (!smd_xprtp->is_partial_in_pkt) {
+			smd_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						    GFP_KERNEL);
+			if (!smd_xprtp->in_pkt) {
 				pr_err("%s: Couldn't alloc rr_packet\n",
 					__func__);
 				return;
 			}
 
-			in_pkt->pkt_fragment_q = kmalloc(
-						  sizeof(struct sk_buff_head),
-						  GFP_KERNEL);
-			if (!in_pkt->pkt_fragment_q) {
+			smd_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (!smd_xprtp->in_pkt->pkt_fragment_q) {
 				pr_err("%s: Couldn't alloc pkt_fragment_q\n",
 					__func__);
-				kfree(in_pkt);
+				kfree(smd_xprtp->in_pkt);
 				return;
 			}
-			skb_queue_head_init(in_pkt->pkt_fragment_q);
-			is_partial_in_pkt = 1;
+			skb_queue_head_init(smd_xprtp->in_pkt->pkt_fragment_q);
+			smd_xprtp->is_partial_in_pkt = 1;
 			D("%s: Allocated rr_packet\n", __func__);
 		}
 
 		if (((pkt_size >= MIN_FRAG_SZ) &&
-		     (smd_read_avail(smd_remote_xprt.channel) < MIN_FRAG_SZ)) ||
+		     (smd_read_avail(smd_xprtp->channel) < MIN_FRAG_SZ)) ||
 		    ((pkt_size < MIN_FRAG_SZ) &&
-		     (smd_read_avail(smd_remote_xprt.channel) < pkt_size)))
+		     (smd_read_avail(smd_xprtp->channel) < pkt_size)))
 			return;
 
-		sz = smd_read_avail(smd_remote_xprt.channel);
+		sz = smd_read_avail(smd_xprtp->channel);
 		do {
 			ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
 			if (!ipc_rtr_pkt) {
 				if (sz <= (PAGE_SIZE/2)) {
-					queue_delayed_work(smd_xprt_workqueue,
-						   &work_read_data,
-						   msecs_to_jiffies(100));
+					queue_delayed_work(
+						smd_xprtp->smd_xprt_wq,
+						&smd_xprtp->read_work,
+						msecs_to_jiffies(100));
 					return;
 				}
 				sz = sz / 2;
 			}
 		} while (!ipc_rtr_pkt);
 
-		D("%s: Allocated the sk_buff of size %d\n",
-			__func__, sz);
+		D("%s: Allocated the sk_buff of size %d\n", __func__, sz);
 		data = skb_put(ipc_rtr_pkt, sz);
-		sz_read = smd_read(smd_remote_xprt.channel, data, sz);
+		sz_read = smd_read(smd_xprtp->channel, data, sz);
 		if (sz_read != sz) {
-			pr_err("%s: Couldn't read completely\n", __func__);
+			pr_err("%s: Couldn't read %s completely\n",
+				__func__, smd_xprtp->xprt.name);
 			kfree_skb(ipc_rtr_pkt);
-			release_pkt(in_pkt);
-			is_partial_in_pkt = 0;
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->is_partial_in_pkt = 0;
 			return;
 		}
-		skb_queue_tail(in_pkt->pkt_fragment_q, ipc_rtr_pkt);
-		in_pkt->length += sz_read;
+		skb_queue_tail(smd_xprtp->in_pkt->pkt_fragment_q, ipc_rtr_pkt);
+		smd_xprtp->in_pkt->length += sz_read;
 		if (sz_read != pkt_size)
-			is_partial_in_pkt = 1;
+			smd_xprtp->is_partial_in_pkt = 1;
 		else
-			is_partial_in_pkt = 0;
+			smd_xprtp->is_partial_in_pkt = 0;
 
-		if (!is_partial_in_pkt) {
+		if (!smd_xprtp->is_partial_in_pkt) {
 			D("%s: Packet size read %d\n",
-				__func__, in_pkt->length);
-			msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
-					   IPC_ROUTER_XPRT_EVENT_DATA,
-					   (void *)in_pkt);
-			release_pkt(in_pkt);
-			in_pkt = NULL;
+			  __func__, smd_xprtp->in_pkt->length);
+			msm_ipc_router_xprt_notify(&smd_xprtp->xprt,
+						IPC_ROUTER_XPRT_EVENT_DATA,
+						(void *)smd_xprtp->in_pkt);
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->in_pkt = NULL;
 		}
 	}
 }
@@ -265,7 +313,8 @@
 
 	msm_ipc_router_xprt_notify(xprt_work->xprt,
 				IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
-	D("%s: Notified IPC Router of OPEN Event\n", __func__);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	   __func__, xprt_work->xprt->name);
 	kfree(xprt_work);
 }
 
@@ -276,28 +325,34 @@
 
 	msm_ipc_router_xprt_notify(xprt_work->xprt,
 				IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
-	D("%s: Notified IPC Router of CLOSE Event\n", __func__);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	   __func__, xprt_work->xprt->name);
 	kfree(xprt_work);
 }
 
 static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
 {
 	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
 	struct msm_ipc_router_smd_xprt_work *xprt_work;
 
+	smd_xprtp = (struct msm_ipc_router_smd_xprt *)_dev;
+	if (!smd_xprtp)
+		return;
+
 	switch (event) {
 	case SMD_EVENT_DATA:
-		if (smd_read_avail(smd_remote_xprt.channel))
-			queue_delayed_work(smd_xprt_workqueue,
-					   &work_read_data, 0);
-		if (smd_write_avail(smd_remote_xprt.channel))
-			wake_up(&write_avail_wait_q);
+		if (smd_read_avail(smd_xprtp->channel))
+			queue_delayed_work(smd_xprtp->smd_xprt_wq,
+					   &smd_xprtp->read_work, 0);
+		if (smd_write_avail(smd_xprtp->channel))
+			wake_up(&smd_xprtp->write_avail_wait_q);
 		break;
 
 	case SMD_EVENT_OPEN:
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		modem_reset = 0;
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 0;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
 				    GFP_ATOMIC);
 		if (!xprt_work) {
@@ -305,16 +360,16 @@
 				__func__, event);
 			return;
 		}
-		xprt_work->xprt = &smd_remote_xprt.xprt;
+		xprt_work->xprt = &smd_xprtp->xprt;
 		INIT_WORK(&xprt_work->work, smd_xprt_open_event);
-		queue_work(smd_xprt_workqueue, &xprt_work->work);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
 		break;
 
 	case SMD_EVENT_CLOSE:
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		modem_reset = 1;
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
-		wake_up(&write_avail_wait_q);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 1;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		wake_up(&smd_xprtp->write_avail_wait_q);
 		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
 				    GFP_ATOMIC);
 		if (!xprt_work) {
@@ -322,9 +377,9 @@
 				__func__, event);
 			return;
 		}
-		xprt_work->xprt = &smd_remote_xprt.xprt;
+		xprt_work->xprt = &smd_xprtp->xprt;
 		INIT_WORK(&xprt_work->work, smd_xprt_close_event);
-		queue_work(smd_xprt_workqueue, &xprt_work->work);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
 		break;
 	}
 }
@@ -332,50 +387,93 @@
 static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
 {
 	int rc;
+	int id;		/*Index into the smd_xprt_cfg table*/
 
-	smd_xprt_workqueue = create_singlethread_workqueue("smd_xprt");
-	if (!smd_xprt_workqueue)
-		return -ENOMEM;
+	id = find_smd_xprt_cfg(pdev->name);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
 
-	smd_remote_xprt.xprt.name = "msm_ipc_router_smd_xprt";
-	smd_remote_xprt.xprt.link_id = 1;
-	smd_remote_xprt.xprt.read_avail = NULL;
-	smd_remote_xprt.xprt.read = NULL;
-	smd_remote_xprt.xprt.write_avail =
+	smd_remote_xprt[id].smd_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!smd_remote_xprt[id].smd_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
+	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.read_avail = NULL;
+	smd_remote_xprt[id].xprt.read = NULL;
+	smd_remote_xprt[id].xprt.write_avail =
 		msm_ipc_router_smd_remote_write_avail;
-	smd_remote_xprt.xprt.write = msm_ipc_router_smd_remote_write;
-	smd_remote_xprt.xprt.close = msm_ipc_router_smd_remote_close;
-	smd_remote_xprt.xprt.priv = NULL;
+	smd_remote_xprt[id].xprt.write = msm_ipc_router_smd_remote_write;
+	smd_remote_xprt[id].xprt.close = msm_ipc_router_smd_remote_close;
+	smd_remote_xprt[id].xprt.priv = NULL;
 
-	init_waitqueue_head(&write_avail_wait_q);
+	init_waitqueue_head(&smd_remote_xprt[id].write_avail_wait_q);
+	smd_remote_xprt[id].in_pkt = NULL;
+	smd_remote_xprt[id].is_partial_in_pkt = 0;
+	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
+	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
+	smd_remote_xprt[id].ss_reset = 0;
 
-	rc = smd_open("RPCRPY_CNTL", &smd_remote_xprt.channel, NULL,
-		      msm_ipc_router_smd_remote_notify);
+	rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
+				    smd_xprt_cfg[id].edge,
+				    &smd_remote_xprt[id].channel,
+				    &smd_remote_xprt[id],
+				    msm_ipc_router_smd_remote_notify);
 	if (rc < 0) {
-		destroy_workqueue(smd_xprt_workqueue);
+		pr_err("%s: Channel open failed for %s\n",
+			__func__, smd_xprt_cfg[id].ch_name);
+		destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
 		return rc;
 	}
 
-	smd_disable_read_intr(smd_remote_xprt.channel);
+	smd_disable_read_intr(smd_remote_xprt[id].channel);
 
 	smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
 
 	return 0;
 }
 
-static struct platform_driver msm_ipc_router_smd_remote_driver = {
-	.probe		= msm_ipc_router_smd_remote_probe,
-	.driver		= {
-			.name	= "RPCRPY_CNTL",
-			.owner	= THIS_MODULE,
+static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "RPCRPY_CNTL",
+				.owner	= THIS_MODULE,
+		},
+	},
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "IPCRTR",
+				.owner	= THIS_MODULE,
+		},
 	},
 };
 
 static int __init msm_ipc_router_smd_init(void)
 {
-	return platform_driver_register(&msm_ipc_router_smd_remote_driver);
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(msm_ipc_router_smd_remote_driver) != NUM_SMD_XPRTS);
+	BUG_ON(ARRAY_SIZE(smd_xprt_cfg) != NUM_SMD_XPRTS);
+	for (i = 0; i < NUM_SMD_XPRTS; i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_smd_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for"
+			       " xprt%d. Continuing...\n", __func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
 }
 
 module_init(msm_ipc_router_smd_init);
-MODULE_DESCRIPTION("RPC Router SMD XPRT");
+MODULE_DESCRIPTION("IPC Router SMD XPRT");
 MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index b75fb38..a2ec89b 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -33,6 +33,9 @@
 #define CPMR_ETMCLKEN		(0x8)
 
 
+uint32_t msm_jtag_save_cntr[NR_CPUS];
+uint32_t msm_jtag_restore_cntr[NR_CPUS];
+
 struct dbg_ctx {
 	uint8_t		arch;
 	bool		arch_supported;
@@ -1015,6 +1018,10 @@
 
 	cpu = raw_smp_processor_id();
 
+	msm_jtag_save_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
 	if (dbg.arch_supported)
 		dbg_save_state(cpu);
 	if (etm.arch_supported)
@@ -1027,6 +1034,10 @@
 
 	cpu = raw_smp_processor_id();
 
+	msm_jtag_restore_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
 	if (dbg.arch_supported)
 		dbg_restore_state(cpu);
 	if (etm.arch_supported)
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index 6e79dfe..3f56d1a 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -54,6 +54,7 @@
 	int nentries;
 	int size;
 	int enabled;
+	int initialized;
 	uint32_t filter;
 	int step_size;
 };
@@ -66,6 +67,7 @@
 
 struct msm_rtb_state msm_rtb = {
 	.filter = 1 << LOGK_LOGBUF,
+	.enabled = 1,
 };
 
 module_param_named(filter, msm_rtb.filter, uint, 0644);
@@ -73,7 +75,7 @@
 
 int msm_rtb_event_should_log(enum logk_event_type log_type)
 {
-	return msm_rtb.enabled &&
+	return msm_rtb.initialized && msm_rtb.enabled &&
 		((1 << log_type) & msm_rtb.filter);
 }
 EXPORT_SYMBOL(msm_rtb_event_should_log);
@@ -217,7 +219,7 @@
 #endif
 
 
-	msm_rtb.enabled = 1;
+	msm_rtb.initialized = 1;
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 534fc0e..8081b45 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -28,6 +28,8 @@
 #include "pm.h"
 
 #define MSM_CORE1_RESET		0xA8600590
+#define MSM_CORE1_STATUS_MSK	0x02800000
+
 /*
  * control for which core is the next to come out of the secondary
  * boot "holding pen"
@@ -80,20 +82,53 @@
 	spin_unlock(&boot_lock);
 }
 
+static int  __cpuinit msm8625_release_secondary(void)
+{
+	void __iomem *base_ptr;
+	int value = 0;
+	unsigned long timeout;
+
+	/*
+	 * loop to ensure that the GHS_STATUS_CORE1 bit in the
+	 * MPA5_STATUS_REG(0x3c) is set. The timeout for the while
+	 * loop can be set as 20us as of now
+	 */
+	timeout = jiffies + usecs_to_jiffies(20);
+	while (time_before(jiffies, timeout)) {
+		value = __raw_readl(MSM_CFG_CTL_BASE + 0x3c);
+		if ((value & MSM_CORE1_STATUS_MSK) ==
+				MSM_CORE1_STATUS_MSK)
+			break;
+			udelay(1);
+	}
+
+	if (!value) {
+		pr_err("Core 1 cannot be brought out of Reset!!!\n");
+		return -ENODEV;
+	}
+
+	base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+	if (!base_ptr)
+		return -ENODEV;
+	/* Reset core 1 out of reset */
+	__raw_writel(0x0, base_ptr);
+	mb();
+
+	iounmap(base_ptr);
+
+	return 0;
+}
+
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
 	unsigned long timeout;
-	void __iomem *base_ptr;
 
 	if (cold_boot_done == false) {
-		base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
-		if (!base_ptr)
+		if (msm8625_release_secondary()) {
+			pr_err("Failed to release secondary core\n");
 			return -ENODEV;
-		/* Reset core 1 out of reset */
-		__raw_writel(0x0, base_ptr);
-		mb();
+		}
 		cold_boot_done = true;
-		iounmap(base_ptr);
 	}
 
 	/*
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 33c5a53..31a54b7 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -3,7 +3,7 @@
  * Register/Interrupt access for userspace aDSP library.
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Iliyan Malchev <ibm@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -58,8 +58,6 @@
 #include <mach/msm_adsp.h>
 #include "adsp.h"
 
-#define INT_ADSP INT_ADSP_A9_A11
-
 static struct adsp_info adsp_info;
 static struct msm_rpc_endpoint *rpc_cb_server_client;
 static struct msm_adsp_module *adsp_modules;
@@ -280,6 +278,7 @@
 	int rc = 0;
 	static uint32_t init_info_cmd_sent;
 
+	mutex_lock(&adsp_info.lock);
 	if (!init_info_cmd_sent) {
 		init_waitqueue_head(&adsp_info.init_info_wait);
 		msm_get_init_info();
@@ -288,10 +287,13 @@
 			5 * HZ);
 		if (!rc) {
 			MM_ERR("INIT_INFO failed\n");
+			mutex_unlock(&adsp_info.lock);
 			return -ETIMEDOUT;
+
 		}
 		init_info_cmd_sent++;
 	}
+	mutex_unlock(&adsp_info.lock);
 
 	module = find_adsp_module_by_name(&adsp_info, name);
 	if (!module)
@@ -1016,16 +1018,49 @@
 
 int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
 {
+	if (!module)
+		return -EINVAL;
+
 	if (module->clk && clk_rate)
 		return clk_set_rate(module->clk, clk_rate);
 
 	return -EINVAL;
 }
 
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg)
+{
+	unsigned long flags;
+	void (*func)(void *, size_t);
+
+	if (!mod)
+		return -EINVAL;
+
+	if (event_size == sizeof(uint32_t))
+		func = read_event_32;
+	else if (event_size == sizeof(uint16_t))
+		func = read_event_16;
+	else
+		return -EINVAL;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+	read_event_addr = msg;
+	mod->ops->event(data, event_id, event_length, func);
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return 0;
+}
+
 int msm_adsp_enable(struct msm_adsp_module *module)
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	MM_INFO("enable '%s'state[%d] id[%d]\n",
 				module->name, module->state, module->id);
 
@@ -1053,7 +1088,7 @@
 
 		mutex_lock(&adsp_open_lock);
 		if (adsp_open_count++ == 0) {
-			enable_irq(INT_ADSP);
+			enable_irq(adsp_info.int_adsp);
 			prevent_suspend();
 		}
 		mutex_unlock(&adsp_open_lock);
@@ -1078,6 +1113,9 @@
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	mutex_lock(&module->lock);
 
 	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
@@ -1092,6 +1130,9 @@
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	switch (module->state) {
 	case ADSP_STATE_DISABLED:
 		MM_DBG("module '%s' already disabled\n", module->name);
@@ -1105,7 +1146,7 @@
 			clk_disable(module->clk);
 		mutex_lock(&adsp_open_lock);
 		if (--adsp_open_count == 0) {
-			disable_irq(INT_ADSP);
+			disable_irq(adsp_info.int_adsp);
 			allow_suspend();
 			MM_DBG("disable interrupt\n");
 		}
@@ -1117,6 +1158,10 @@
 int msm_adsp_disable(struct msm_adsp_module *module)
 {
 	int rc;
+
+	if (!module)
+		return -EINVAL;
+
 	MM_INFO("disable '%s'\n", module->name);
 	mutex_lock(&module->lock);
 	rc = msm_adsp_disable_locked(module);
@@ -1130,8 +1175,11 @@
 	unsigned count;
 	int rc, i;
 
-	if (pdev->id != (rpc_adsp_rtos_atom_vers & RPC_VERSION_MAJOR_MASK))
-		return -EINVAL;
+	adsp_info.int_adsp = platform_get_irq(pdev, 0);
+	if (adsp_info.int_adsp < 0) {
+		MM_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
 
 	wake_lock_init(&adsp_wake_lock, WAKE_LOCK_SUSPEND, "adsp");
 	adsp_info.init_info_ptr = kzalloc(
@@ -1157,12 +1205,13 @@
 
 	spin_lock_init(&adsp_cmd_lock);
 	spin_lock_init(&adsp_write_lock);
+	mutex_init(&adsp_info.lock);
 
-	rc = request_irq(INT_ADSP, adsp_irq_handler, IRQF_TRIGGER_RISING,
-			 "adsp", 0);
+	rc = request_irq(adsp_info.int_adsp, adsp_irq_handler,
+			IRQF_TRIGGER_RISING, "adsp", 0);
 	if (rc < 0)
 		goto fail_request_irq;
-	disable_irq(INT_ADSP);
+	disable_irq(adsp_info.int_adsp);
 
 	rpc_cb_server_client = msm_rpc_open();
 	if (IS_ERR(rpc_cb_server_client)) {
@@ -1214,8 +1263,8 @@
 	msm_rpc_close(rpc_cb_server_client);
 	rpc_cb_server_client = NULL;
 fail_rpc_open:
-	enable_irq(INT_ADSP);
-	free_irq(INT_ADSP, 0);
+	enable_irq(adsp_info.int_adsp);
+	free_irq(adsp_info.int_adsp, 0);
 fail_request_irq:
 	kfree(adsp_modules);
 	kfree(adsp_info.init_info_ptr);
@@ -1344,7 +1393,7 @@
 	},
 };
 
-static char msm_adsp_driver_name[] = "rs00000000";
+static const char msm_adsp_driver_name[] = "msm_adsp";
 
 #ifdef CONFIG_DEBUG_FS
 static const struct file_operations adsp_debug_fops = {
@@ -1383,9 +1432,6 @@
 	rpc_adsp_rtos_mtoa_vers_comp = 0x00030001;
 #endif
 
-	snprintf(msm_adsp_driver_name, sizeof(msm_adsp_driver_name),
-		"rs%08x",
-		rpc_adsp_rtos_atom_prog);
 	msm_adsp_driver.driver.name = msm_adsp_driver_name;
 	rc = platform_driver_register(&msm_adsp_driver);
 	MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 0ef27b9..0f16111 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/qdsp5/adsp.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. All rights reserved.
  * Author: Iliyan Malchev <ibm@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -117,6 +117,10 @@
 	struct adsp_rtos_mp_mtoa_init_info_type	*init_info_ptr;
 	wait_queue_head_t	init_info_wait;
 	unsigned 		init_info_state;
+	struct mutex lock;
+
+	/* Interrupt value */
+	int int_adsp;
 };
 
 #define RPC_ADSP_RTOS_ATOM_NULL_PROC 0
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 5e1e655..de756eb 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -298,6 +298,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -672,24 +673,31 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static int audaac_validate_usr_config(struct msm_audio_aac_config *config)
@@ -990,7 +998,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index c9e60d8..456a8ff 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -2,7 +2,7 @@
  *
  * aac audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_aac_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -320,9 +320,10 @@
 
 		audaac_in_dsp_enable(audio, 0);
 
-		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -697,21 +698,23 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audaac_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audaac_out_flush(audio);
+	audaac_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audaac_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audaac_in_flush(struct audio_aac_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
@@ -720,6 +723,7 @@
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -729,15 +733,18 @@
 static void audaac_out_flush(struct audio_aac_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -777,7 +784,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audaac_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 476a63d..d66a270 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * amrnb audio decoder device
  *
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -302,6 +302,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -628,24 +629,31 @@
 
 static void audamrnb_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audamrnb_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audamrnb_ioport_reset(struct audio *audio)
@@ -876,7 +884,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audamrnb_disable(audio);
-		audio->stopped = 1;
 		audamrnb_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index e811731..b566c60 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -6,7 +6,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -299,6 +299,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -616,25 +617,32 @@
 
 static void audamrwb_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audamrwb_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audamrwb_ioport_reset(struct audio *audio)
@@ -865,7 +873,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audamrwb_disable(audio);
-		audio->stopped = 1;
 		audamrwb_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 3c39b6d..86035db 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/audio_evrc.c
  *
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This code also borrows from audio_aac.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -291,6 +291,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -615,24 +616,30 @@
 
 static void audevrc_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audevrc_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
-
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audevrc_ioport_reset(struct audio *audio)
@@ -863,7 +870,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audevrc_disable(audio);
-		audio->stopped = 1;
 		audevrc_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 7a5536a..0bdbf5d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -2,7 +2,7 @@
  *
  * evrc audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -281,6 +281,8 @@
 		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -655,21 +657,23 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audevrc_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audevrc_out_flush(audio);
+	audevrc_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audevrc_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audevrc_in_flush(struct audio_evrc_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
@@ -678,6 +682,7 @@
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -687,15 +692,18 @@
 static void audevrc_out_flush(struct audio_evrc_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -735,7 +743,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audevrc_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index c4b464a..f6fa62a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -368,6 +368,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -853,12 +854,16 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -885,13 +890,15 @@
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
-
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -1366,7 +1373,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 7c56037..7d33e05 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -247,6 +247,7 @@
 
 		audpp_disable(-1, audio);
 
+		audio->stopped = 1;
 		wake_up(&audio->wait);
 		audmgr_disable(&audio->audmgr);
 		audio->out_needed = 0;
@@ -519,7 +520,6 @@
 		break;
 	case AUDIO_STOP:
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		break;
 	case AUDIO_FLUSH:
 		if (audio->stopped) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 02103fc..6468e93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -1,7 +1,7 @@
 
 /* audio_pcm.c - pcm audio decoder driver
  *
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 decoder driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -336,6 +336,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
@@ -639,12 +640,16 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -1041,7 +1046,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 81813a0..16c70ce 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -218,6 +218,7 @@
 
 		audpcm_in_dsp_enable(audio, 0);
 
+		audio->stopped = 1;
 		wake_up(&audio->wait);
 
 		msm_adsp_disable(audio->audrec);
@@ -613,7 +614,6 @@
 	}
 	case AUDIO_STOP:
 		rc = audpcm_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	case AUDIO_FLUSH:
 		if (audio->stopped) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index b12e713..2be5144 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -2,7 +2,7 @@
  *
  * qcelp 13k audio decoder device
  *
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on audio_mp3.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -288,6 +288,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -612,23 +613,30 @@
 
 static void audqcelp_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audqcelp_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audqcelp_ioport_reset(struct audio *audio)
@@ -859,7 +867,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audqcelp_disable(audio);
-		audio->stopped = 1;
 		audqcelp_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index a339825..a79f721 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -2,7 +2,7 @@
  *
  * qcelp audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -279,9 +279,10 @@
 
 		audqcelp_in_dsp_enable(audio, 0);
 
-		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -657,29 +658,32 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audqcelp_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audqcelp_out_flush(audio);
+	audqcelp_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audqcelp_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audqcelp_in_flush(struct audio_qcelp_in *audio)
 {
 	int i;
+	unsigned long flags;
 
+	audio->eos_ack = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->dsp_cnt = 0;
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
-	audio->eos_ack = 0;
 	for (i = FRAME_NUM-1; i >= 0; i--) {
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -689,15 +693,18 @@
 static void audqcelp_out_flush(struct audio_qcelp_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -737,7 +744,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audqcelp_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index b7e8e1c..7a962b2 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -266,7 +266,9 @@
 		audio->in[index].used = 0;
 
 	audio->read_next = 0;
+	mutex_lock(&audio->dsp_lock);
 	audio->fill_next = 0;
+	mutex_unlock(&audio->dsp_lock);
 }
 
 static void audvoicememo_ioport_reset(struct audio_voicememo *audio)
@@ -387,6 +389,7 @@
 		rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
 		wait_event_timeout(audio->wait, audio->stopped == 0,
 				1 * HZ);
+		audio->stopped = 1;
 		wake_up(&audio->read_wait);
 		audmgr_disable(&audio->audmgr);
 		audio->enabled = 0;
@@ -536,12 +539,14 @@
 					callback time\n");
 		else if (rec_status == RPC_VOC_REC_STAT_AUTO_STOP) {
 			MM_DBG(" Voice Record AUTO STOP\n");
+			mutex_lock(&audio->lock);
+			audio->stopped = 1;
 			wake_up(&audio->read_wait);
 			audmgr_disable(&audio->audmgr);
-			audio->stopped = 1;
 			audvoicememo_ioport_reset(audio);
 			audio->stopped = 0;
 			audio->enabled = 0;
+			mutex_unlock(&audio->lock);
 		}
 			break;
 		}
@@ -648,7 +653,6 @@
 	case AUDIO_STOP: {
 			MM_DBG("AUDIO_STOP\n");
 			rc = audvoicememo_disable(audio);
-			audio->stopped = 1;
 			audvoicememo_ioport_reset(audio);
 			audio->stopped = 0;
 			MM_DBG("AUDIO_STOP rc %d\n", rc);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index cf2ade4..674ee4f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -1,6 +1,6 @@
 /* audio_wma.c - wma audio decoder driver
  *
- * Copyright (c) 2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -306,6 +306,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -659,11 +660,15 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -671,11 +676,15 @@
 {
 	uint8_t index;
 
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -905,7 +914,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index d9b384a..c2a0b93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -301,6 +301,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -648,23 +649,30 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -894,7 +902,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index 3e834d8..2dbb5dc0 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -4,7 +4,7 @@
  * common code to deal with the AUDPP dsp task (audio postproc)
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, 2012 Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -124,6 +124,8 @@
 	uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
 	struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
 
+	spinlock_t avsync_lock;
+
 	wait_queue_head_t event_wait;
 };
 
@@ -237,13 +239,24 @@
 	}
 }
 
+static void audpp_fake_event(struct audpp_state *audpp, int id,
+			     unsigned event, unsigned arg)
+{
+	uint16_t msg[1];
+	msg[0] = arg;
+	audpp->func[id] (audpp->private[id], event, msg);
+}
+
 static void audpp_dsp_event(void *data, unsigned id, size_t len,
 			    void (*getevent) (void *ptr, size_t len))
 {
 	struct audpp_state *audpp = data;
+	unsigned long flags;
 	uint16_t msg[8];
+	int cid = 0;
 
 	if (id == AUDPP_MSG_AVSYNC_MSG) {
+		spin_lock_irqsave(&audpp->avsync_lock, flags);
 		getevent(audpp->avsync, sizeof(audpp->avsync));
 
 		/* mask off any channels we're not watching to avoid
@@ -252,6 +265,7 @@
 		 * we next read...
 		 */
 		audpp->avsync[0] &= audpp->avsync_mask;
+		spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 		return;
 	}
 
@@ -278,13 +292,28 @@
 	case AUDPP_MSG_CFG_MSG:
 		if (msg[0] == AUDPP_MSG_ENA_ENA) {
 			MM_INFO("ENABLE\n");
-			audpp->enabled = 1;
-			audpp_broadcast(audpp, id, msg);
+			if (!audpp->enabled) {
+				audpp->enabled = 1;
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_ENA);
+			}
+
 		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
-			MM_INFO("DISABLE\n");
-			audpp->enabled = 0;
-			wake_up(&audpp->event_wait);
-			audpp_broadcast(audpp, id, msg);
+			if (audpp->open_count == 0) {
+				MM_INFO("DISABLE\n");
+				audpp->enabled = 0;
+				wake_up(&audpp->event_wait);
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_DIS);
+				audpp->func[cid] = NULL;
+				audpp->private[cid] = NULL;
+			}
 		} else {
 			MM_ERR("invalid config msg %d\n", msg[0]);
 		}
@@ -307,17 +336,10 @@
 	.event = audpp_dsp_event,
 };
 
-static void audpp_fake_event(struct audpp_state *audpp, int id,
-			     unsigned event, unsigned arg)
-{
-	uint16_t msg[1];
-	msg[0] = arg;
-	audpp->func[id] (audpp->private[id], event, msg);
-}
-
 int audpp_enable(int id, audpp_event_func func, void *private)
 {
 	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t msg[8];
 	int res = 0;
 
 	if (id < -1 || id > 4)
@@ -350,12 +372,15 @@
 		msm_adsp_enable(audpp->mod);
 		audpp_dsp_config(1);
 	} else {
-		unsigned long flags;
-		local_irq_save(flags);
-		if (audpp->enabled)
-			audpp_fake_event(audpp, id,
-					 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
-		local_irq_restore(flags);
+		if (audpp->enabled) {
+			msg[0] = AUDPP_MSG_ENA_ENA;
+			msg[1] = id;
+			res = msm_adsp_generate_event(audpp, audpp->mod,
+					 AUDPP_MSG_CFG_MSG, sizeof(msg),
+					 sizeof(uint16_t), (void *)msg);
+			if (res < 0)
+				goto out;
+		}
 	}
 
 	res = 0;
@@ -368,7 +393,7 @@
 void audpp_disable(int id, void *private)
 {
 	struct audpp_state *audpp = &the_audpp_state;
-	unsigned long flags;
+	uint16_t msg[8];
 	int rc;
 
 	if (id < -1 || id > 4)
@@ -384,11 +409,13 @@
 	if (audpp->private[id] != private)
 		goto out;
 
-	local_irq_save(flags);
-	audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
-	audpp->func[id] = NULL;
-	audpp->private[id] = NULL;
-	local_irq_restore(flags);
+	msg[0] = AUDPP_MSG_ENA_DIS;
+	msg[1] = id;
+	rc = msm_adsp_generate_event(audpp, audpp->mod,
+				 AUDPP_MSG_CFG_MSG, sizeof(msg),
+				 sizeof(uint16_t), (void *)msg);
+	if (rc < 0)
+		goto out;
 
 	if (--audpp->open_count == 0) {
 		MM_DBG("disable\n");
@@ -420,13 +447,13 @@
 	if (BAD_ID(id))
 		return;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
 	if (rate)
 		the_audpp_state.avsync_mask |= (1 << id);
 	else
 		the_audpp_state.avsync_mask &= (~(1 << id));
 	the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
 
 	cmd.cmd_id = AUDPP_CMD_AVSYNC;
 	cmd.object_number = id;
@@ -438,7 +465,8 @@
 
 unsigned audpp_avsync_sample_count(int id)
 {
-	uint16_t *avsync = the_audpp_state.avsync;
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
 	unsigned val;
 	unsigned long flags;
 	unsigned mask;
@@ -448,12 +476,12 @@
 
 	mask = 1 << id;
 	id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
-	local_irq_save(flags);
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
 	if (avsync[0] & mask)
 		val = (avsync[id] << 16) | avsync[id + 1];
 	else
 		val = 0;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 
 	return val;
 }
@@ -461,7 +489,8 @@
 
 unsigned audpp_avsync_byte_count(int id)
 {
-	uint16_t *avsync = the_audpp_state.avsync;
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
 	unsigned val;
 	unsigned long flags;
 	unsigned mask;
@@ -471,12 +500,12 @@
 
 	mask = 1 << id;
 	id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
-	local_irq_save(flags);
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
 	if (avsync[0] & mask)
 		val = (avsync[id] << 16) | avsync[id + 1];
 	else
 		val = 0;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 
 	return val;
 }
@@ -826,6 +855,8 @@
 
 	init_waitqueue_head(&audpp->event_wait);
 
+	spin_lock_init(&audpp->avsync_lock);
+
 	for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
 		audpp->dec_info_table[idx].codec = -1;
 		audpp->dec_info_table[idx].pid = 0;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index 3225d61..599198e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -45,7 +45,7 @@
 #include <mach/debug_mm.h>
 #include <linux/fs.h>
 
-#define MAX_BUF 3
+#define MAX_BUF 4
 #define BUFSZ (524288)
 
 #define AUDDEC_DEC_PCM 0
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 4128e3a..0bc080c 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -66,6 +66,7 @@
 	DGT_CLK_CTL_DIV_3 = 2,
 	DGT_CLK_CTL_DIV_4 = 3,
 };
+#define TIMER_STATUS            0x0088
 #define TIMER_ENABLE_EN              1
 #define TIMER_ENABLE_CLR_ON_MATCH_EN 2
 
@@ -112,6 +113,7 @@
 	uint32_t                    index;
 	void __iomem                *global_counter;
 	void __iomem                *local_counter;
+	uint32_t		    status_mask;
 	union {
 		struct clock_event_device		*evt;
 		struct clock_event_device __percpu	**percpu_evt;
@@ -1001,15 +1003,21 @@
 		dgt->regbase = MSM_TMR_BASE + 0x10;
 	} else if (cpu_is_fsm9xxx())
 		dgt->freq = 4800000;
-	else if (cpu_is_msm7x30() || cpu_is_msm8x55())
+	else if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		dgt->freq = 6144000;
-	else if (cpu_is_msm8x60()) {
+	} else if (cpu_is_msm8x60()) {
 		global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		dgt->freq = 6750000;
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 	} else if (cpu_is_msm9615()) {
 		dgt->freq = 6750000;
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		gpt->freq = 32765;
 		gpt_hz = 32765;
 		sclk_hz = 32765;
@@ -1019,6 +1027,8 @@
 		global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
 		dgt->freq = 6750000;
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
 		gpt->freq = 32765;
 		gpt_hz = 32765;
 		sclk_hz = 32765;
@@ -1042,8 +1052,7 @@
 		struct clock_event_device *ce = &clock->clockevent;
 		struct clocksource *cs = &clock->clocksource;
 		__raw_writel(0, clock->regbase + TIMER_ENABLE);
-		__raw_writel(1, clock->regbase + TIMER_CLEAR);
-		__raw_writel(0, clock->regbase + TIMER_COUNT_VAL);
+		__raw_writel(0, clock->regbase + TIMER_CLEAR);
 		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
 
 		if ((clock->freq << clock->shift) == gpt_hz) {
@@ -1105,6 +1114,11 @@
 		if (chip && chip->irq_mask)
 			chip->irq_mask(irq_get_irq_data(clock->irq));
 
+		if (clock->status_mask)
+			while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+			       clock->status_mask)
+				;
+
 		clockevents_register_device(ce);
 	}
 	msm_sched_clock_init();
@@ -1136,6 +1150,10 @@
 		__raw_writel(0, clock->regbase + TIMER_CLEAR);
 		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
 		__get_cpu_var(first_boot) = false;
+		if (clock->status_mask)
+			while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+			       clock->status_mask)
+				;
 	}
 	evt->irq = clock->irq;
 	evt->name = "local_timer";
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 8dcce03..321abe8 100755
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1139,3 +1139,4 @@
 mpq8064_hrd		MACH_MPQ8064_HRD	MPQ8064_HRD		3994
 mpq8064_dtv		MACH_MPQ8064_DTV	MPQ8064_DTV		3995
 msm7627a_qrd3		MACH_MSM7627A_QRD3	MSM7627A_QRD3		4005
+msm8625_surf		MACH_MSM8625_SURF	MSM8625_SURF		4037
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 6525d9b..24e8efe 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -59,7 +59,9 @@
 	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
 	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
 	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
-	0x2750, 0x2756, 0x2760, 0x2760,
+	0x2750, 0x2756, 0x2760, 0x2760, 0x300C, 0x300E, 0x301C, 0x301D,
+	0x302A, 0x302A, 0x302C, 0x302D, 0x3030, 0x3031, 0x3034, 0x3036,
+	0x303C, 0x303C, 0x305E, 0x305F,
 };
 
 const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index 1dffc32..f99462e 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -163,6 +163,13 @@
 
 #define CP_LOAD_STATE 0x30 /* load high level sequencer command */
 
+/* Conditionally load a IB based on a flag */
+#define CP_COND_INDIRECT_BUFFER_PFE 0x3A /* prefetch enabled */
+#define CP_COND_INDIRECT_BUFFER_PFD 0x32 /* prefetch disabled */
+
+/* Load a buffer with pre-fetch enabled */
+#define CP_INDIRECT_BUFFER_PFE 0x3F
+
 #define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
 #define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
 #define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index cc3f3e7..a4899a2 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -45,11 +45,19 @@
 	int index;
 	void *ptr;
 
-	/* Go through the list and see that object has already been seen */
+	/*
+	 * Sometimes IBs can be reused in the same dump.  Because we parse from
+	 * oldest to newest, if we come across an IB that has already been used,
+	 * assume that it has been reused and update the list with the newest
+	 * size.
+	 */
+
 	for (index = 0; index < objbufptr; index++) {
 		if (objbuf[index].gpuaddr == gpuaddr &&
-			objbuf[index].ptbase == ptbase)
-			return;
+			objbuf[index].ptbase == ptbase) {
+				objbuf[index].dwords = dwords;
+				return;
+			}
 	}
 
 	if (objbufptr == SNAPSHOT_OBJ_BUFSIZE) {
@@ -77,6 +85,34 @@
 	objbuf[objbufptr++].ptr = ptr;
 }
 
+/*
+ * Return a 1 if the specified object is already on the list of buffers
+ * to be dumped
+ */
+
+static int find_object(int type, unsigned int gpuaddr, unsigned int ptbase)
+{
+	int index;
+
+	for (index = 0; index < objbufptr; index++) {
+		if (objbuf[index].gpuaddr == gpuaddr &&
+			objbuf[index].ptbase == ptbase &&
+			objbuf[index].type == type)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Return 1 if the packet starting at ptr is an indirect buffer of any kind */
+static inline int packet_is_buffer(unsigned int *ptr)
+{
+	return (*ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2) ||
+		*ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2) ||
+		*ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFE, 2) ||
+		*ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFD, 2));
+}
+
 /* Snapshot the istore memory */
 static int snapshot_istore(struct kgsl_device *device, void *snapshot,
 	int remain, void *priv)
@@ -113,6 +149,7 @@
 	unsigned int rbbase, ptbase, rptr, *rbptr;
 	int start, stop, index;
 	int numitems, size;
+	int parse_ibs = 0, ib_parse_start;
 
 	/* Get the GPU address of the ringbuffer */
 	kgsl_regread(device, REG_CP_RB_BASE, &rbbase);
@@ -158,9 +195,53 @@
 	header->rbsize = rb->sizedwords;
 	header->count = numitems;
 
-	index = start;
+	/*
+	 * We can only reliably dump IBs from the beginning of the context,
+	 * and it turns out that for the vast majority of the time we really
+	 * only care about the current context when it comes to diagnosing
+	 * a hang. So, with an eye to limiting the buffer dumping to what is
+	 * really useful find the beginning of the context and only dump
+	 * IBs from that point
+	 */
+
+	index = rptr;
+	ib_parse_start = start;
 	rbptr = rb->buffer_desc.hostptr;
 
+	while (index != start) {
+		index--;
+
+		if (index < 0) {
+			/*
+			 * The marker we are looking for is 2 dwords long, so
+			 * when wrapping, go back 2 from the end so we don't
+			 * access out of range in the if statement below
+			 */
+			index = rb->sizedwords - 2;
+
+			/*
+			 * Account for the possibility that start might be at
+			 * rb->sizedwords - 1
+			 */
+
+			if (start == rb->sizedwords - 1)
+				break;
+		}
+
+		/*
+		 * Look for a NOP packet with the context switch identifier in
+		 * the second dword
+		 */
+
+		if (rbptr[index] == cp_nop_packet(1) &&
+			rbptr[index + 1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+				ib_parse_start = index;
+				break;
+		}
+	}
+
+	index = start;
+
 	/*
 	 * Loop through the RB, copying the data and looking for indirect
 	 * buffers and MMU pagetable changes
@@ -169,15 +250,18 @@
 	while (index != rb->wptr) {
 		*data = rbptr[index];
 
-		if (rbptr[index] == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2))
+		/* Only parse IBs between the context start and the rptr */
+
+		if (index == ib_parse_start)
+			parse_ibs = 1;
+
+		if (index == rptr)
+			parse_ibs = 0;
+
+		if (parse_ibs && packet_is_buffer(&rbptr[index]))
 			push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
 				rbptr[index + 1], rbptr[index + 2]);
 
-		/*
-		 * FIXME: Handle upcoming MMU pagetable changes, but only
-		 * between the rptr and the wptr
-		 */
-
 		index = index + 1;
 
 		if (index == rb->sizedwords)
@@ -228,10 +312,9 @@
 		*dst = *src;
 		/* If another IB is discovered, then push it on the list too */
 
-		if (*src == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+		if (packet_is_buffer(src))
 			push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
 				*(src + 1), *(src + 2));
-		}
 
 		src++;
 		dst++;
@@ -288,22 +371,45 @@
 		snapshot, remain, snapshot_rb, NULL);
 
 	/*
-	 * Make sure that the IBs described in the CP registers are on the
-	 * list of objects
+	 * Make sure that the last IB1 that was being executed is dumped.
+	 * Since this was the last IB1 that was processed, we should have
+	 * already added it to the list during the ringbuffer parse but we
+	 * want to be double plus sure.
 	 */
+
 	kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
 	kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);
 
-	if (ibsize)
+	/*
+	 * The problem is that IB size from the register is the unprocessed size
+	 * of the buffer not the original size, so if we didn't catch this
+	 * buffer being directly used in the RB, then we might not be able to
+	 * dump the whle thing. Print a warning message so we can try to
+	 * figure how often this really happens.
+	 */
+
+	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
 		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
 			ibbase, ibsize);
+		KGSL_DRV_ERR(device, "CP_IB1_BASE not found in the ringbuffer. "
+			"Dumping %x dwords of the buffer.\n", ibsize);
+	}
 
 	kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
 	kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);
 
-	if (ibsize)
+	/*
+	 * Add the last parsed IB2 to the list. The IB2 should be found as we
+	 * parse the objects below, but we try to add it to the list first, so
+	 * it too can be parsed.  Don't print an error message in this case - if
+	 * the IB2 is found during parsing, the list will be updated with the
+	 * correct size.
+	 */
+
+	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
 		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
 			ibbase, ibsize);
+	}
 
 	/*
 	 * Go through the list of found objects and dump each one.  As the IBs
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 1c4f616..5ec2932 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -2582,6 +2582,7 @@
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
 	int retval = 0;
+	int cnt = 0;
 	unsigned char xfr_buf[XFR_REG_NUM];
 	signed char cRmssiThreshold;
 	signed char ioc;
@@ -2712,6 +2713,69 @@
 		ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
 			IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
 		break;
+	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
+		size = 0x04;
+		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+		xfr_buf[1] = ON_CHANNEL_TH_MSB;
+		xfr_buf[2] = ON_CHANNEL_TH_LSB;
+		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+		if (retval < 0) {
+			pr_err("%s: Failed to write\n", __func__);
+			return retval;
+		}
+		/*Wait for the XFR interrupt */
+		msleep(TAVARUA_DELAY*10);
+		retval = tavarua_read_registers(radio, XFRDAT0, 4);
+		if (retval < 0) {
+			pr_err("%s: On Ch. DET: Read failure\n", __func__);
+			return retval;
+		}
+		for (cnt = 0; cnt < 4; cnt++)
+			FMDBG("On-Channel data set is : 0x%x\t",
+				(int)radio->registers[XFRDAT0+cnt]);
+
+		ctrl->value =	LSH_DATA(radio->registers[XFRDAT0],   24) |
+				LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+				LSH_DATA(radio->registers[XFRDAT0+2],  8) |
+				(radio->registers[XFRDAT0+3]);
+		FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
+		break;
+	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
+		size = 0x04;
+		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+		xfr_buf[1] = OFF_CHANNEL_TH_MSB;
+		xfr_buf[2] = OFF_CHANNEL_TH_LSB;
+		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+		if (retval < 0) {
+			pr_err("%s: Failed to write\n", __func__);
+			return retval;
+		}
+		/*Wait for the XFR interrupt */
+		msleep(TAVARUA_DELAY*10);
+		retval = tavarua_read_registers(radio, XFRDAT0, 4);
+		if (retval < 0) {
+			pr_err("%s: Off Ch. DET: Read failure\n", __func__);
+			return retval;
+		}
+		for (cnt = 0; cnt < 4; cnt++)
+			FMDBG("Off-channel data set is : 0x%x\t",
+				(int)radio->registers[XFRDAT0+cnt]);
+
+		ctrl->value =	LSH_DATA(radio->registers[XFRDAT0],   24) |
+				LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+				LSH_DATA(radio->registers[XFRDAT0+2],  8) |
+				(radio->registers[XFRDAT0+3]);
+		FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
+		break;
+	/*
+	 * These IOCTL's are place holders to keep the
+	 * driver compatible with change in frame works for IRIS
+	 */
+	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+	case V4L2_CID_PRIVATE_SINR_SAMPLES:
+	case V4L2_CID_PRIVATE_IRIS_GET_SINR:
+		retval = 0;
+		break;
 	default:
 		retval = -EINVAL;
 	}
@@ -3090,7 +3154,7 @@
 		SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
 					IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
 		break;
-	case V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD:
+	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
 		size = 0x04;
 		/* Poking the value of ON Channel Threshold value */
 		xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3110,39 +3174,13 @@
 		retval = tavarua_write_registers(radio, XFRCTRL,
 				xfr_buf, size+3);
 		if (retval < 0) {
-			FMDBG("Failed to write\n");
-			return retval;
-		}
-		/*Wait for the XFR interrupt */
-		msleep(TAVARUA_DELAY*15);
-
-		for (cnt = 0; cnt < 5; cnt++) {
-			xfr_buf[cnt] = 0;
-			radio->registers[XFRDAT0+cnt] = 0x0;
-		}
-
-		/* Peeking Regs 0x88C2-0x88C4 */
-		size = 0x04;
-		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
-		xfr_buf[1] = ON_CHANNEL_TH_MSB;
-		xfr_buf[2] = ON_CHANNEL_TH_LSB;
-		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
-		if (retval < 0) {
 			pr_err("%s: Failed to write\n", __func__);
 			return retval;
 		}
 		/*Wait for the XFR interrupt */
 		msleep(TAVARUA_DELAY*10);
-		retval = tavarua_read_registers(radio, XFRDAT0, 4);
-		if (retval < 0) {
-			pr_err("%s: On Ch. DET: Read failure\n", __func__);
-			return retval;
-		}
-		for (cnt = 0; cnt < 4; cnt++)
-			FMDBG("On-Channel data set is : 0x%x\t",
-				(int)radio->registers[XFRDAT0+cnt]);
 		break;
-	case V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD:
+	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
 		size = 0x04;
 		/* Poking the value of OFF Channel Threshold value */
 		xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3167,32 +3205,6 @@
 		}
 		/*Wait for the XFR interrupt */
 		msleep(TAVARUA_DELAY*10);
-
-		for (cnt = 0; cnt < 5; cnt++) {
-			xfr_buf[cnt] = 0;
-			radio->registers[XFRDAT0+cnt] = 0x0;
-		}
-
-		/* Peeking Regs 0x88C2-0x88C4 */
-		size = 0x04;
-		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
-		xfr_buf[1] = OFF_CHANNEL_TH_MSB;
-		xfr_buf[2] = OFF_CHANNEL_TH_LSB;
-		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
-		if (retval < 0) {
-			pr_err("%s: Failed to write\n", __func__);
-			return retval;
-		}
-		/*Wait for the XFR interrupt */
-		msleep(TAVARUA_DELAY*10);
-		retval = tavarua_read_registers(radio, XFRDAT0, 4);
-		if (retval < 0) {
-			pr_err("%s: Off Ch. DET: Read failure\n", __func__);
-			return retval;
-		}
-		for (cnt = 0; cnt < 4; cnt++)
-			FMDBG("Off-channel data set is : 0x%x\t",
-				(int)radio->registers[XFRDAT0+cnt]);
 		break;
 	/* TX Controls */
 
@@ -3264,6 +3276,8 @@
 	case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
 	case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
 	case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
+	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+	case V4L2_CID_PRIVATE_SINR_SAMPLES:
 		retval = 0;
 		break;
 	default:
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index 78eef72..aa6f966 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -90,6 +90,42 @@
 	return rc;
 }
 
+int32_t imx074_act_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	int dir,
+	int32_t num_steps)
+{
+	int32_t step_direction, dest_step_position, bit_mask;
+	int32_t rc = 0;
+
+	if (num_steps == 0)
+		return rc;
+
+	if (dir == MOVE_NEAR) {
+		step_direction = 1;
+		bit_mask = 0x80;
+	} else if (dir == MOVE_FAR) {
+		step_direction = -1;
+		bit_mask = 0x00;
+	} else {
+		CDBG("imx074_move_focus: Illegal focus direction");
+		return -EINVAL;
+	}
+	dest_step_position = a_ctrl->curr_step_pos +
+		(step_direction * num_steps);
+	if (dest_step_position < 0)
+		dest_step_position = 0;
+	else if (dest_step_position > IMX074_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = IMX074_TOTAL_STEPS_NEAR_TO_FAR;
+
+	msm_camera_i2c_write(&a_ctrl->i2c_client,
+		0x00,
+		((num_steps * g_regions[0].code_per_step) | bit_mask),
+		MSM_CAMERA_I2C_BYTE_DATA);
+	a_ctrl->curr_step_pos = dest_step_position;
+	return rc;
+}
+
 static int32_t imx074_set_default_focus(
 	struct msm_actuator_ctrl_t *a_ctrl)
 {
@@ -228,7 +264,7 @@
 
 	.func_tbl = {
 		.actuator_init_table = msm_actuator_init_table,
-		.actuator_move_focus = msm_actuator_move_focus,
+		.actuator_move_focus = imx074_act_move_focus,
 		.actuator_write_focus = imx074_act_write_focus,
 		.actuator_set_default_focus = imx074_set_default_focus,
 		.actuator_init_focus = imx074_act_init_focus,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index 0f0bd67..f035ad6 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -435,8 +435,11 @@
 	}
 
 	buf_cmd = buf_p->vbuf;
-	msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
-				&buf_p->handle);
+	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ENCODE ||
+		pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ROTATION) {
+		msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
+			&buf_p->handle);
+	}
 	kfree(buf_p->subsystem_id);
 	kfree(buf_p);
 
@@ -484,16 +487,23 @@
 		kfree(buf_p);
 		return -ENOMEM;
 	}
+	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+		buf_p->y_buffer_addr    = buf_cmd.y_off;
+	} else {
 	buf_p->y_buffer_addr    = msm_gemini_platform_v2p(buf_cmd.fd,
 		buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
 			&buf_p->msm_buffer, buf_p->subsystem_id, &buf_p->handle)
 			+ buf_cmd.offset;
+	}
 	buf_p->y_len          = buf_cmd.y_len;
 
 	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
 	buf_p->cbcr_len       = buf_cmd.cbcr_len;
 
 	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+	GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
+		buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
+		buf_p->cbcr_len);
 
 	if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
 		GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index ea969cf..9bfc239 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -117,7 +117,7 @@
 	case CAMIO_JPEG_CLK:
 		camio_jpeg_clk =
 		clk = clk_get(NULL, "ijpeg_clk");
-		clk_set_rate(clk, 153600000);
+		clk_set_rate(clk, 228571000);
 		break;
 
 	case CAMIO_JPEG_PCLK:
@@ -191,6 +191,11 @@
 	if (rc < 0)
 		return rc;
 	rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_disable(CAMIO_IMEM_CLK);
+	if (rc < 0)
+		return rc;
 
 	if (fs_ijpeg) {
 		rc = regulator_disable(fs_ijpeg);
@@ -225,6 +230,10 @@
 	if (rc < 0)
 		return rc;
 
+	rc = msm_camio_clk_enable(CAMIO_IMEM_CLK);
+	if (rc < 0)
+		return rc;
+
 	CDBG("%s: exit %d\n", __func__, rc);
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index fdd1f0e..a0ac70d 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -90,6 +90,7 @@
 		case VFE_OUTPUTS_MAIN_AND_VIDEO:
 		case VFE_OUTPUTS_MAIN_AND_THUMB:
 		case VFE_OUTPUTS_RAW:
+		case VFE_OUTPUTS_JPEG_AND_THUMB:
 			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
 			break;
 		case VFE_OUTPUTS_THUMB_AND_MAIN:
@@ -123,6 +124,9 @@
 		case VFE_OUTPUTS_THUMB_AND_MAIN:
 			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
 			break;
+		case VFE_OUTPUTS_JPEG_AND_THUMB:
+			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
+			break;
 		default:
 			image_mode = -1;
 			break;
@@ -200,16 +204,27 @@
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		break;
 	case VFE_MSG_V32_JPEG_CAPTURE:
+		D("%s:VFE_MSG_V32_JPEG_CAPTURE vdata->type %d\n", __func__,
+			vdata->type);
 		free_buf.num_planes = 1;
-		free_buf.ch_paddr[0] = IMEM_Y_OFFSET;
-		free_buf.ch_paddr[1] = IMEM_CBCR_OFFSET;
+		free_buf.ch_paddr[0] = IMEM_Y_PING_OFFSET;
+		free_buf.ch_paddr[1] = IMEM_CBCR_PING_OFFSET;
 		cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
 		cfgcmd.value = &vfe_id;
 		vfe_params.vfe_cfg = &cfgcmd;
 		vfe_params.data = (void *)&free_buf;
+		D("%s:VFE_MSG_V32_JPEG_CAPTURE y_ping=%x cbcr_ping=%x\n",
+			__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		/* Write the same buffer into PONG */
+		free_buf.ch_paddr[0] = IMEM_Y_PONG_OFFSET;
+		free_buf.ch_paddr[1] = IMEM_CBCR_PONG_OFFSET;
 		cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
+		cfgcmd.value = &vfe_id;
+		vfe_params.vfe_cfg = &cfgcmd;
+		vfe_params.data = (void *)&free_buf;
+		D("%s:VFE_MSG_V32_JPEG_CAPTURE y_pong=%x cbcr_pong=%x\n",
+			__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		break;
 	case VFE_MSG_OUTPUT_IRQ:
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index b539d19..e9201ea 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -868,6 +868,7 @@
 	irq_comp_mask	= msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 
 	if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+		vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
 		vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
 		if (vfe32_ctrl->outpath.output_mode &
 			VFE32_OUTPUT_MODE_PRIMARY) {
@@ -1297,8 +1298,6 @@
 		rc = vfe32_capture_raw(snapshot_cnt);
 		break;
 	case VFE_CMD_CAPTURE:
-		CDBG("vfe32_proc_general: cmdID = %s op mode = %d\n",
-			vfe32_general_cmd[cmd->id], vfe32_ctrl->operation_mode);
 		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
 				sizeof(uint32_t))) {
 			rc = -EFAULT;
@@ -2960,13 +2959,14 @@
 
 	free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
 		VFE_MSG_OUTPUT_SECONDARY);
-
 	out_bool = ((vfe32_ctrl->operation_mode ==
 				VFE_OUTPUTS_THUMB_AND_MAIN ||
 			vfe32_ctrl->operation_mode ==
 				VFE_OUTPUTS_MAIN_AND_THUMB ||
 			vfe32_ctrl->operation_mode ==
-				VFE_OUTPUTS_RAW) &&
+				VFE_OUTPUTS_RAW ||
+			vfe32_ctrl->operation_mode ==
+				VFE_OUTPUTS_JPEG_AND_THUMB) &&
 			(vfe32_ctrl->vfe_capture_count <= 1)) || free_buf;
 
 	if (out_bool) {
@@ -3003,7 +3003,9 @@
 			vfe32_ctrl->operation_mode ==
 				VFE_OUTPUTS_MAIN_AND_THUMB ||
 			vfe32_ctrl->operation_mode ==
-				VFE_OUTPUTS_RAW)
+				VFE_OUTPUTS_RAW ||
+			vfe32_ctrl->operation_mode ==
+				VFE_OUTPUTS_JPEG_AND_THUMB)
 			vfe32_ctrl->outpath.out1.capture_cnt--;
 
 		vfe_send_outmsg(&vfe32_ctrl->subdev,
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 047226e..cfc0fe0 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -4,9 +4,9 @@
 EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
 obj-$(CONFIG_IMX074) += imx074_v4l2.o
-obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
 obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
 obj-$(CONFIG_OV2720) += ov2720.o
+obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
 obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
 obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
 obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 954dd2f..af68601 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -123,7 +123,7 @@
 	{0x0344, 0x01}, /* x_addr_start */
 	{0x0345, 0x20}, /* x_addr_start */
 	{0x0346, 0x02}, /* y_addr_start */
-	{0x0347, 0x23}, /* y_addr_start */
+	{0x0347, 0x24}, /* y_addr_start */
 	{0x0348, 0x0E}, /* x_addr_end */
 	{0x0349, 0xA0}, /* x_addr_end */
 	{0x034A, 0x09}, /* y_addr_end */
@@ -160,7 +160,7 @@
 	{0x0344, 0x01}, /* x_addr_start */
 	{0x0345, 0x20}, /* x_addr_start */
 	{0x0346, 0x02}, /* y_addr_start */
-	{0x0347, 0x23}, /* y_addr_start */
+	{0x0347, 0x24}, /* y_addr_start */
 	{0x0348, 0x0E}, /* x_addr_end */
 	{0x0349, 0xA0}, /* x_addr_end */
 	{0x034A, 0x09}, /* y_addr_end */
@@ -197,7 +197,7 @@
 	{0x0344, 0x01}, /* x_addr_start */
 	{0x0345, 0x20}, /* x_addr_start */
 	{0x0346, 0x02}, /* y_addr_start */
-	{0x0347, 0x23}, /* y_addr_start */
+	{0x0347, 0x24}, /* y_addr_start */
 	{0x0348, 0x0E}, /* x_addr_end */
 	{0x0349, 0xA0}, /* x_addr_end */
 	{0x034A, 0x09}, /* y_addr_end */
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index e3d9d2d..6c52e21 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -699,7 +699,8 @@
 }
 
 static long venc_set_h264_intra_period(struct video_client_ctx *client_ctx,
-		__s32 period) {
+		__s32 period)
+{
 	struct vcd_property_i_period vcd_property_i_period;
 	struct vcd_property_codec vcd_property_codec;
 	struct vcd_property_hdr vcd_property_hdr;
@@ -726,7 +727,7 @@
 	vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
 
 	vcd_property_i_period.p_frames = period - 1;
-	vcd_property_i_period.b_frames = 1;
+	vcd_property_i_period.b_frames = 0;
 
 	rc = vcd_set_property(client_ctx->vcd_handle,
 				&vcd_property_hdr, &vcd_property_i_period);
@@ -740,6 +741,47 @@
 	return rc;
 }
 
+static long venc_get_h264_intra_period(struct video_client_ctx *client_ctx,
+		__s32 *period)
+{
+	struct vcd_property_i_period vcd_property_i_period;
+	struct vcd_property_codec vcd_property_codec;
+	struct vcd_property_hdr vcd_property_hdr;
+	int rc = 0;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting codec property\n");
+		goto err;
+	}
+
+	if (vcd_property_codec.codec != VCD_CODEC_H264) {
+		rc = -ENOTSUPP;
+		WFD_MSG_ERR("Control not supported for non H264 codec\n");
+		goto err;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_INTRA_PERIOD;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_i_period);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting intra period\n");
+		goto err;
+	}
+
+	*period = vcd_property_i_period.p_frames + 1;
+err:
+	return rc;
+}
+
 static long venc_request_frame(struct video_client_ctx *client_ctx, __s32 type)
 {
 	struct vcd_property_req_i_frame vcd_property_req_i_frame;
@@ -950,6 +992,212 @@
 	return rc;
 }
 
+static long venc_set_qp_value(struct video_client_ctx *client_ctx,
+		__s32 frametype, __s32 qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_session_qp vcd_property_session_qp;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_SESSION_QP;
+	vcd_property_hdr.sz = sizeof(vcd_property_session_qp);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_session_qp);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get session qp\n");
+		goto err;
+	}
+
+	switch (frametype) {
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+		vcd_property_session_qp.i_frame_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+		vcd_property_session_qp.p_frame_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+		vcd_property_session_qp.b_frame_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+		rc = -ENOTSUPP;
+		goto err;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+
+	rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_session_qp);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set session qp\n");
+		goto err;
+	}
+err:
+	return rc;
+}
+
+static long venc_get_qp_value(struct video_client_ctx *client_ctx,
+		__s32 frametype, __s32 *qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_session_qp vcd_property_session_qp;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_SESSION_QP;
+	vcd_property_hdr.sz = sizeof(vcd_property_session_qp);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_session_qp);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get session qp\n");
+		goto err;
+	}
+
+	switch (frametype) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+		*qp = vcd_property_session_qp.i_frame_qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+		*qp = vcd_property_session_qp.p_frame_qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+		*qp = vcd_property_session_qp.b_frame_qp;
+		break;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+err:
+	return rc;
+}
+
+static long venc_set_qp_range(struct video_client_ctx *client_ctx,
+		__s32 type, __s32 qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_qp_range vcd_property_qp_range;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_QP_RANGE;
+	vcd_property_hdr.sz = sizeof(vcd_property_qp_range);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get qp range\n");
+		goto err;
+	}
+
+	switch (type) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+		vcd_property_qp_range.min_qp = qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		vcd_property_qp_range.max_qp = qp;
+		break;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set qp range\n");
+		goto err;
+	}
+err:
+	return rc;
+}
+
+static long venc_get_qp_range(struct video_client_ctx *client_ctx,
+		__s32 type, __s32 *qp)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_qp_range vcd_property_qp_range;
+	int rc = 0;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_QP_RANGE;
+	vcd_property_hdr.sz = sizeof(vcd_property_qp_range);
+
+	rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to get qp range\n");
+		goto err;
+	}
+
+	switch (type) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+		*qp = vcd_property_qp_range.min_qp;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		*qp = vcd_property_qp_range.max_qp;
+		break;
+	default:
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+			&vcd_property_qp_range);
+
+	if (rc) {
+		WFD_MSG_ERR("Failed to set qp range\n");
+		goto err;
+	}
+err:
+	return rc;
+}
+
 static long venc_alloc_input_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	struct mem_region *mregion = arg;
@@ -1220,6 +1468,25 @@
 	case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
 		rc = venc_request_frame(client_ctx, ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+		rc = venc_set_qp_value(client_ctx, ctrl->id, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		rc = venc_set_qp_range(client_ctx, ctrl->id, ctrl->value);
+		break;
 	default:
 		WFD_MSG_ERR("Set property not suported: %d\n", ctrl->id);
 		rc = -ENOTSUPP;
@@ -1248,6 +1515,28 @@
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 		rc = venc_get_codec_profile(client_ctx, ctrl->id, &ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+		rc = venc_get_h264_intra_period(client_ctx, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+		rc = venc_get_qp_value(client_ctx, ctrl->id, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		rc = venc_get_qp_range(client_ctx, ctrl->id, &ctrl->value);
+		break;
 	default:
 		WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
 		rc = -ENOTSUPP;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 77ac845..54e1b9a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -879,6 +879,16 @@
 	  voltage leaves the accepatable range which then calls a notifier call
 	  chain.
 
+config WCD9304_CODEC
+        tristate "WCD9304 Codec"
+        select SLIMBUS
+        select MFD_CORE
+        default n
+        help
+          Enables the WCD9304 core driver. The core driver provides
+          read/write capability to registers which are part of the
+          WCD9304 core and gives the ability to use the WCD9304 codec.
+
 config WCD9310_CODEC
         tristate "WCD9310 Codec"
         select SLIMBUS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c8fcf5f..fd887ea 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -69,7 +69,8 @@
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
 obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-ts.o
 
-obj-$(CONFIG_WCD9310_CODEC)       += wcd9310-core.o wcd9310-irq.o wcd9310-slimslave.o
+obj-$(CONFIG_WCD9310_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
+obj-$(CONFIG_WCD9304_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
 
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 8049975..66b98a1 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -754,6 +754,11 @@
 	}
 
 	if (version != PM8XXX_VERSION_8917) {
+		if (pdata->pwm_pdata) {
+			pwm_cell.platform_data = pdata->pwm_pdata;
+			pwm_cell.pdata_size =
+				sizeof(struct pm8xxx_pwm_platform_data);
+		}
 		ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
 		if (ret) {
 			pr_err("Failed to add pwm subdevice ret=%d\n", ret);
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index 05f02c4..191e079 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -64,6 +64,7 @@
 #define SSBI_REG_ADDR_LPG_BANK_EN	0x144
 #define SSBI_REG_ADDR_LPG_LUT_CFG0	0x145
 #define SSBI_REG_ADDR_LPG_LUT_CFG1	0x146
+#define SSBI_REG_ADDR_LPG_TEST		0x147
 
 /* LPG Control 0 */
 #define PM8XXX_PWM_1KHZ_COUNT_MASK	0xF0
@@ -137,6 +138,10 @@
 /* LPG LUT_CFG1 */
 #define PM8XXX_PWM_LUT_READ			0x40
 
+/* TEST */
+#define PM8XXX_PWM_DTEST_MASK		0x38
+#define PM8XXX_PWM_DTEST_SHIFT		3
+#define PM8XXX_PWM_DTEST_BANK_MASK	0x07
 
 /*
  * PWM Frequency = Clock Frequency / (N * T)
@@ -200,6 +205,7 @@
 	int			irq;
 	struct pm8xxx_pwm_chip	*chip;
 	int			bypass_lut;
+	int			dtest_mode_supported;
 };
 
 struct pm8xxx_pwm_chip {
@@ -638,6 +644,28 @@
 	return rc;
 }
 
+static int pm8xxx_pwm_set_dtest(struct pwm_device *pwm, int enable)
+{
+	int	rc;
+	u8	reg;
+
+	reg = pwm->pwm_id & PM8XXX_PWM_DTEST_BANK_MASK;
+
+	if (enable) {
+		/* Observe LPG_OUT on DTEST1*/
+		reg |= (1 << PM8XXX_PWM_DTEST_SHIFT) &
+				PM8XXX_PWM_DTEST_MASK;
+	}
+
+	rc = pm8xxx_writeb(pwm->chip->dev->parent,
+			SSBI_REG_ADDR_LPG_TEST, reg);
+	if (rc)
+		pr_err("pm8xxx_write(DTEST=0x%x) failed: rc=%d\n",
+							reg, rc);
+
+	return rc;
+}
+
 /* APIs */
 /**
  * pwm_request - request a PWM device
@@ -785,6 +813,8 @@
 		rc = -EINVAL;
 	} else {
 		if (pwm_chip->is_lpg_supported) {
+			if (pwm->dtest_mode_supported)
+				pm8xxx_pwm_set_dtest(pwm, 1);
 			rc = pm8xxx_pwm_bank_enable(pwm, 1);
 			pm8xxx_pwm_bank_sel(pwm);
 			pm8xxx_pwm_start(pwm, 1, 0);
@@ -811,6 +841,8 @@
 	mutex_lock(&pwm->chip->pwm_mutex);
 	if (pwm->in_use) {
 		if (pwm_chip->is_lpg_supported) {
+			if (pwm->dtest_mode_supported)
+				pm8xxx_pwm_set_dtest(pwm, 0);
 			pm8xxx_pwm_bank_sel(pwm);
 			pm8xxx_pwm_start(pwm, 0, 0);
 			pm8xxx_pwm_bank_enable(pwm, 0);
@@ -1030,11 +1062,17 @@
 
 	mutex_lock(&pwm->chip->pwm_mutex);
 	if (start) {
+		if (pwm->dtest_mode_supported)
+			pm8xxx_pwm_set_dtest(pwm, 1);
+
 		pm8xxx_pwm_bank_enable(pwm, 1);
 
 		pm8xxx_pwm_bank_sel(pwm);
 		pm8xxx_pwm_start(pwm, 1, 1);
 	} else {
+		if (pwm->dtest_mode_supported)
+			pm8xxx_pwm_set_dtest(pwm, 0);
+
 		pm8xxx_pwm_bank_sel(pwm);
 		pm8xxx_pwm_start(pwm, 0, 0);
 
@@ -1324,6 +1362,7 @@
 
 static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
 {
+	const struct pm8xxx_pwm_platform_data *pdata = pdev->dev.platform_data;
 	struct pm8xxx_pwm_chip	*chip;
 	int	i;
 	enum pm8xxx_version version;
@@ -1374,6 +1413,8 @@
 	for (i = 0; i < chip->pwm_channels; i++) {
 		chip->pwm_dev[i].pwm_id = i;
 		chip->pwm_dev[i].chip = chip;
+		if (i == pdata->dtest_channel)
+			chip->pwm_dev[i].dtest_mode_supported = 1;
 	}
 
 	platform_set_drvdata(pdev, chip);
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
deleted file mode 100644
index d1d9132..0000000
--- a/drivers/mfd/wcd9310-core.c
+++ /dev/null
@@ -1,1151 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/wcd9310/pdata.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/debugfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/i2c.h>
-#include <sound/soc.h>
-
-#define TABLA_SLIM_GLA_MAX_RETRIES 5
-#define TABLA_REGISTER_START_OFFSET 0x800
-#define TABLA_SLIM_RW_MAX_TRIES 3
-
-#define MAX_TABLA_DEVICE	4
-#define TABLA_I2C_MODE	0x03
-
-struct tabla_i2c {
-	struct i2c_client *client;
-	struct i2c_msg xfer_msg[2];
-	struct mutex xfer_lock;
-	int mod_id;
-};
-
-struct tabla_i2c tabla_modules[MAX_TABLA_DEVICE];
-static int tabla_intf;
-
-static int tabla_read(struct tabla *tabla, unsigned short reg,
-		       int bytes, void *dest, bool interface_reg)
-{
-	int ret;
-	u8 *buf = dest;
-
-	if (bytes <= 0) {
-		dev_err(tabla->dev, "Invalid byte read length %d\n", bytes);
-		return -EINVAL;
-	}
-
-	ret = tabla->read_dev(tabla, reg, bytes, dest, interface_reg);
-	if (ret < 0) {
-		dev_err(tabla->dev, "Tabla read failed\n");
-		return ret;
-	} else
-		dev_dbg(tabla->dev, "Read 0x%02x from R%d(0x%x)\n",
-			 *buf, reg, reg);
-
-	return 0;
-}
-int tabla_reg_read(struct tabla *tabla, unsigned short reg)
-{
-	u8 val;
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_read(tabla, reg, 1, &val, false);
-	mutex_unlock(&tabla->io_lock);
-
-	if (ret < 0)
-		return ret;
-	else
-		return val;
-}
-EXPORT_SYMBOL_GPL(tabla_reg_read);
-
-static int tabla_write(struct tabla *tabla, unsigned short reg,
-			int bytes, void *src, bool interface_reg)
-{
-	u8 *buf = src;
-
-	if (bytes <= 0) {
-		pr_err("%s: Error, invalid write length\n", __func__);
-		return -EINVAL;
-	}
-
-	dev_dbg(tabla->dev, "Write %02x to R%d(0x%x)\n",
-		 *buf, reg, reg);
-
-	return tabla->write_dev(tabla, reg, bytes, src, interface_reg);
-}
-
-int tabla_reg_write(struct tabla *tabla, unsigned short reg,
-		     u8 val)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_write(tabla, reg, 1, &val, false);
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_reg_write);
-
-static u8 tabla_pgd_la;
-static u8 tabla_inf_la;
-
-int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la)
-{
-	*pgd_la = tabla_pgd_la;
-	*inf_la = tabla_inf_la;
-	return 0;
-
-}
-EXPORT_SYMBOL_GPL(tabla_get_logical_addresses);
-
-int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg)
-{
-	u8 val;
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_read(tabla, reg, 1, &val, true);
-	mutex_unlock(&tabla->io_lock);
-
-	if (ret < 0)
-		return ret;
-	else
-		return val;
-}
-EXPORT_SYMBOL_GPL(tabla_interface_reg_read);
-
-int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg,
-		     u8 val)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-	ret = tabla_write(tabla, reg, 1, &val, true);
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_interface_reg_write);
-
-int tabla_bulk_read(struct tabla *tabla, unsigned short reg,
-		     int count, u8 *buf)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-
-	ret = tabla_read(tabla, reg, count, buf, false);
-
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_bulk_read);
-
-int tabla_bulk_write(struct tabla *tabla, unsigned short reg,
-		     int count, u8 *buf)
-{
-	int ret;
-
-	mutex_lock(&tabla->io_lock);
-
-	ret = tabla_write(tabla, reg, count, buf, false);
-
-	mutex_unlock(&tabla->io_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_bulk_write);
-
-static int tabla_slim_read_device(struct tabla *tabla, unsigned short reg,
-				int bytes, void *dest, bool interface)
-{
-	int ret;
-	struct slim_ele_access msg;
-	int slim_read_tries = TABLA_SLIM_RW_MAX_TRIES;
-	msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
-	msg.num_bytes = bytes;
-	msg.comp = NULL;
-
-	while (1) {
-		mutex_lock(&tabla->xfer_lock);
-		ret = slim_request_val_element(interface ?
-					       tabla->slim_slave : tabla->slim,
-					       &msg, dest, bytes);
-		mutex_unlock(&tabla->xfer_lock);
-		if (likely(ret == 0) || (--slim_read_tries == 0))
-			break;
-		usleep_range(5000, 5000);
-	}
-
-	if (ret)
-		pr_err("%s: Error, Tabla read failed (%d)\n", __func__, ret);
-
-	return ret;
-}
-/* Interface specifies whether the write is to the interface or general
- * registers.
- */
-static int tabla_slim_write_device(struct tabla *tabla, unsigned short reg,
-				   int bytes, void *src, bool interface)
-{
-	int ret;
-	struct slim_ele_access msg;
-	int slim_write_tries = TABLA_SLIM_RW_MAX_TRIES;
-	msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
-	msg.num_bytes = bytes;
-	msg.comp = NULL;
-
-	while (1) {
-		mutex_lock(&tabla->xfer_lock);
-		ret = slim_change_val_element(interface ?
-					      tabla->slim_slave : tabla->slim,
-					      &msg, src, bytes);
-		mutex_unlock(&tabla->xfer_lock);
-		if (likely(ret == 0) || (--slim_write_tries == 0))
-			break;
-		usleep_range(5000, 5000);
-	}
-
-	if (ret)
-		pr_err("%s: Error, Tabla write failed (%d)\n", __func__, ret);
-
-	return ret;
-}
-
-static struct mfd_cell tabla_devs[] = {
-	{
-		.name = "tabla_codec",
-	},
-};
-
-static struct mfd_cell tabla1x_devs[] = {
-	{
-		.name = "tabla1x_codec",
-	},
-};
-
-static void tabla_bring_up(struct tabla *tabla)
-{
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x4);
-	tabla_reg_write(tabla, TABLA_A_CDC_CTL, 0);
-	usleep_range(5000, 5000);
-	tabla_reg_write(tabla, TABLA_A_CDC_CTL, 3);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 3);
-}
-
-static void tabla_bring_down(struct tabla *tabla)
-{
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x7);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x6);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0xe);
-	tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x8);
-}
-
-static int tabla_reset(struct tabla *tabla)
-{
-	int ret;
-
-	if (tabla->reset_gpio) {
-		ret = gpio_request(tabla->reset_gpio, "CDC_RESET");
-		if (ret) {
-			pr_err("%s: Failed to request gpio %d\n", __func__,
-				tabla->reset_gpio);
-			tabla->reset_gpio = 0;
-			return ret;
-		}
-
-		gpio_direction_output(tabla->reset_gpio, 1);
-		msleep(20);
-		gpio_direction_output(tabla->reset_gpio, 0);
-		msleep(20);
-		gpio_direction_output(tabla->reset_gpio, 1);
-		msleep(20);
-	}
-	return 0;
-}
-
-static void tabla_free_reset(struct tabla *tabla)
-{
-	if (tabla->reset_gpio) {
-		gpio_free(tabla->reset_gpio);
-		tabla->reset_gpio = 0;
-	}
-}
-
-struct tabla_regulator {
-	const char *name;
-	int min_uV;
-	int max_uV;
-	int optimum_uA;
-	struct regulator *regulator;
-};
-
-
-/*
- *	format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
- *
- *	<POWER_SUPPLY_PIN_NAME> from Tabla objective spec
-*/
-
-#define  TABLA_CDC_VDDA_CP_CUR_MAX	500000
-#define  TABLA_CDC_VDDA_RX_CUR_MAX	20000
-#define  TABLA_CDC_VDDA_TX_CUR_MAX	20000
-#define  TABLA_VDDIO_CDC_CUR_MAX	5000
-
-#define  TABLA_VDDD_CDC_D_CUR_MAX	5000
-#define  TABLA_VDDD_CDC_A_CUR_MAX	5000
-
-static struct tabla_regulator tabla_regulators[] = {
-	{
-		.name = "CDC_VDD_CP",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_CDC_VDDA_CP_CUR_MAX,
-	},
-	{
-		.name = "CDC_VDDA_RX",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_CDC_VDDA_RX_CUR_MAX,
-	},
-	{
-		.name = "CDC_VDDA_TX",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_CDC_VDDA_TX_CUR_MAX,
-	},
-	{
-		.name = "VDDIO_CDC",
-		.min_uV = 1800000,
-		.max_uV = 1800000,
-		.optimum_uA = TABLA_VDDIO_CDC_CUR_MAX,
-	},
-	{
-		.name = "VDDD_CDC_D",
-		.min_uV = 1225000,
-		.max_uV = 1225000,
-		.optimum_uA = TABLA_VDDD_CDC_D_CUR_MAX,
-	},
-	{
-		.name = "CDC_VDDA_A_1P2V",
-		.min_uV = 1225000,
-		.max_uV = 1225000,
-		.optimum_uA = TABLA_VDDD_CDC_A_CUR_MAX,
-	},
-};
-
-static int tabla_device_init(struct tabla *tabla, int irq)
-{
-	int ret;
-	struct mfd_cell *tabla_dev;
-	int tabla_dev_size;
-
-	mutex_init(&tabla->io_lock);
-	mutex_init(&tabla->xfer_lock);
-
-	mutex_init(&tabla->pm_lock);
-	tabla->wlock_holders = 0;
-	tabla->pm_state = TABLA_PM_SLEEPABLE;
-	init_waitqueue_head(&tabla->pm_wq);
-	wake_lock_init(&tabla->wlock, WAKE_LOCK_IDLE, "wcd9310-irq");
-
-	dev_set_drvdata(tabla->dev, tabla);
-
-	tabla_bring_up(tabla);
-
-	ret = tabla_irq_init(tabla);
-	if (ret) {
-		pr_err("IRQ initialization failed\n");
-		goto err;
-	}
-	tabla->version = tabla_reg_read(tabla, TABLA_A_CHIP_VERSION) & 0x1F;
-	pr_info("%s : Tabla version %u initialized\n",
-		__func__, tabla->version);
-
-	if (TABLA_IS_1_X(tabla->version)) {
-		tabla_dev = tabla1x_devs;
-		tabla_dev_size = ARRAY_SIZE(tabla1x_devs);
-	} else {
-		tabla_dev = tabla_devs;
-		tabla_dev_size = ARRAY_SIZE(tabla_devs);
-	}
-	ret = mfd_add_devices(tabla->dev, -1,
-			      tabla_dev, tabla_dev_size,
-			      NULL, 0);
-	if (ret != 0) {
-		dev_err(tabla->dev, "Failed to add children: %d\n", ret);
-		goto err_irq;
-	}
-
-	tabla->version = tabla_reg_read(tabla, TABLA_A_CHIP_VERSION) & 0x1F;
-	pr_info("%s : Tabla version %u initialized\n",
-		__func__, tabla->version);
-
-	return ret;
-err_irq:
-	tabla_irq_exit(tabla);
-err:
-	tabla_bring_down(tabla);
-	wake_lock_destroy(&tabla->wlock);
-	mutex_destroy(&tabla->pm_lock);
-	mutex_destroy(&tabla->io_lock);
-	mutex_destroy(&tabla->xfer_lock);
-	return ret;
-}
-
-static void tabla_device_exit(struct tabla *tabla)
-{
-	tabla_irq_exit(tabla);
-	tabla_bring_down(tabla);
-	tabla_free_reset(tabla);
-	mutex_destroy(&tabla->pm_lock);
-	wake_lock_destroy(&tabla->wlock);
-	mutex_destroy(&tabla->io_lock);
-	mutex_destroy(&tabla->xfer_lock);
-}
-
-
-#ifdef CONFIG_DEBUG_FS
-struct tabla *debugTabla;
-
-static struct dentry *debugfs_tabla_dent;
-static struct dentry *debugfs_peek;
-static struct dentry *debugfs_poke;
-
-static unsigned char read_data;
-
-static int codec_debug_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static int get_parameters(char *buf, long int *param1, int num_of_par)
-{
-	char *token;
-	int base, cnt;
-
-	token = strsep(&buf, " ");
-
-	for (cnt = 0; cnt < num_of_par; cnt++) {
-		if (token != NULL) {
-			if ((token[1] == 'x') || (token[1] == 'X'))
-				base = 16;
-			else
-				base = 10;
-
-			if (strict_strtoul(token, base, &param1[cnt]) != 0)
-				return -EINVAL;
-
-			token = strsep(&buf, " ");
-		} else
-			return -EINVAL;
-	}
-	return 0;
-}
-
-static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
-				size_t count, loff_t *ppos)
-{
-	char lbuf[8];
-
-	snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
-	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
-		strnlen(lbuf, 7));
-}
-
-
-static ssize_t codec_debug_write(struct file *filp,
-	const char __user *ubuf, size_t cnt, loff_t *ppos)
-{
-	char *access_str = filp->private_data;
-	char lbuf[32];
-	int rc;
-	long int param[5];
-
-	if (cnt > sizeof(lbuf) - 1)
-		return -EINVAL;
-
-	rc = copy_from_user(lbuf, ubuf, cnt);
-	if (rc)
-		return -EFAULT;
-
-	lbuf[cnt] = '\0';
-
-	if (!strncmp(access_str, "poke", 6)) {
-		/* write */
-		rc = get_parameters(lbuf, param, 2);
-		if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) &&
-			(rc == 0))
-			tabla_interface_reg_write(debugTabla, param[0],
-				param[1]);
-		else
-			rc = -EINVAL;
-	} else if (!strncmp(access_str, "peek", 6)) {
-		/* read */
-		rc = get_parameters(lbuf, param, 1);
-		if ((param[0] <= 0x3FF) && (rc == 0))
-			read_data = tabla_interface_reg_read(debugTabla,
-				param[0]);
-		else
-			rc = -EINVAL;
-	}
-
-	if (rc == 0)
-		rc = cnt;
-	else
-		pr_err("%s: rc = %d\n", __func__, rc);
-
-	return rc;
-}
-
-static const struct file_operations codec_debug_ops = {
-	.open = codec_debug_open,
-	.write = codec_debug_write,
-	.read = codec_debug_read
-};
-#endif
-
-static int tabla_enable_supplies(struct tabla *tabla)
-{
-	int ret;
-	int i;
-
-	tabla->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
-				   ARRAY_SIZE(tabla_regulators),
-				   GFP_KERNEL);
-	if (!tabla->supplies) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++)
-		tabla->supplies[i].supply = tabla_regulators[i].name;
-
-	ret = regulator_bulk_get(tabla->dev, ARRAY_SIZE(tabla_regulators),
-				 tabla->supplies);
-	if (ret != 0) {
-		dev_err(tabla->dev, "Failed to get supplies: err = %d\n", ret);
-		goto err_supplies;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
-		ret = regulator_set_voltage(tabla->supplies[i].consumer,
-			tabla_regulators[i].min_uV, tabla_regulators[i].max_uV);
-		if (ret) {
-			pr_err("%s: Setting regulator voltage failed for "
-				"regulator %s err = %d\n", __func__,
-				tabla->supplies[i].supply, ret);
-			goto err_get;
-		}
-
-		ret = regulator_set_optimum_mode(tabla->supplies[i].consumer,
-			tabla_regulators[i].optimum_uA);
-		if (ret < 0) {
-			pr_err("%s: Setting regulator optimum mode failed for "
-				"regulator %s err = %d\n", __func__,
-				tabla->supplies[i].supply, ret);
-			goto err_get;
-		}
-	}
-
-	ret = regulator_bulk_enable(ARRAY_SIZE(tabla_regulators),
-				    tabla->supplies);
-	if (ret != 0) {
-		dev_err(tabla->dev, "Failed to enable supplies: err = %d\n",
-				ret);
-		goto err_configure;
-	}
-	return ret;
-
-err_configure:
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
-		regulator_set_voltage(tabla->supplies[i].consumer, 0,
-			tabla_regulators[i].max_uV);
-		regulator_set_optimum_mode(tabla->supplies[i].consumer, 0);
-	}
-err_get:
-	regulator_bulk_free(ARRAY_SIZE(tabla_regulators), tabla->supplies);
-err_supplies:
-	kfree(tabla->supplies);
-err:
-	return ret;
-}
-
-static void tabla_disable_supplies(struct tabla *tabla)
-{
-	int i;
-
-	regulator_bulk_disable(ARRAY_SIZE(tabla_regulators),
-				    tabla->supplies);
-	for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
-		regulator_set_voltage(tabla->supplies[i].consumer, 0,
-			tabla_regulators[i].max_uV);
-		regulator_set_optimum_mode(tabla->supplies[i].consumer, 0);
-	}
-	regulator_bulk_free(ARRAY_SIZE(tabla_regulators), tabla->supplies);
-	kfree(tabla->supplies);
-}
-
-int tabla_get_intf_type(void)
-{
-	return tabla_intf;
-}
-EXPORT_SYMBOL_GPL(tabla_get_intf_type);
-
-struct tabla_i2c *get_i2c_tabla_device_info(u16 reg)
-{
-	u16 mask = 0x0f00;
-	int value = 0;
-	struct tabla_i2c *tabla = NULL;
-	value = ((reg & mask) >> 8) & 0x000f;
-	switch (value) {
-	case 0:
-		tabla = &tabla_modules[0];
-		break;
-	case 1:
-		tabla = &tabla_modules[1];
-		break;
-	case 2:
-		tabla = &tabla_modules[2];
-		break;
-	case 3:
-		tabla = &tabla_modules[3];
-		break;
-	default:
-		break;
-	}
-	return tabla;
-}
-
-int tabla_i2c_write_device(u16 reg, u8 *value,
-				u32 bytes)
-{
-
-	struct i2c_msg *msg;
-	int ret = 0;
-	u8 reg_addr = 0;
-	u8 data[bytes + 1];
-	struct tabla_i2c *tabla;
-
-	tabla = get_i2c_tabla_device_info(reg);
-	if (tabla == NULL || tabla->client == NULL) {
-		pr_err("failed to get device info\n");
-		return -ENODEV;
-	}
-	reg_addr = (u8)reg;
-	msg = &tabla->xfer_msg[0];
-	msg->addr = tabla->client->addr;
-	msg->len = bytes + 1;
-	msg->flags = 0;
-	data[0] = reg;
-	data[1] = *value;
-	msg->buf = data;
-	ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 1);
-	/* Try again if the write fails */
-	if (ret != 1) {
-		ret = i2c_transfer(tabla->client->adapter,
-						tabla->xfer_msg, 1);
-		if (ret != 1) {
-			pr_err("failed to write the device\n");
-			return ret;
-		}
-	}
-	pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
-	return 0;
-}
-
-
-int tabla_i2c_read_device(unsigned short reg,
-				  int bytes, unsigned char *dest)
-{
-	struct i2c_msg *msg;
-	int ret = 0;
-	u8 reg_addr = 0;
-	struct tabla_i2c *tabla;
-	u8 i = 0;
-
-	tabla = get_i2c_tabla_device_info(reg);
-	if (tabla == NULL || tabla->client == NULL) {
-		pr_err("failed to get device info\n");
-		return -ENODEV;
-	}
-	for (i = 0; i < bytes; i++) {
-		reg_addr = (u8)reg++;
-		msg = &tabla->xfer_msg[0];
-		msg->addr = tabla->client->addr;
-		msg->len = 1;
-		msg->flags = 0;
-		msg->buf = &reg_addr;
-
-		msg = &tabla->xfer_msg[1];
-		msg->addr = tabla->client->addr;
-		msg->len = 1;
-		msg->flags = I2C_M_RD;
-		msg->buf = dest++;
-		ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 2);
-
-		/* Try again if read fails first time */
-		if (ret != 2) {
-			ret = i2c_transfer(tabla->client->adapter,
-							tabla->xfer_msg, 2);
-			if (ret != 2) {
-				pr_err("failed to read tabla register\n");
-				return ret;
-			}
-		}
-	}
-	return 0;
-}
-
-int tabla_i2c_read(struct tabla *tabla, unsigned short reg,
-		   int bytes, void *dest, bool interface_reg)
-{
-	return tabla_i2c_read_device(reg, bytes, dest);
-}
-
-int tabla_i2c_write(struct tabla *tabla, unsigned short reg,
-		    int bytes, void *src, bool interface_reg)
-{
-	return tabla_i2c_write_device(reg, src, bytes);
-}
-
-static int __devinit tabla_i2c_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
-{
-	struct tabla *tabla;
-	struct tabla_pdata *pdata = client->dev.platform_data;
-	int val = 0;
-	int ret = 0;
-	static int device_id;
-
-	if (device_id > 0) {
-		tabla_modules[device_id++].client = client;
-		pr_info("probe for other slaves devices of tabla\n");
-		return ret;
-	}
-
-	tabla = kzalloc(sizeof(struct tabla), GFP_KERNEL);
-	if (tabla == NULL) {
-		pr_err("%s: error, allocation failed\n", __func__);
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	if (!pdata) {
-		dev_dbg(&client->dev, "no platform data?\n");
-		ret = -EINVAL;
-		goto err_tabla;
-	}
-	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
-		dev_dbg(&client->dev, "can't talk I2C?\n");
-		ret = -EIO;
-		goto err_tabla;
-	}
-	tabla->dev = &client->dev;
-	tabla->reset_gpio = pdata->reset_gpio;
-
-	ret = tabla_enable_supplies(tabla);
-	if (ret) {
-		pr_err("%s: Fail to enable Tabla supplies\n", __func__);
-		goto err_tabla;
-	}
-
-	usleep_range(5, 5);
-	ret = tabla_reset(tabla);
-	if (ret) {
-		pr_err("%s: Resetting Tabla failed\n", __func__);
-		goto err_supplies;
-	}
-	tabla_modules[device_id++].client = client;
-
-	tabla->read_dev = tabla_i2c_read;
-	tabla->write_dev = tabla_i2c_write;
-	tabla->irq = pdata->irq;
-	tabla->irq_base = pdata->irq_base;
-
-	/*read the tabla status before initializing the device type*/
-	ret = tabla_read(tabla, TABLA_A_CHIP_STATUS, 1, &val, 0);
-	if ((ret < 0) || (val != TABLA_I2C_MODE)) {
-		pr_err("failed to read the tabla status\n");
-		goto err_device_init;
-	}
-
-	ret = tabla_device_init(tabla, tabla->irq);
-	if (ret) {
-		pr_err("%s: error, initializing device failed\n", __func__);
-		goto err_device_init;
-	}
-	tabla_intf = TABLA_INTERFACE_TYPE_I2C;
-
-	return ret;
-err_device_init:
-	tabla_free_reset(tabla);
-err_supplies:
-	tabla_disable_supplies(tabla);
-err_tabla:
-	kfree(tabla);
-fail:
-	return ret;
-}
-
-static int __devexit tabla_i2c_remove(struct i2c_client *client)
-{
-	struct tabla *tabla;
-
-	pr_debug("exit\n");
-	tabla = dev_get_drvdata(&client->dev);
-	tabla_device_exit(tabla);
-	tabla_disable_supplies(tabla);
-	kfree(tabla);
-	return 0;
-}
-
-static int tabla_slim_probe(struct slim_device *slim)
-{
-	struct tabla *tabla;
-	struct tabla_pdata *pdata;
-	int ret = 0;
-	int sgla_retry_cnt;
-
-	dev_info(&slim->dev, "Initialized slim device %s\n", slim->name);
-	pdata = slim->dev.platform_data;
-
-	if (!pdata) {
-		dev_err(&slim->dev, "Error, no platform data\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
-	tabla = kzalloc(sizeof(struct tabla), GFP_KERNEL);
-	if (tabla == NULL) {
-		pr_err("%s: error, allocation failed\n", __func__);
-		ret = -ENOMEM;
-		goto err;
-	}
-	if (!slim->ctrl) {
-		pr_err("Error, no SLIMBUS control data\n");
-		ret = -EINVAL;
-		goto err_tabla;
-	}
-	tabla->slim = slim;
-	slim_set_clientdata(slim, tabla);
-	tabla->reset_gpio = pdata->reset_gpio;
-	tabla->dev = &slim->dev;
-
-	ret = tabla_enable_supplies(tabla);
-	if (ret) {
-		pr_err("%s: Fail to enable Tabla supplies\n", __func__);
-		goto err_tabla;
-	}
-	usleep_range(5, 5);
-
-	ret = tabla_reset(tabla);
-	if (ret) {
-		pr_err("%s: Resetting Tabla failed\n", __func__);
-		goto err_supplies;
-	}
-
-	ret = slim_get_logical_addr(tabla->slim, tabla->slim->e_addr,
-		ARRAY_SIZE(tabla->slim->e_addr), &tabla->slim->laddr);
-	if (ret) {
-		pr_err("fail to get slimbus logical address %d\n", ret);
-		goto err_reset;
-	}
-	tabla->read_dev = tabla_slim_read_device;
-	tabla->write_dev = tabla_slim_write_device;
-	tabla->irq = pdata->irq;
-	tabla->irq_base = pdata->irq_base;
-	tabla_pgd_la = tabla->slim->laddr;
-
-	if (pdata->num_irqs < TABLA_NUM_IRQS) {
-		pr_err("%s: Error, not enough interrupt lines allocated\n",
-			__func__);
-		goto err_reset;
-	}
-
-	tabla->slim_slave = &pdata->slimbus_slave_device;
-
-	ret = slim_add_device(slim->ctrl, tabla->slim_slave);
-	if (ret) {
-		pr_err("%s: error, adding SLIMBUS device failed\n", __func__);
-		goto err_reset;
-	}
-
-	sgla_retry_cnt = 0;
-
-	while (1) {
-		ret = slim_get_logical_addr(tabla->slim_slave,
-			tabla->slim_slave->e_addr,
-			ARRAY_SIZE(tabla->slim_slave->e_addr),
-			&tabla->slim_slave->laddr);
-		if (ret) {
-			if (sgla_retry_cnt++ < TABLA_SLIM_GLA_MAX_RETRIES) {
-				/* Give SLIMBUS slave time to report present
-				   and be ready.
-				 */
-				usleep_range(1000, 1000);
-				pr_debug("%s: retry slim_get_logical_addr()\n",
-					__func__);
-				continue;
-			}
-			pr_err("fail to get slimbus slave logical address"
-				" %d\n", ret);
-			goto err_slim_add;
-		}
-		break;
-	}
-	tabla_inf_la = tabla->slim_slave->laddr;
-	tabla_intf = TABLA_INTERFACE_TYPE_SLIMBUS;
-
-	ret = tabla_device_init(tabla, tabla->irq);
-	if (ret) {
-		pr_err("%s: error, initializing device failed\n", __func__);
-		goto err_slim_add;
-	}
-	tabla_init_slimslave(tabla, tabla_pgd_la);
-#ifdef CONFIG_DEBUG_FS
-	debugTabla = tabla;
-
-	debugfs_tabla_dent = debugfs_create_dir
-		("wcd9310_slimbus_interface_device", 0);
-	if (!IS_ERR(debugfs_tabla_dent)) {
-		debugfs_peek = debugfs_create_file("peek",
-		S_IFREG | S_IRUGO, debugfs_tabla_dent,
-		(void *) "peek", &codec_debug_ops);
-
-		debugfs_poke = debugfs_create_file("poke",
-		S_IFREG | S_IRUGO, debugfs_tabla_dent,
-		(void *) "poke", &codec_debug_ops);
-	}
-#endif
-
-	return ret;
-
-err_slim_add:
-	slim_remove_device(tabla->slim_slave);
-err_reset:
-	tabla_free_reset(tabla);
-err_supplies:
-	tabla_disable_supplies(tabla);
-err_tabla:
-	kfree(tabla);
-err:
-	return ret;
-}
-
-static int tabla_slim_remove(struct slim_device *pdev)
-{
-	struct tabla *tabla;
-
-#ifdef CONFIG_DEBUG_FS
-	debugfs_remove(debugfs_peek);
-	debugfs_remove(debugfs_poke);
-	debugfs_remove(debugfs_tabla_dent);
-#endif
-
-	tabla = slim_get_devicedata(pdev);
-	tabla_deinit_slimslave(tabla);
-	tabla_disable_supplies(tabla);
-	slim_remove_device(tabla->slim_slave);
-	tabla_device_exit(tabla);
-	return 0;
-}
-
-static int tabla_resume(struct tabla *tabla)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	mutex_lock(&tabla->pm_lock);
-	if (tabla->pm_state == TABLA_PM_ASLEEP) {
-		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
-			 tabla->pm_state, tabla->wlock_holders);
-		tabla->pm_state = TABLA_PM_SLEEPABLE;
-	} else {
-		pr_warn("%s: system is already awake, state %d wlock %d\n",
-			__func__, tabla->pm_state, tabla->wlock_holders);
-	}
-	mutex_unlock(&tabla->pm_lock);
-	wake_up_all(&tabla->pm_wq);
-
-	return ret;
-}
-
-static int tabla_slim_resume(struct slim_device *sldev)
-{
-	struct tabla *tabla = slim_get_devicedata(sldev);
-	return tabla_resume(tabla);
-}
-
-static int tabla_i2c_resume(struct i2c_client *i2cdev)
-{
-	struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
-	return tabla_resume(tabla);
-}
-
-static int tabla_suspend(struct tabla *tabla, pm_message_t pmesg)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	/* wake_lock() can be called after this suspend chain call started.
-	 * thus suspend can be called while wlock is being held */
-	mutex_lock(&tabla->pm_lock);
-	if (tabla->pm_state == TABLA_PM_SLEEPABLE) {
-		pr_debug("%s: suspending system, state %d, wlock %d\n",
-			 __func__, tabla->pm_state, tabla->wlock_holders);
-		tabla->pm_state = TABLA_PM_ASLEEP;
-	} else if (tabla->pm_state == TABLA_PM_AWAKE) {
-		/* unlock to wait for pm_state == TABLA_PM_SLEEPABLE
-		 * then set to TABLA_PM_ASLEEP */
-		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
-			 __func__, tabla->pm_state, tabla->wlock_holders);
-		mutex_unlock(&tabla->pm_lock);
-		if (!(wait_event_timeout(tabla->pm_wq,
-					 tabla_pm_cmpxchg(tabla,
-							  TABLA_PM_SLEEPABLE,
-							  TABLA_PM_ASLEEP) ==
-							     TABLA_PM_SLEEPABLE,
-					 HZ))) {
-			pr_debug("%s: suspend failed state %d, wlock %d\n",
-				 __func__, tabla->pm_state,
-				 tabla->wlock_holders);
-			ret = -EBUSY;
-		} else {
-			pr_debug("%s: done, state %d, wlock %d\n", __func__,
-				 tabla->pm_state, tabla->wlock_holders);
-		}
-		mutex_lock(&tabla->pm_lock);
-	} else if (tabla->pm_state == TABLA_PM_ASLEEP) {
-		pr_warn("%s: system is already suspended, state %d, wlock %dn",
-			__func__, tabla->pm_state, tabla->wlock_holders);
-	}
-	mutex_unlock(&tabla->pm_lock);
-
-	return ret;
-}
-
-static int tabla_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
-{
-	struct tabla *tabla = slim_get_devicedata(sldev);
-	return tabla_suspend(tabla, pmesg);
-}
-
-static int tabla_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
-{
-	struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
-	return tabla_suspend(tabla, pmesg);
-}
-
-static const struct slim_device_id slimtest_id[] = {
-	{"tabla-slim", 0},
-	{}
-};
-
-static struct slim_driver tabla_slim_driver = {
-	.driver = {
-		.name = "tabla-slim",
-		.owner = THIS_MODULE,
-	},
-	.probe = tabla_slim_probe,
-	.remove = tabla_slim_remove,
-	.id_table = slimtest_id,
-	.resume = tabla_slim_resume,
-	.suspend = tabla_slim_suspend,
-};
-
-static const struct slim_device_id slimtest2x_id[] = {
-	{"tabla2x-slim", 0},
-	{}
-};
-
-static struct slim_driver tabla2x_slim_driver = {
-	.driver = {
-		.name = "tabla2x-slim",
-		.owner = THIS_MODULE,
-	},
-	.probe = tabla_slim_probe,
-	.remove = tabla_slim_remove,
-	.id_table = slimtest2x_id,
-	.resume = tabla_slim_resume,
-	.suspend = tabla_slim_suspend,
-};
-
-#define TABLA_I2C_TOP_LEVEL 0
-#define TABLA_I2C_ANALOG       1
-#define TABLA_I2C_DIGITAL_1    2
-#define TABLA_I2C_DIGITAL_2    3
-
-static struct i2c_device_id tabla_id_table[] = {
-	{"tabla top level", TABLA_I2C_TOP_LEVEL},
-	{"tabla analog", TABLA_I2C_TOP_LEVEL},
-	{"tabla digital1", TABLA_I2C_TOP_LEVEL},
-	{"tabla digital2", TABLA_I2C_TOP_LEVEL},
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, tabla_id_table);
-
-static struct i2c_driver tabla_i2c_driver = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = "tabla-i2c-core",
-	},
-	.id_table = tabla_id_table,
-	.probe = tabla_i2c_probe,
-	.remove = __devexit_p(tabla_i2c_remove),
-	.resume	= tabla_i2c_resume,
-	.suspend = tabla_i2c_suspend,
-};
-
-static int __init tabla_init(void)
-{
-	int ret1, ret2, ret3;
-
-	ret1 = slim_driver_register(&tabla_slim_driver);
-	if (ret1 != 0)
-		pr_err("Failed to register tabla SB driver: %d\n", ret1);
-
-	ret2 = slim_driver_register(&tabla2x_slim_driver);
-	if (ret2 != 0)
-		pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
-
-	ret3 = i2c_add_driver(&tabla_i2c_driver);
-	if (ret3 != 0)
-		pr_err("failed to add the I2C driver\n");
-
-	return (ret1 && ret2 && ret3) ? -1 : 0;
-}
-module_init(tabla_init);
-
-static void __exit tabla_exit(void)
-{
-}
-module_exit(tabla_exit);
-
-MODULE_DESCRIPTION("Tabla core driver");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
deleted file mode 100644
index c6a9c23..0000000
--- a/drivers/mfd/wcd9310-irq.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/irq.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/interrupt.h>
-
-#define BYTE_BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_BYTE))
-#define BIT_BYTE(nr)			((nr) / BITS_PER_BYTE)
-
-struct tabla_irq {
-	bool level;
-};
-
-static struct tabla_irq tabla_irqs[TABLA_NUM_IRQS] = {
-	[0] = { .level = 1},
-/* All other tabla interrupts are edge triggered */
-};
-
-static inline int irq_to_tabla_irq(struct tabla *tabla, int irq)
-{
-	return irq - tabla->irq_base;
-}
-
-static void tabla_irq_lock(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	mutex_lock(&tabla->irq_lock);
-}
-
-static void tabla_irq_sync_unlock(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(tabla->irq_masks_cur); i++) {
-		/* If there's been a change in the mask write it back
-		 * to the hardware.
-		 */
-		if (tabla->irq_masks_cur[i] != tabla->irq_masks_cache[i]) {
-			tabla->irq_masks_cache[i] = tabla->irq_masks_cur[i];
-			tabla_reg_write(tabla, TABLA_A_INTR_MASK0+i,
-				tabla->irq_masks_cur[i]);
-		}
-	}
-
-	mutex_unlock(&tabla->irq_lock);
-}
-
-static void tabla_irq_enable(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	int tabla_irq = irq_to_tabla_irq(tabla, data->irq);
-	tabla->irq_masks_cur[BIT_BYTE(tabla_irq)] &=
-		~(BYTE_BIT_MASK(tabla_irq));
-}
-
-static void tabla_irq_disable(struct irq_data *data)
-{
-	struct tabla *tabla = irq_data_get_irq_chip_data(data);
-	int tabla_irq = irq_to_tabla_irq(tabla, data->irq);
-	tabla->irq_masks_cur[BIT_BYTE(tabla_irq)] |= BYTE_BIT_MASK(tabla_irq);
-}
-
-static struct irq_chip tabla_irq_chip = {
-	.name = "tabla",
-	.irq_bus_lock = tabla_irq_lock,
-	.irq_bus_sync_unlock = tabla_irq_sync_unlock,
-	.irq_disable = tabla_irq_disable,
-	.irq_enable = tabla_irq_enable,
-};
-
-enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
-				     enum tabla_pm_state n)
-{
-	enum tabla_pm_state old;
-	mutex_lock(&tabla->pm_lock);
-	old = tabla->pm_state;
-	if (old == o)
-		tabla->pm_state = n;
-	mutex_unlock(&tabla->pm_lock);
-	return old;
-}
-EXPORT_SYMBOL_GPL(tabla_pm_cmpxchg);
-
-void tabla_lock_sleep(struct tabla *tabla)
-{
-	enum tabla_pm_state os;
-
-	/* tabla_{lock/unlock}_sleep will be called by tabla_irq_thread
-	 * and its subroutines only motly.
-	 * but btn0_lpress_fn is not tabla_irq_thread's subroutine and
-	 * it can race with tabla_irq_thread.
-	 * so need to embrace wlock_holders with mutex.
-	 */
-	mutex_lock(&tabla->pm_lock);
-	if (tabla->wlock_holders++ == 0)
-		wake_lock(&tabla->wlock);
-	mutex_unlock(&tabla->pm_lock);
-	while (!wait_event_timeout(tabla->pm_wq,
-			((os = tabla_pm_cmpxchg(tabla, TABLA_PM_SLEEPABLE,
-						TABLA_PM_AWAKE)) ==
-						    TABLA_PM_SLEEPABLE ||
-			 (os == TABLA_PM_AWAKE)),
-			5 * HZ)) {
-		pr_err("%s: system didn't resume within 5000ms, state %d, "
-		       "wlock %d\n", __func__, tabla->pm_state,
-		       tabla->wlock_holders);
-		WARN_ON_ONCE(1);
-	}
-	wake_up_all(&tabla->pm_wq);
-}
-EXPORT_SYMBOL_GPL(tabla_lock_sleep);
-
-void tabla_unlock_sleep(struct tabla *tabla)
-{
-	mutex_lock(&tabla->pm_lock);
-	if (--tabla->wlock_holders == 0) {
-		tabla->pm_state = TABLA_PM_SLEEPABLE;
-		wake_unlock(&tabla->wlock);
-	}
-	mutex_unlock(&tabla->pm_lock);
-	wake_up_all(&tabla->pm_wq);
-}
-EXPORT_SYMBOL_GPL(tabla_unlock_sleep);
-
-static irqreturn_t tabla_irq_thread(int irq, void *data)
-{
-	int ret;
-	struct tabla *tabla = data;
-	u8 status[TABLA_NUM_IRQ_REGS];
-	unsigned int i;
-
-	tabla_lock_sleep(tabla);
-	ret = tabla_bulk_read(tabla, TABLA_A_INTR_STATUS0,
-			       TABLA_NUM_IRQ_REGS, status);
-	if (ret < 0) {
-		dev_err(tabla->dev, "Failed to read interrupt status: %d\n",
-			ret);
-		tabla_unlock_sleep(tabla);
-		return IRQ_NONE;
-	}
-	/* Apply masking */
-	for (i = 0; i < TABLA_NUM_IRQ_REGS; i++)
-		status[i] &= ~tabla->irq_masks_cur[i];
-
-	/* Find out which interrupt was triggered and call that interrupt's
-	 * handler function
-	 */
-	for (i = 0; i < TABLA_NUM_IRQS; i++) {
-		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
-			if ((i <= TABLA_IRQ_MBHC_INSERTION) &&
-				(i >= TABLA_IRQ_MBHC_REMOVAL)) {
-				tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
-					BIT_BYTE(i), BYTE_BIT_MASK(i));
-				if (tabla_get_intf_type() ==
-					TABLA_INTERFACE_TYPE_I2C)
-					tabla_reg_write(tabla,
-						TABLA_A_INTR_MODE, 0x02);
-				handle_nested_irq(tabla->irq_base + i);
-			} else {
-				handle_nested_irq(tabla->irq_base + i);
-				tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
-					BIT_BYTE(i), BYTE_BIT_MASK(i));
-				if (tabla_get_intf_type() ==
-					TABLA_INTERFACE_TYPE_I2C)
-					tabla_reg_write(tabla,
-						TABLA_A_INTR_MODE, 0x02);
-			}
-			break;
-		}
-	}
-	tabla_unlock_sleep(tabla);
-
-	return IRQ_HANDLED;
-}
-
-int tabla_irq_init(struct tabla *tabla)
-{
-	int ret;
-	unsigned int i, cur_irq;
-
-	mutex_init(&tabla->irq_lock);
-
-	if (!tabla->irq) {
-		dev_warn(tabla->dev,
-			 "No interrupt specified, no interrupts\n");
-		tabla->irq_base = 0;
-		return 0;
-	}
-
-	if (!tabla->irq_base) {
-		dev_err(tabla->dev,
-			"No interrupt base specified, no interrupts\n");
-		return 0;
-	}
-	/* Mask the individual interrupt sources */
-	for (i = 0, cur_irq = tabla->irq_base; i < TABLA_NUM_IRQS; i++,
-		cur_irq++) {
-
-		irq_set_chip_data(cur_irq, tabla);
-
-		if (tabla_irqs[i].level)
-			irq_set_chip_and_handler(cur_irq, &tabla_irq_chip,
-					 handle_level_irq);
-		else
-			irq_set_chip_and_handler(cur_irq, &tabla_irq_chip,
-					 handle_edge_irq);
-
-		irq_set_nested_thread(cur_irq, 1);
-
-		/* ARM needs us to explicitly flag the IRQ as valid
-		 * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
-		set_irq_flags(cur_irq, IRQF_VALID);
-#else
-		set_irq_noprobe(cur_irq);
-#endif
-
-		tabla->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
-		tabla->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
-		tabla->irq_level[BIT_BYTE(i)] |= tabla_irqs[i].level <<
-			(i % BITS_PER_BYTE);
-	}
-	for (i = 0; i < TABLA_NUM_IRQ_REGS; i++) {
-		/* Initialize interrupt mask and level registers */
-		tabla_reg_write(tabla, TABLA_A_INTR_LEVEL0 + i,
-			tabla->irq_level[i]);
-		tabla_reg_write(tabla, TABLA_A_INTR_MASK0 + i,
-			tabla->irq_masks_cur[i]);
-	}
-
-	ret = request_threaded_irq(tabla->irq, NULL, tabla_irq_thread,
-				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-				   "tabla", tabla);
-	if (ret != 0)
-		dev_err(tabla->dev, "Failed to request IRQ %d: %d\n",
-			tabla->irq, ret);
-	else {
-		ret = enable_irq_wake(tabla->irq);
-		if (ret == 0) {
-			ret = device_init_wakeup(tabla->dev, 1);
-			if (ret) {
-				dev_err(tabla->dev, "Failed to init device"
-					"wakeup : %d\n", ret);
-				disable_irq_wake(tabla->irq);
-			}
-		} else
-			dev_err(tabla->dev, "Failed to set wake interrupt on"
-				" IRQ %d: %d\n", tabla->irq, ret);
-		if (ret)
-			free_irq(tabla->irq, tabla);
-	}
-
-	if (ret)
-		mutex_destroy(&tabla->irq_lock);
-
-	return ret;
-}
-
-void tabla_irq_exit(struct tabla *tabla)
-{
-	if (tabla->irq) {
-		disable_irq_wake(tabla->irq);
-		free_irq(tabla->irq, tabla);
-		device_init_wakeup(tabla->dev, 0);
-	}
-	mutex_destroy(&tabla->irq_lock);
-}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
new file mode 100644
index 0000000..59a4283
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -0,0 +1,1126 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/i2c.h>
+#include <sound/soc.h>
+
+#define WCD9XXX_SLIM_GLA_MAX_RETRIES 5
+#define WCD9XXX_REGISTER_START_OFFSET 0x800
+#define WCD9XXX_SLIM_RW_MAX_TRIES 3
+
+#define MAX_WCD9XXX_DEVICE	4
+#define WCD9XXX_I2C_MODE	0x03
+
+struct wcd9xxx_i2c {
+	struct i2c_client *client;
+	struct i2c_msg xfer_msg[2];
+	struct mutex xfer_lock;
+	int mod_id;
+};
+
+struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
+static int wcd9xxx_intf;
+
+static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		       int bytes, void *dest, bool interface_reg)
+{
+	int ret;
+	u8 *buf = dest;
+
+	if (bytes <= 0) {
+		dev_err(wcd9xxx->dev, "Invalid byte read length %d\n", bytes);
+		return -EINVAL;
+	}
+
+	ret = wcd9xxx->read_dev(wcd9xxx, reg, bytes, dest, interface_reg);
+	if (ret < 0) {
+		dev_err(wcd9xxx->dev, "Codec read failed\n");
+		return ret;
+	} else
+		dev_dbg(wcd9xxx->dev, "Read 0x%02x from R%d(0x%x)\n",
+			 *buf, reg, reg);
+
+	return 0;
+}
+int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+{
+	u8 val;
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, false);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	if (ret < 0)
+		return ret;
+	else
+		return val;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_reg_read);
+
+static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *src, bool interface_reg)
+{
+	u8 *buf = src;
+
+	if (bytes <= 0) {
+		pr_err("%s: Error, invalid write length\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(wcd9xxx->dev, "Write %02x to R%d(0x%x)\n",
+		 *buf, reg, reg);
+
+	return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
+}
+
+int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     u8 val)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, false);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_reg_write);
+
+static u8 wcd9xxx_pgd_la;
+static u8 wcd9xxx_inf_la;
+
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+{
+	u8 val;
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, true);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	if (ret < 0)
+		return ret;
+	else
+		return val;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_read);
+
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     u8 val)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, true);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_write);
+
+int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     int count, u8 *buf)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+
+	ret = wcd9xxx_read(wcd9xxx, reg, count, buf, false);
+
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_bulk_read);
+
+int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     int count, u8 *buf)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+
+	ret = wcd9xxx_write(wcd9xxx, reg, count, buf, false);
+
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_bulk_write);
+
+static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
+				int bytes, void *dest, bool interface)
+{
+	int ret;
+	struct slim_ele_access msg;
+	int slim_read_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+	msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+	msg.num_bytes = bytes;
+	msg.comp = NULL;
+
+	while (1) {
+		mutex_lock(&wcd9xxx->xfer_lock);
+		ret = slim_request_val_element(interface ?
+			       wcd9xxx->slim_slave : wcd9xxx->slim,
+			       &msg, dest, bytes);
+		mutex_unlock(&wcd9xxx->xfer_lock);
+		if (likely(ret == 0) || (--slim_read_tries == 0))
+			break;
+		usleep_range(5000, 5000);
+	}
+
+	if (ret)
+		pr_err("%s: Error, Codec read failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+/* Interface specifies whether the write is to the interface or general
+ * registers.
+ */
+static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx,
+		unsigned short reg, int bytes, void *src, bool interface)
+{
+	int ret;
+	struct slim_ele_access msg;
+	int slim_write_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+	msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+	msg.num_bytes = bytes;
+	msg.comp = NULL;
+
+	while (1) {
+		mutex_lock(&wcd9xxx->xfer_lock);
+		ret = slim_change_val_element(interface ?
+			      wcd9xxx->slim_slave : wcd9xxx->slim,
+			      &msg, src, bytes);
+		mutex_unlock(&wcd9xxx->xfer_lock);
+		if (likely(ret == 0) || (--slim_write_tries == 0))
+			break;
+		usleep_range(5000, 5000);
+	}
+
+	if (ret)
+		pr_err("%s: Error, Codec write failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static struct mfd_cell tabla1x_devs[] = {
+	{
+		.name = "tabla1x_codec",
+	},
+};
+
+static struct mfd_cell tabla_devs[] = {
+	{
+		.name = "tabla_codec",
+	},
+};
+
+static struct mfd_cell sitar_devs[] = {
+	{
+		.name = "sitar_codec",
+	},
+};
+
+static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
+{
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
+	usleep_range(5000, 5000);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
+}
+
+static void wcd9xxx_bring_down(struct wcd9xxx *wcd9xxx)
+{
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
+	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
+}
+
+static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
+{
+	int ret;
+
+	if (wcd9xxx->reset_gpio) {
+		ret = gpio_request(wcd9xxx->reset_gpio, "CDC_RESET");
+		if (ret) {
+			pr_err("%s: Failed to request gpio %d\n", __func__,
+				wcd9xxx->reset_gpio);
+			wcd9xxx->reset_gpio = 0;
+			return ret;
+		}
+
+		gpio_direction_output(wcd9xxx->reset_gpio, 1);
+		msleep(20);
+		gpio_direction_output(wcd9xxx->reset_gpio, 0);
+		msleep(20);
+		gpio_direction_output(wcd9xxx->reset_gpio, 1);
+		msleep(20);
+	}
+	return 0;
+}
+
+static void wcd9xxx_free_reset(struct wcd9xxx *wcd9xxx)
+{
+	if (wcd9xxx->reset_gpio) {
+		gpio_free(wcd9xxx->reset_gpio);
+		wcd9xxx->reset_gpio = 0;
+	}
+}
+
+static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
+{
+	int ret;
+	u8 idbyte_0, idbyte_1, idbyte_2, idbyte_3;
+	struct mfd_cell *wcd9xxx_dev = NULL;
+	int wcd9xxx_dev_size = 0;
+
+	mutex_init(&wcd9xxx->io_lock);
+	mutex_init(&wcd9xxx->xfer_lock);
+
+	mutex_init(&wcd9xxx->pm_lock);
+	wcd9xxx->wlock_holders = 0;
+	wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+	init_waitqueue_head(&wcd9xxx->pm_wq);
+	wake_lock_init(&wcd9xxx->wlock, WAKE_LOCK_IDLE, "wcd9310-irq");
+
+	dev_set_drvdata(wcd9xxx->dev, wcd9xxx);
+
+	wcd9xxx_bring_up(wcd9xxx);
+
+	ret = wcd9xxx_irq_init(wcd9xxx);
+	if (ret) {
+		pr_err("IRQ initialization failed\n");
+		goto err;
+	}
+
+	idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
+	idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
+	idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
+	idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
+
+	wcd9xxx->version = wcd9xxx_reg_read(wcd9xxx,
+			WCD9XXX_A_CHIP_VERSION) & 0x1F;
+	pr_info("%s : Codec version %u initialized\n",
+		__func__, wcd9xxx->version);
+	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 (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);
+	}
+
+	ret = mfd_add_devices(wcd9xxx->dev, -1,
+		      wcd9xxx_dev, wcd9xxx_dev_size,
+		      NULL, 0);
+	if (ret != 0) {
+		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
+		goto err_irq;
+	}
+	return ret;
+err_irq:
+	wcd9xxx_irq_exit(wcd9xxx);
+err:
+	wcd9xxx_bring_down(wcd9xxx);
+	wake_lock_destroy(&wcd9xxx->wlock);
+	mutex_destroy(&wcd9xxx->pm_lock);
+	mutex_destroy(&wcd9xxx->io_lock);
+	mutex_destroy(&wcd9xxx->xfer_lock);
+	return ret;
+}
+
+static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
+{
+	wcd9xxx_irq_exit(wcd9xxx);
+	wcd9xxx_bring_down(wcd9xxx);
+	wcd9xxx_free_reset(wcd9xxx);
+	mutex_destroy(&wcd9xxx->pm_lock);
+	wake_lock_destroy(&wcd9xxx->wlock);
+	mutex_destroy(&wcd9xxx->io_lock);
+	mutex_destroy(&wcd9xxx->xfer_lock);
+	slim_remove_device(wcd9xxx->slim_slave);
+	kfree(wcd9xxx);
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+struct wcd9xxx *debugCodec;
+
+static struct dentry *debugfs_wcd9xxx_dent;
+static struct dentry *debugfs_peek;
+static struct dentry *debugfs_poke;
+
+static unsigned char read_data;
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token != NULL) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (strict_strtoul(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[8];
+
+	snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
+	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+		strnlen(lbuf, 7));
+}
+
+
+static ssize_t codec_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *access_str = filp->private_data;
+	char lbuf[32];
+	int rc;
+	long int param[5];
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+
+	if (!strncmp(access_str, "poke", 6)) {
+		/* write */
+		rc = get_parameters(lbuf, param, 2);
+		if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) &&
+			(rc == 0))
+			wcd9xxx_interface_reg_write(debugCodec, param[0],
+				param[1]);
+		else
+			rc = -EINVAL;
+	} else if (!strncmp(access_str, "peek", 6)) {
+		/* read */
+		rc = get_parameters(lbuf, param, 1);
+		if ((param[0] <= 0x3FF) && (rc == 0))
+			read_data = wcd9xxx_interface_reg_read(debugCodec,
+				param[0]);
+		else
+			rc = -EINVAL;
+	}
+
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+	.read = codec_debug_read
+};
+#endif
+
+static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx)
+{
+	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);
+	if (!wcd9xxx->supplies) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++)
+		wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
+
+	ret = regulator_bulk_get(wcd9xxx->dev, ARRAY_SIZE(pdata->regulator),
+				 wcd9xxx->supplies);
+	if (ret != 0) {
+		dev_err(wcd9xxx->dev, "Failed to get supplies: err = %d\n",
+							ret);
+		goto err_supplies;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		ret = regulator_set_voltage(wcd9xxx->supplies[i].consumer,
+			pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+		if (ret) {
+			pr_err("%s: Setting regulator voltage failed for "
+				"regulator %s err = %d\n", __func__,
+				wcd9xxx->supplies[i].supply, ret);
+			goto err_get;
+		}
+
+		ret = regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer,
+			pdata->regulator[i].optimum_uA);
+		if (ret < 0) {
+			pr_err("%s: Setting regulator optimum mode failed for "
+				"regulator %s err = %d\n", __func__,
+				wcd9xxx->supplies[i].supply, ret);
+			goto err_get;
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pdata->regulator),
+				    wcd9xxx->supplies);
+	if (ret != 0) {
+		dev_err(wcd9xxx->dev, "Failed to enable supplies: err = %d\n",
+				ret);
+		goto err_configure;
+	}
+	return ret;
+
+err_configure:
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
+			pdata->regulator[i].max_uV);
+		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
+	}
+err_get:
+	regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+err_supplies:
+	kfree(wcd9xxx->supplies);
+err:
+	return ret;
+}
+
+static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx)
+{
+	int i;
+	struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
+
+	regulator_bulk_disable(ARRAY_SIZE(pdata->regulator),
+				    wcd9xxx->supplies);
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
+			pdata->regulator[i].max_uV);
+		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
+	}
+	regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+	kfree(wcd9xxx->supplies);
+}
+
+int wcd9xxx_get_intf_type(void)
+{
+	return wcd9xxx_intf;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
+
+struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
+{
+	u16 mask = 0x0f00;
+	int value = 0;
+	struct wcd9xxx_i2c *wcd9xxx = NULL;
+	value = ((reg & mask) >> 8) & 0x000f;
+	switch (value) {
+	case 0:
+		wcd9xxx = &wcd9xxx_modules[0];
+		break;
+	case 1:
+		wcd9xxx = &wcd9xxx_modules[1];
+		break;
+	case 2:
+		wcd9xxx = &wcd9xxx_modules[2];
+		break;
+	case 3:
+		wcd9xxx = &wcd9xxx_modules[3];
+		break;
+	default:
+		break;
+	}
+	return wcd9xxx;
+}
+
+int wcd9xxx_i2c_write_device(u16 reg, u8 *value,
+				u32 bytes)
+{
+
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	u8 data[bytes + 1];
+	struct wcd9xxx_i2c *wcd9xxx;
+
+	wcd9xxx = get_i2c_wcd9xxx_device_info(reg);
+	if (wcd9xxx == NULL || wcd9xxx->client == NULL) {
+		pr_err("failed to get device info\n");
+		return -ENODEV;
+	}
+	reg_addr = (u8)reg;
+	msg = &wcd9xxx->xfer_msg[0];
+	msg->addr = wcd9xxx->client->addr;
+	msg->len = bytes + 1;
+	msg->flags = 0;
+	data[0] = reg;
+	data[1] = *value;
+	msg->buf = data;
+	ret = i2c_transfer(wcd9xxx->client->adapter, wcd9xxx->xfer_msg, 1);
+	/* Try again if the write fails */
+	if (ret != 1) {
+		ret = i2c_transfer(wcd9xxx->client->adapter,
+						wcd9xxx->xfer_msg, 1);
+		if (ret != 1) {
+			pr_err("failed to write the device\n");
+			return ret;
+		}
+	}
+	pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
+	return 0;
+}
+
+
+int wcd9xxx_i2c_read_device(unsigned short reg,
+				  int bytes, unsigned char *dest)
+{
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	struct wcd9xxx_i2c *wcd9xxx;
+	u8 i = 0;
+
+	wcd9xxx = get_i2c_wcd9xxx_device_info(reg);
+	if (wcd9xxx == NULL || wcd9xxx->client == NULL) {
+		pr_err("failed to get device info\n");
+		return -ENODEV;
+	}
+	for (i = 0; i < bytes; i++) {
+		reg_addr = (u8)reg++;
+		msg = &wcd9xxx->xfer_msg[0];
+		msg->addr = wcd9xxx->client->addr;
+		msg->len = 1;
+		msg->flags = 0;
+		msg->buf = &reg_addr;
+
+		msg = &wcd9xxx->xfer_msg[1];
+		msg->addr = wcd9xxx->client->addr;
+		msg->len = 1;
+		msg->flags = I2C_M_RD;
+		msg->buf = dest++;
+		ret = i2c_transfer(wcd9xxx->client->adapter,
+				wcd9xxx->xfer_msg, 2);
+
+		/* Try again if read fails first time */
+		if (ret != 2) {
+			ret = i2c_transfer(wcd9xxx->client->adapter,
+							wcd9xxx->xfer_msg, 2);
+			if (ret != 2) {
+				pr_err("failed to read wcd9xxx register\n");
+				return ret;
+			}
+		}
+	}
+	return 0;
+}
+
+int wcd9xxx_i2c_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *dest, bool interface_reg)
+{
+	return wcd9xxx_i2c_read_device(reg, bytes, dest);
+}
+
+int wcd9xxx_i2c_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			 int bytes, void *src, bool interface_reg)
+{
+	return wcd9xxx_i2c_write_device(reg, src, bytes);
+}
+
+static int __devinit wcd9xxx_i2c_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata = client->dev.platform_data;
+	int val = 0;
+	int ret = 0;
+	static int device_id;
+
+	if (device_id > 0) {
+		wcd9xxx_modules[device_id++].client = client;
+		pr_info("probe for other slaves devices of tabla\n");
+		return ret;
+	}
+
+	wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+	if (wcd9xxx == NULL) {
+		pr_err("%s: error, allocation failed\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	if (!pdata) {
+		dev_dbg(&client->dev, "no platform data?\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+		dev_dbg(&client->dev, "can't talk I2C?\n");
+		ret = -EIO;
+		goto fail;
+	}
+	dev_set_drvdata(&client->dev, wcd9xxx);
+	wcd9xxx->dev = &client->dev;
+	wcd9xxx->reset_gpio = pdata->reset_gpio;
+
+	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Fail to enable Codec supplies\n", __func__);
+		goto err_codec;
+	}
+
+	usleep_range(5, 5);
+	ret = wcd9xxx_reset(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Resetting Codec failed\n", __func__);
+		goto err_supplies;
+	}
+	wcd9xxx_modules[device_id++].client = client;
+
+	wcd9xxx->read_dev = wcd9xxx_i2c_read;
+	wcd9xxx->write_dev = wcd9xxx_i2c_write;
+	wcd9xxx->irq = pdata->irq;
+	wcd9xxx->irq_base = pdata->irq_base;
+
+	/*read the tabla status before initializing the device type*/
+	ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+	if ((ret < 0) || (val != WCD9XXX_I2C_MODE)) {
+		pr_err("failed to read the wcd9xxx status\n");
+		goto err_device_init;
+	}
+
+	ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+	if (ret) {
+		pr_err("%s: error, initializing device failed\n", __func__);
+		goto err_device_init;
+	}
+	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
+
+	return ret;
+err_device_init:
+	wcd9xxx_free_reset(wcd9xxx);
+err_supplies:
+	wcd9xxx_disable_supplies(wcd9xxx);
+err_codec:
+	kfree(wcd9xxx);
+fail:
+	return ret;
+}
+
+static int __devexit wcd9xxx_i2c_remove(struct i2c_client *client)
+{
+	struct wcd9xxx *wcd9xxx;
+
+	pr_debug("exit\n");
+	wcd9xxx = dev_get_drvdata(&client->dev);
+	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_device_exit(wcd9xxx);
+	return 0;
+}
+
+static int wcd9xxx_slim_probe(struct slim_device *slim)
+{
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata;
+	int ret = 0;
+	int sgla_retry_cnt;
+
+	dev_info(&slim->dev, "Initialized slim device %s\n", slim->name);
+	pdata = slim->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&slim->dev, "Error, no platform data\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+	if (wcd9xxx == NULL) {
+		pr_err("%s: error, allocation failed\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+	if (!slim->ctrl) {
+		pr_err("Error, no SLIMBUS control data\n");
+		ret = -EINVAL;
+		goto err_codec;
+	}
+	wcd9xxx->slim = slim;
+	slim_set_clientdata(slim, wcd9xxx);
+	wcd9xxx->reset_gpio = pdata->reset_gpio;
+	wcd9xxx->dev = &slim->dev;
+
+	ret = wcd9xxx_enable_supplies(wcd9xxx);
+	if (ret)
+		goto err_codec;
+	usleep_range(5, 5);
+
+	ret = wcd9xxx_reset(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Resetting Codec failed\n", __func__);
+		goto err_supplies;
+	}
+
+	ret = slim_get_logical_addr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
+		ARRAY_SIZE(wcd9xxx->slim->e_addr), &wcd9xxx->slim->laddr);
+	if (ret) {
+		pr_err("fail to get slimbus logical address %d\n", ret);
+		goto err_reset;
+	}
+	wcd9xxx->read_dev = wcd9xxx_slim_read_device;
+	wcd9xxx->write_dev = wcd9xxx_slim_write_device;
+	wcd9xxx->irq = pdata->irq;
+	wcd9xxx->irq_base = pdata->irq_base;
+	wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
+
+	if (pdata->num_irqs < TABLA_NUM_IRQS) {
+		pr_err("%s: Error, not enough interrupt lines allocated\n",
+			__func__);
+		goto err_reset;
+	}
+
+	wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
+
+	ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
+	if (ret) {
+		pr_err("%s: error, adding SLIMBUS device failed\n", __func__);
+		goto err_reset;
+	}
+
+	sgla_retry_cnt = 0;
+
+	while (1) {
+		ret = slim_get_logical_addr(wcd9xxx->slim_slave,
+			wcd9xxx->slim_slave->e_addr,
+			ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
+			&wcd9xxx->slim_slave->laddr);
+		if (ret) {
+			if (sgla_retry_cnt++ < WCD9XXX_SLIM_GLA_MAX_RETRIES) {
+				/* Give SLIMBUS slave time to report present
+				   and be ready.
+				 */
+				usleep_range(1000, 1000);
+				pr_debug("%s: retry slim_get_logical_addr()\n",
+					__func__);
+				continue;
+			}
+			pr_err("fail to get slimbus slave logical address"
+				" %d\n", ret);
+			goto err_slim_add;
+		}
+		break;
+	}
+	wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
+	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
+
+	ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+	if (ret) {
+		pr_err("%s: error, initializing device failed\n", __func__);
+		goto err_slim_add;
+	}
+	wcd9xxx_init_slimslave(wcd9xxx, wcd9xxx_pgd_la);
+#ifdef CONFIG_DEBUG_FS
+	debugCodec = wcd9xxx;
+
+	debugfs_wcd9xxx_dent = debugfs_create_dir
+		("wcd9310_slimbus_interface_device", 0);
+	if (!IS_ERR(debugfs_wcd9xxx_dent)) {
+		debugfs_peek = debugfs_create_file("peek",
+		S_IFREG | S_IRUGO, debugfs_wcd9xxx_dent,
+		(void *) "peek", &codec_debug_ops);
+
+		debugfs_poke = debugfs_create_file("poke",
+		S_IFREG | S_IRUGO, debugfs_wcd9xxx_dent,
+		(void *) "poke", &codec_debug_ops);
+	}
+#endif
+
+	return ret;
+
+err_slim_add:
+	slim_remove_device(wcd9xxx->slim_slave);
+err_reset:
+	wcd9xxx_free_reset(wcd9xxx);
+err_supplies:
+	wcd9xxx_disable_supplies(wcd9xxx);
+err_codec:
+	kfree(wcd9xxx);
+err:
+	return ret;
+}
+static int wcd9xxx_slim_remove(struct slim_device *pdev)
+{
+	struct wcd9xxx *wcd9xxx;
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(debugfs_peek);
+	debugfs_remove(debugfs_poke);
+	debugfs_remove(debugfs_wcd9xxx_dent);
+#endif
+	wcd9xxx = slim_get_devicedata(pdev);
+	wcd9xxx_deinit_slimslave(wcd9xxx);
+	slim_remove_device(wcd9xxx->slim_slave);
+	wcd9xxx_disable_supplies(wcd9xxx);
+	wcd9xxx_device_exit(wcd9xxx);
+	return 0;
+}
+
+static int wcd9xxx_resume(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+			 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+	} else {
+		pr_warn("%s: system is already awake, state %d wlock %d\n",
+			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx->pm_lock);
+	wake_up_all(&wcd9xxx->pm_wq);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_resume(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	return wcd9xxx_resume(wcd9xxx);
+}
+
+static int wcd9xxx_i2c_resume(struct i2c_client *i2cdev)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
+	if (wcd9xxx)
+		return wcd9xxx_resume(wcd9xxx);
+	else
+		return 0;
+}
+
+static int wcd9xxx_suspend(struct wcd9xxx *wcd9xxx, pm_message_t pmesg)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	/* wake_lock() can be called after this suspend chain call started.
+	 * thus suspend can be called while wlock is being held */
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (wcd9xxx->pm_state == WCD9XXX_PM_SLEEPABLE) {
+		pr_debug("%s: suspending system, state %d, wlock %d\n",
+			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		wcd9xxx->pm_state = WCD9XXX_PM_ASLEEP;
+	} else if (wcd9xxx->pm_state == WCD9XXX_PM_AWAKE) {
+		/* unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+		 * then set to WCD9XXX_PM_ASLEEP */
+		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		mutex_unlock(&wcd9xxx->pm_lock);
+		if (!(wait_event_timeout(wcd9xxx->pm_wq,
+					 wcd9xxx_pm_cmpxchg(wcd9xxx,
+						  WCD9XXX_PM_SLEEPABLE,
+						  WCD9XXX_PM_ASLEEP) ==
+							WCD9XXX_PM_SLEEPABLE,
+					 HZ))) {
+			pr_debug("%s: suspend failed state %d, wlock %d\n",
+				 __func__, wcd9xxx->pm_state,
+				 wcd9xxx->wlock_holders);
+			ret = -EBUSY;
+		} else {
+			pr_debug("%s: done, state %d, wlock %d\n", __func__,
+				 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+		}
+		mutex_lock(&wcd9xxx->pm_lock);
+	} else if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_warn("%s: system is already suspended, state %d, wlock %dn",
+			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx->pm_lock);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	return wcd9xxx_suspend(wcd9xxx, pmesg);
+}
+
+static int wcd9xxx_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
+	if (wcd9xxx)
+		return wcd9xxx_suspend(wcd9xxx, pmesg);
+	else
+		return 0;
+}
+
+static const struct slim_device_id sitar_slimtest_id[] = {
+	{"sitar-slim", 0},
+	{}
+};
+static struct slim_driver sitar_slim_driver = {
+	.driver = {
+		.name = "sitar-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = sitar_slimtest_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
+static const struct slim_device_id slimtest_id[] = {
+	{"tabla-slim", 0},
+	{}
+};
+
+static struct slim_driver tabla_slim_driver = {
+	.driver = {
+		.name = "tabla-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = slimtest_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
+static const struct slim_device_id slimtest2x_id[] = {
+	{"tabla2x-slim", 0},
+	{}
+};
+
+static struct slim_driver tabla2x_slim_driver = {
+	.driver = {
+		.name = "tabla2x-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = slimtest2x_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
+#define TABLA_I2C_TOP_LEVEL 0
+#define TABLA_I2C_ANALOG       1
+#define TABLA_I2C_DIGITAL_1    2
+#define TABLA_I2C_DIGITAL_2    3
+
+static struct i2c_device_id tabla_id_table[] = {
+	{"tabla top level", TABLA_I2C_TOP_LEVEL},
+	{"tabla analog", TABLA_I2C_TOP_LEVEL},
+	{"tabla digital1", TABLA_I2C_TOP_LEVEL},
+	{"tabla digital2", TABLA_I2C_TOP_LEVEL},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static struct i2c_driver tabla_i2c_driver = {
+	.driver                 = {
+		.owner          =       THIS_MODULE,
+		.name           =       "tabla-i2c-core",
+	},
+	.id_table               =       tabla_id_table,
+	.probe                  =       wcd9xxx_i2c_probe,
+	.remove                 =       __devexit_p(wcd9xxx_i2c_remove),
+	.resume	= wcd9xxx_i2c_resume,
+	.suspend = wcd9xxx_i2c_suspend,
+};
+
+static int __init wcd9xxx_init(void)
+{
+	int ret1, ret2, ret3, ret4;
+
+	ret1 = slim_driver_register(&tabla_slim_driver);
+	if (ret1 != 0)
+		pr_err("Failed to register tabla SB driver: %d\n", ret1);
+
+	ret2 = slim_driver_register(&tabla2x_slim_driver);
+	if (ret2 != 0)
+		pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
+
+	ret3 = i2c_add_driver(&tabla_i2c_driver);
+	if (ret3 != 0)
+		pr_err("failed to add the I2C driver\n");
+
+	ret4 = slim_driver_register(&sitar_slim_driver);
+	if (ret1 != 0)
+		pr_err("Failed to register sitar SB driver: %d\n", ret4);
+
+	return (ret1 && ret2 && ret3 && ret4) ? -1 : 0;
+}
+module_init(wcd9xxx_init);
+
+static void __exit wcd9xxx_exit(void)
+{
+}
+module_exit(wcd9xxx_exit);
+
+MODULE_DESCRIPTION("Codec core driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
new file mode 100644
index 0000000..86c01ee
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -0,0 +1,286 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/interrupt.h>
+
+#define BYTE_BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_BYTE))
+#define BIT_BYTE(nr)			((nr) / BITS_PER_BYTE)
+
+struct wcd9xxx_irq {
+	bool level;
+};
+
+static struct wcd9xxx_irq wcd9xxx_irqs[TABLA_NUM_IRQS] = {
+	[0] = { .level = 1},
+/* All other wcd9xxx interrupts are edge triggered */
+};
+
+static inline int irq_to_wcd9xxx_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+	return irq - wcd9xxx->irq_base;
+}
+
+static void wcd9xxx_irq_lock(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	mutex_lock(&wcd9xxx->irq_lock);
+}
+
+static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
+		/* If there's been a change in the mask write it back
+		 * to the hardware.
+		 */
+		if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
+			wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
+			wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0+i,
+				wcd9xxx->irq_masks_cur[i]);
+		}
+	}
+
+	mutex_unlock(&wcd9xxx->irq_lock);
+}
+
+static void wcd9xxx_irq_enable(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
+		~(BYTE_BIT_MASK(wcd9xxx_irq));
+}
+
+static void wcd9xxx_irq_disable(struct irq_data *data)
+{
+	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
+			|= BYTE_BIT_MASK(wcd9xxx_irq);
+}
+
+static struct irq_chip wcd9xxx_irq_chip = {
+	.name = "wcd9xxx",
+	.irq_bus_lock = wcd9xxx_irq_lock,
+	.irq_bus_sync_unlock = wcd9xxx_irq_sync_unlock,
+	.irq_disable = wcd9xxx_irq_disable,
+	.irq_enable = wcd9xxx_irq_enable,
+};
+
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
+		enum wcd9xxx_pm_state o,
+		enum wcd9xxx_pm_state n)
+{
+	enum wcd9xxx_pm_state old;
+	mutex_lock(&wcd9xxx->pm_lock);
+	old = wcd9xxx->pm_state;
+	if (old == o)
+		wcd9xxx->pm_state = n;
+	mutex_unlock(&wcd9xxx->pm_lock);
+	return old;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_pm_cmpxchg);
+
+void wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx)
+{
+	enum wcd9xxx_pm_state os;
+
+	/* wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+	 * and its subroutines only motly.
+	 * but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
+	 * it can race with wcd9xxx_irq_thread.
+	 * so need to embrace wlock_holders with mutex.
+	 */
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (wcd9xxx->wlock_holders++ == 0)
+		wake_lock(&wcd9xxx->wlock);
+	mutex_unlock(&wcd9xxx->pm_lock);
+	while (!wait_event_timeout(wcd9xxx->pm_wq,
+			((os = wcd9xxx_pm_cmpxchg(wcd9xxx, WCD9XXX_PM_SLEEPABLE,
+						WCD9XXX_PM_AWAKE)) ==
+						    WCD9XXX_PM_SLEEPABLE ||
+			 (os == WCD9XXX_PM_AWAKE)),
+			5 * HZ)) {
+		pr_err("%s: system didn't resume within 5000ms, state %d, "
+		       "wlock %d\n", __func__, wcd9xxx->pm_state,
+		       wcd9xxx->wlock_holders);
+		WARN_ON_ONCE(1);
+	}
+	wake_up_all(&wcd9xxx->pm_wq);
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_lock_sleep);
+
+void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx)
+{
+	mutex_lock(&wcd9xxx->pm_lock);
+	if (--wcd9xxx->wlock_holders == 0) {
+		wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+		wake_unlock(&wcd9xxx->wlock);
+	}
+	mutex_unlock(&wcd9xxx->pm_lock);
+	wake_up_all(&wcd9xxx->pm_wq);
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep);
+
+static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
+{
+	int ret;
+	struct wcd9xxx *wcd9xxx = data;
+	u8 status[WCD9XXX_NUM_IRQ_REGS];
+	unsigned int i;
+
+	wcd9xxx_lock_sleep(wcd9xxx);
+	ret = wcd9xxx_bulk_read(wcd9xxx, TABLA_A_INTR_STATUS0,
+			       WCD9XXX_NUM_IRQ_REGS, status);
+	if (ret < 0) {
+		dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
+			ret);
+		wcd9xxx_unlock_sleep(wcd9xxx);
+		return IRQ_NONE;
+	}
+	/* Apply masking */
+	for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++)
+		status[i] &= ~wcd9xxx->irq_masks_cur[i];
+
+	/* Find out which interrupt was triggered and call that interrupt's
+	 * handler function
+	 */
+	for (i = 0; i < TABLA_NUM_IRQS; i++) {
+		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
+			if ((i <= TABLA_IRQ_MBHC_INSERTION) &&
+				(i >= TABLA_IRQ_MBHC_REMOVAL)) {
+				wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
+					BIT_BYTE(i), BYTE_BIT_MASK(i));
+				if (wcd9xxx_get_intf_type() ==
+					WCD9XXX_INTERFACE_TYPE_I2C)
+					wcd9xxx_reg_write(wcd9xxx,
+						TABLA_A_INTR_MODE, 0x02);
+				handle_nested_irq(wcd9xxx->irq_base + i);
+			} else {
+				handle_nested_irq(wcd9xxx->irq_base + i);
+				wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
+					BIT_BYTE(i), BYTE_BIT_MASK(i));
+				if (wcd9xxx_get_intf_type() ==
+					WCD9XXX_INTERFACE_TYPE_I2C)
+					wcd9xxx_reg_write(wcd9xxx,
+						TABLA_A_INTR_MODE, 0x02);
+			}
+			break;
+		}
+	}
+	wcd9xxx_unlock_sleep(wcd9xxx);
+
+	return IRQ_HANDLED;
+}
+
+int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
+{
+	int ret;
+	unsigned int i, cur_irq;
+
+	mutex_init(&wcd9xxx->irq_lock);
+
+	if (!wcd9xxx->irq) {
+		dev_warn(wcd9xxx->dev,
+			 "No interrupt specified, no interrupts\n");
+		wcd9xxx->irq_base = 0;
+		return 0;
+	}
+
+	if (!wcd9xxx->irq_base) {
+		dev_err(wcd9xxx->dev,
+			"No interrupt base specified, no interrupts\n");
+		return 0;
+	}
+	/* Mask the individual interrupt sources */
+	for (i = 0, cur_irq = wcd9xxx->irq_base; i < TABLA_NUM_IRQS; i++,
+		cur_irq++) {
+
+		irq_set_chip_data(cur_irq, wcd9xxx);
+
+		if (wcd9xxx_irqs[i].level)
+			irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
+					 handle_level_irq);
+		else
+			irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
+					 handle_edge_irq);
+
+		irq_set_nested_thread(cur_irq, 1);
+
+		/* ARM needs us to explicitly flag the IRQ as valid
+		 * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+		set_irq_flags(cur_irq, IRQF_VALID);
+#else
+		set_irq_noprobe(cur_irq);
+#endif
+
+		wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		wcd9xxx->irq_level[BIT_BYTE(i)] |= wcd9xxx_irqs[i].level <<
+			(i % BITS_PER_BYTE);
+	}
+	for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++) {
+		/* Initialize interrupt mask and level registers */
+		wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_LEVEL0 + i,
+			wcd9xxx->irq_level[i]);
+		wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0 + i,
+			wcd9xxx->irq_masks_cur[i]);
+	}
+
+	ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   "wcd9xxx", wcd9xxx);
+	if (ret != 0)
+		dev_err(wcd9xxx->dev, "Failed to request IRQ %d: %d\n",
+			wcd9xxx->irq, ret);
+	else {
+		ret = enable_irq_wake(wcd9xxx->irq);
+		if (ret == 0) {
+			ret = device_init_wakeup(wcd9xxx->dev, 1);
+			if (ret) {
+				dev_err(wcd9xxx->dev, "Failed to init device"
+					"wakeup : %d\n", ret);
+				disable_irq_wake(wcd9xxx->irq);
+			}
+		} else
+			dev_err(wcd9xxx->dev, "Failed to set wake interrupt on"
+				" IRQ %d: %d\n", wcd9xxx->irq, ret);
+		if (ret)
+			free_irq(wcd9xxx->irq, wcd9xxx);
+	}
+
+	if (ret)
+		mutex_destroy(&wcd9xxx->irq_lock);
+
+	return ret;
+}
+
+void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
+{
+	if (wcd9xxx->irq) {
+		disable_irq_wake(wcd9xxx->irq);
+		free_irq(wcd9xxx->irq, wcd9xxx);
+		device_init_wakeup(wcd9xxx->dev, 0);
+	}
+	mutex_destroy(&wcd9xxx->irq_lock);
+}
diff --git a/drivers/mfd/wcd9310-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
similarity index 72%
rename from drivers/mfd/wcd9310-slimslave.c
rename to drivers/mfd/wcd9xxx-slimslave.c
index 12ac27f..acef55e 100644
--- a/drivers/mfd/wcd9310-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -11,45 +11,47 @@
  */
 #include <linux/slab.h>
 #include <linux/mutex.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 
-struct tabla_slim_sch_rx {
+struct wcd9xxx_slim_sch_rx {
 	u32 sph;
 	u32 ch_num;
 	u16 ch_h;
 	u16 grph;
 };
 
-struct tabla_slim_sch_tx {
+struct wcd9xxx_slim_sch_tx {
 	u32 sph;
 	u32 ch_num;
 	u16 ch_h;
 	u16 grph;
 };
 
-struct tabla_slim_sch {
-	struct tabla_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
-	struct tabla_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
+struct wcd9xxx_slim_sch {
+	struct wcd9xxx_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
+	struct wcd9xxx_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
 };
 
-static struct tabla_slim_sch sh_ch;
+static struct wcd9xxx_slim_sch sh_ch;
 
-static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la);
-static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la);
-static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab);
-static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab);
+static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
+					u8 wcd9xxx_pgd_la);
+static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
+					u8 wcd9xxx_pgd_la);
+static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx);
+static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx);
 
-int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la)
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 
-	ret = tabla_alloc_slim_sh_ch_rx(tabla, tabla_pgd_la);
+	ret = wcd9xxx_alloc_slim_sh_ch_rx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc rx slimbus shared channels\n",
 								__func__);
 		goto rx_err;
 	}
-	ret = tabla_alloc_slim_sh_ch_tx(tabla, tabla_pgd_la);
+	ret = wcd9xxx_alloc_slim_sh_ch_tx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc tx slimbus shared channels\n",
 								__func__);
@@ -57,21 +59,21 @@
 	}
 	return 0;
 tx_err:
-	tabla_dealloc_slim_sh_ch_rx(tabla);
+	wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
 rx_err:
 	return ret;
 }
 
 
-int tabla_deinit_slimslave(struct tabla *tabla)
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
-	ret = tabla_dealloc_slim_sh_ch_rx(tabla);
+	ret = wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
 	if (ret < 0) {
 		pr_err("%s: fail to dealloc rx slim ports\n", __func__);
 		goto err;
 	}
-	ret = tabla_dealloc_slim_sh_ch_tx(tabla);
+	ret = wcd9xxx_dealloc_slim_sh_ch_tx(wcd9xxx);
 	if (ret < 0) {
 		pr_err("%s: fail to dealloc tx slim ports\n", __func__);
 		goto err;
@@ -80,13 +82,13 @@
 	return ret;
 }
 
-int tabla_get_channel(struct tabla *tabla,
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
 		unsigned int *rx_ch,
 		unsigned int *tx_ch)
 {
 	int ch_idx = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 
 	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++)
 		rx_ch[ch_idx] = rx[ch_idx].ch_num;
@@ -95,23 +97,23 @@
 	return 0;
 }
 
-static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la)
+static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
+			u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 	u8 ch_idx ;
 	u16 slave_port_id = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 
-	/* DSP requires channel number to be between 128 and 255. For RX port
-	 * use channel numbers from 138 to 144, for TX port
-	 * use channel numbers from 128 to 137
+	/*
+	 * DSP requires channel number to be between 128 and 255.
 	 */
-	pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+	pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
 	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++) {
 		slave_port_id = (ch_idx + 1 +
 				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
 		rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
-		ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
 					&rx[ch_idx].sph, SLIM_SINK);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
@@ -119,7 +121,7 @@
 			goto err;
 		}
 
-		ret = slim_query_ch(tabla->slim, rx[ch_idx].ch_num,
+		ret = slim_query_ch(wcd9xxx->slim, rx[ch_idx].ch_num,
 							&rx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
@@ -131,14 +133,15 @@
 	return ret;
 }
 
-static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la)
+static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
+			u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 	u8 ch_idx ;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	u16 slave_port_id = 0;
 
-	pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+	pr_err("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
 	/* DSP requires channel number to be between 128 and 255. For RX port
 	 * use channel numbers from 138 to 144, for TX port
 	 * use channel numbers from 128 to 137
@@ -146,14 +149,14 @@
 	for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++) {
 		slave_port_id = ch_idx;
 		tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
-		ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
 					&tx[ch_idx].sph, SLIM_SRC);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
 					__func__, slave_port_id, ret);
 			goto err;
 		}
-		ret = slim_query_ch(tabla->slim, tx[ch_idx].ch_num,
+		ret = slim_query_ch(wcd9xxx->slim, tx[ch_idx].ch_num,
 							&tx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
@@ -165,14 +168,14 @@
 	return ret;
 }
 
-static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab)
+static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx)
 {
 	int idx = 0;
 	int ret = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	/* slim_dealloc_ch */
 	for (idx = 0; idx < SLIM_MAX_RX_PORTS; idx++) {
-		ret = slim_dealloc_ch(tab->slim, rx[idx].ch_h);
+		ret = slim_dealloc_ch(wcd9xxx->slim, rx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
 				__func__, ret, rx[idx].ch_h);
@@ -182,14 +185,14 @@
 	return ret;
 }
 
-static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab)
+static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx)
 {
 	int idx = 0;
 	int ret = 0;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	/* slim_dealloc_ch */
 	for (idx = 0; idx < SLIM_MAX_TX_PORTS; idx++) {
-		ret = slim_dealloc_ch(tab->slim, tx[idx].ch_h);
+		ret = slim_dealloc_ch(wcd9xxx->slim, tx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
 				__func__, ret, tx[idx].ch_h);
@@ -200,7 +203,7 @@
 }
 
 /* Enable slimbus slave device for RX path */
-int tabla_cfg_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt, unsigned int rate)
 {
 	u8 i = 0;
@@ -211,15 +214,15 @@
 	u8  payload_rx = 0, wm_payload = 0;
 	int ret, idx = 0;
 	unsigned short  multi_chan_cfg_reg_addr;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	struct slim_ch prop;
 
 	/* Configure slave interface device */
-	pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
+	pr_err("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
 
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
 		ch_h[i] = rx[idx].ch_h;
 		sph[i] = rx[idx].sph;
 		slave_port_id = idx + 1;
@@ -249,7 +252,8 @@
 		multi_chan_cfg_reg_addr =
 				SB_PGD_RX_PORT_MULTI_CHANNEL_0(slave_port_id);
 		/* write to interface device */
-		ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				multi_chan_cfg_reg_addr,
 				payload_rx);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -262,7 +266,7 @@
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
 				SLAVE_PORT_WATER_MARK_SHIFT) +
 				SLAVE_PORT_ENABLE;
-		ret = tabla_interface_reg_write(tab,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
 				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
 				wm_payload);
 		if (ret < 0) {
@@ -279,7 +283,7 @@
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
 
-	ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
 					true, &grph);
 	if (ret < 0) {
 		pr_err("%s: slim_define_ch failed ret[%d]\n",
@@ -287,7 +291,7 @@
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_sink(tab->slim, &sph[i],
+		ret = slim_connect_sink(wcd9xxx->slim, &sph[i],
 							1, ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_sink failed ret[%d]\n",
@@ -296,7 +300,7 @@
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
 					true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
@@ -312,14 +316,14 @@
 
 err_close_slim_sch:
 	/*  release all acquired handles */
-	tabla_close_slim_sch_rx(tab, ch_num, ch_cnt);
+	wcd9xxx_close_slim_sch_rx(wcd9xxx, ch_num, ch_cnt);
 err:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_rx);
+EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_rx);
 
 /* Enable slimbus slave device for RX path */
-int tabla_cfg_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt, unsigned int rate)
 {
 	u8 i = 0;
@@ -331,7 +335,7 @@
 	int ret = 0;
 	unsigned short  multi_chan_cfg_reg_addr;
 
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	struct slim_ch prop;
 
 	pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
@@ -366,7 +370,8 @@
 		multi_chan_cfg_reg_addr =
 				SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
 		/* write to interface device */
-		ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				multi_chan_cfg_reg_addr,
 				payload_tx_0);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -378,7 +383,8 @@
 		multi_chan_cfg_reg_addr =
 				SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
 		/* ports 8,9 */
-		ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				multi_chan_cfg_reg_addr,
 				payload_tx_1);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -391,7 +397,7 @@
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
 				SLAVE_PORT_WATER_MARK_SHIFT) +
 				SLAVE_PORT_ENABLE;
-		ret = tabla_interface_reg_write(tab,
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
 				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
 				wm_payload);
 		if (ret < 0) {
@@ -408,7 +414,7 @@
 	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
-	ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
 					true, &grph);
 	if (ret < 0) {
 		pr_err("%s: slim_define_ch failed ret[%d]\n",
@@ -416,7 +422,7 @@
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_src(tab->slim, sph[i],
+		ret = slim_connect_src(wcd9xxx->slim, sph[i],
 							ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_src failed ret[%d]\n",
@@ -425,7 +431,7 @@
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
 					true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
@@ -439,21 +445,21 @@
 	return 0;
 err:
 	/* release all acquired handles */
-	tabla_close_slim_sch_tx(tab, ch_num, ch_cnt);
+	wcd9xxx_close_slim_sch_tx(wcd9xxx, ch_num, ch_cnt);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_tx);
+EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_tx);
 
-int tabla_close_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt)
 {
 	u16 grph = 0;
 	u32 sph[SLIM_MAX_RX_PORTS] = {0};
 	int i = 0 , idx = 0;
 	int ret = 0;
-	struct tabla_slim_sch_rx *rx = sh_ch.rx;
+	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 
-	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+	pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM -
 				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
@@ -462,13 +468,13 @@
 	}
 
 	/* slim_disconnect_port */
-	ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
 	if (ret < 0) {
 		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
 				__func__, ret);
 	}
 	/* slim_control_ch (REMOVE) */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
@@ -482,31 +488,31 @@
 err:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_close_slim_sch_rx);
+EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
 
-int tabla_close_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int ch_cnt)
 {
 	u16 grph = 0;
 	u32 sph[SLIM_MAX_TX_PORTS] = {0};
 	int ret = 0;
 	int i = 0 , idx = 0;
-	struct tabla_slim_sch_tx *tx = sh_ch.tx;
+	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 
-	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+	pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
 		idx = (ch_num[i] - BASE_CH_NUM);
 		sph[i] = tx[idx].sph;
 		grph = tx[idx].grph;
 	}
 	/* slim_disconnect_port */
-	ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
 	if (ret < 0) {
 		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
 				__func__, ret);
 	}
 	/* slim_control_ch (REMOVE) */
-	ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
@@ -519,4 +525,4 @@
 err:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(tabla_close_slim_sch_tx);
+EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_tx);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 48f3f2d..4634e75 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -94,6 +94,11 @@
 	unsigned int	read_only;
 	unsigned int	part_type;
 	unsigned int	name_idx;
+	unsigned int	reset_done;
+#define MMC_BLK_READ		BIT(0)
+#define MMC_BLK_WRITE		BIT(1)
+#define MMC_BLK_DISCARD		BIT(2)
+#define MMC_BLK_SECDISCARD	BIT(3)
 
 	/*
 	 * Only set in main mmc_blk_data associated
@@ -106,6 +111,16 @@
 
 static DEFINE_MUTEX(open_lock);
 
+enum mmc_blk_status {
+	MMC_BLK_SUCCESS = 0,
+	MMC_BLK_PARTIAL,
+	MMC_BLK_CMD_ERR,
+	MMC_BLK_RETRY,
+	MMC_BLK_ABORT,
+	MMC_BLK_DATA_ERR,
+	MMC_BLK_ECC_ERR,
+};
+
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
@@ -277,7 +292,7 @@
 	struct mmc_card *card;
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct scatterlist sg;
 	int err;
 
@@ -423,32 +438,29 @@
 #endif
 };
 
-struct mmc_blk_request {
-	struct mmc_request	mrq;
-	struct mmc_command	sbc;
-	struct mmc_command	cmd;
-	struct mmc_command	stop;
-	struct mmc_data		data;
-};
-
 static inline int mmc_blk_part_switch(struct mmc_card *card,
 				      struct mmc_blk_data *md)
 {
 	int ret;
 	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+
 	if (main_md->part_curr == md->part_type)
 		return 0;
 
 	if (mmc_card_mmc(card)) {
-		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
-		card->ext_csd.part_config |= md->part_type;
+		u8 part_config = card->ext_csd.part_config;
+
+		part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		part_config |= md->part_type;
 
 		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+				 EXT_CSD_PART_CONFIG, part_config,
 				 card->ext_csd.part_time);
 		if (ret)
 			return ret;
-}
+
+		card->ext_csd.part_config = part_config;
+	}
 
 	main_md->part_curr = md->part_type;
 	return 0;
@@ -460,7 +472,7 @@
 	u32 result;
 	__be32 *blocks;
 
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	unsigned int timeout_us;
@@ -615,7 +627,7 @@
  * Otherwise we don't understand what happened, so abort.
  */
 static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
-	struct mmc_blk_request *brq)
+	struct mmc_blk_request *brq, int *ecc_err)
 {
 	bool prev_cmd_status_valid = true;
 	u32 status, stop_status = 0;
@@ -647,6 +659,12 @@
 		return ERR_ABORT;
 	}
 
+	/* Flag ECC errors */
+	if ((status & R1_CARD_ECC_FAILED) ||
+	    (brq->stop.resp[0] & R1_CARD_ECC_FAILED) ||
+	    (brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
+		*ecc_err = 1;
+
 	/*
 	 * Check the current card state.  If it is in some data transfer
 	 * mode, tell it to stop (and hopefully transition back to TRAN.)
@@ -664,6 +682,8 @@
 		 */
 		if (err)
 			return ERR_ABORT;
+		if (stop_status & R1_CARD_ECC_FAILED)
+			*ecc_err = 1;
 	}
 
 	/* Check for set block count errors */
@@ -676,6 +696,10 @@
 		return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
 				prev_cmd_status_valid, status);
 
+	/* Data errors */
+	if (!brq->stop.error)
+		return ERR_CONTINUE;
+
 	/* Now for stop errors.  These aren't fatal to the transfer. */
 	pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
 	       req->rq_disk->disk_name, brq->stop.error,
@@ -692,12 +716,45 @@
 	return ERR_CONTINUE;
 }
 
+static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
+			 int type)
+{
+	int err;
+
+	if (md->reset_done & type)
+		return -EEXIST;
+
+	md->reset_done |= type;
+	err = mmc_hw_reset(host);
+	/* Ensure we switch back to the correct partition */
+	if (err != -EOPNOTSUPP) {
+		struct mmc_blk_data *main_md = mmc_get_drvdata(host->card);
+		int part_err;
+
+		main_md->part_curr = main_md->part_type;
+		part_err = mmc_blk_part_switch(host->card, md);
+		if (part_err) {
+			/*
+			 * We have failed to get back into the correct
+			 * partition, so we need to abort the whole request.
+			 */
+			return -ENODEV;
+		}
+	}
+	return err;
+}
+
+static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
+{
+	md->reset_done &= ~type;
+}
+
 static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	unsigned int from, nr, arg;
-	int err = 0;
+	int err = 0, type = MMC_BLK_DISCARD;
 
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
@@ -707,11 +764,13 @@
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
-	if (mmc_can_trim(card))
+	if (mmc_can_discard(card))
+		arg = MMC_DISCARD_ARG;
+	else if (mmc_can_trim(card))
 		arg = MMC_TRIM_ARG;
 	else
 		arg = MMC_ERASE_ARG;
-
+retry:
 	if (card->quirks & MMC_QUIRK_INAND_CMD38) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 INAND_CMD38_ARG_EXT_CSD,
@@ -724,6 +783,10 @@
 	}
 	err = mmc_erase(card, from, nr, arg);
 out:
+	if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+		goto retry;
+	if (!err)
+		mmc_blk_reset_success(md, type);
 	spin_lock_irq(&md->lock);
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
@@ -737,13 +800,20 @@
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	unsigned int from, nr, arg;
-	int err = 0;
+	int err = 0, type = MMC_BLK_SECDISCARD;
 
-	if (!mmc_can_secure_erase_trim(card)) {
+	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
 		err = -EOPNOTSUPP;
 		goto out;
 	}
 
+	/* The sanitize operation is supported at v4.5 only */
+	if (mmc_can_sanitize(card)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_SANITIZE_START, 1, 0);
+		goto out;
+	}
+
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
@@ -751,7 +821,7 @@
 		arg = MMC_SECURE_TRIM1_ARG;
 	else
 		arg = MMC_SECURE_ERASE_ARG;
-
+retry:
 	if (card->quirks & MMC_QUIRK_INAND_CMD38) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 INAND_CMD38_ARG_EXT_CSD,
@@ -775,6 +845,10 @@
 		err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
 	}
 out:
+	if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+		goto retry;
+	if (!err)
+		mmc_blk_reset_success(md, type);
 	spin_lock_irq(&md->lock);
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
@@ -785,16 +859,18 @@
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	int ret = 0;
 
-	/*
-	 * No-op, only service this because we need REQ_FUA for reliable
-	 * writes.
-	 */
+	ret = mmc_flush_cache(card);
+	if (ret)
+		ret = -EIO;
+
 	spin_lock_irq(&md->lock);
-	__blk_end_request_all(req, 0);
+	__blk_end_request_all(req, ret);
 	spin_unlock_irq(&md->lock);
 
-	return 1;
+	return ret ? 0 : 1;
 }
 
 /*
@@ -828,12 +904,106 @@
 	 R1_CC_ERROR |		/* Card controller error */		\
 	 R1_ERROR)		/* General/unknown error */
 
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+static int mmc_blk_err_check(struct mmc_card *card,
+			     struct mmc_async_req *areq)
 {
+	struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
+						    mmc_active);
+	struct mmc_blk_request *brq = &mq_mrq->brq;
+	struct request *req = mq_mrq->req;
+	int ecc_err = 0;
+
+	/*
+	 * sbc.error indicates a problem with the set block count
+	 * command.  No data will have been transferred.
+	 *
+	 * cmd.error indicates a problem with the r/w command.  No
+	 * data will have been transferred.
+	 *
+	 * stop.error indicates a problem with the stop command.  Data
+	 * may have been transferred, or may still be transferring.
+	 */
+	if (brq->sbc.error || brq->cmd.error || brq->stop.error ||
+	    brq->data.error) {
+		switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) {
+		case ERR_RETRY:
+			return MMC_BLK_RETRY;
+		case ERR_ABORT:
+		case ERR_NOMEDIUM:
+			return MMC_BLK_ABORT;
+		case ERR_CONTINUE:
+			break;
+		}
+	}
+
+	/*
+	 * Check for errors relating to the execution of the
+	 * initial command - such as address errors.  No data
+	 * has been transferred.
+	 */
+	if (brq->cmd.resp[0] & CMD_ERRORS) {
+		pr_err("%s: r/w command failed, status = %#x\n",
+		       req->rq_disk->disk_name, brq->cmd.resp[0]);
+		return MMC_BLK_ABORT;
+	}
+
+	/*
+	 * Everything else is either success, or a data error of some
+	 * kind.  If it was a write, we may have transitioned to
+	 * program mode, which we have to wait for it to complete.
+	 */
+	if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+		u32 status;
+		do {
+			int err = get_card_status(card, &status, 5);
+			if (err) {
+				printk(KERN_ERR "%s: error %d requesting status\n",
+				       req->rq_disk->disk_name, err);
+				return MMC_BLK_CMD_ERR;
+			}
+			/*
+			 * Some cards mishandle the status bits,
+			 * so make sure to check both the busy
+			 * indication and the card state.
+			 */
+		} while (!(status & R1_READY_FOR_DATA) ||
+			 (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+	}
+
+	if (brq->data.error) {
+		pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
+		       req->rq_disk->disk_name, brq->data.error,
+		       (unsigned)blk_rq_pos(req),
+		       (unsigned)blk_rq_sectors(req),
+		       brq->cmd.resp[0], brq->stop.resp[0]);
+
+		if (rq_data_dir(req) == READ) {
+			if (ecc_err)
+				return MMC_BLK_ECC_ERR;
+			return MMC_BLK_DATA_ERR;
+		} else {
+			return MMC_BLK_CMD_ERR;
+		}
+	}
+
+	if (!brq->data.bytes_xfered)
+		return MMC_BLK_RETRY;
+
+	if (blk_rq_bytes(req) != brq->data.bytes_xfered)
+		return MMC_BLK_PARTIAL;
+
+	return MMC_BLK_SUCCESS;
+}
+
+static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+			       struct mmc_card *card,
+			       int disable_multi,
+			       struct mmc_queue *mq)
+{
+	u32 readcmd, writecmd;
+	struct mmc_blk_request *brq = &mqrq->brq;
+	struct request *req = mqrq->req;
 	struct mmc_blk_data *md = mq->data;
-	struct mmc_card *card = md->queue.card;
-	struct mmc_blk_request brq;
-	int ret = 1, disable_multi = 0, retry = 0;
 
 	/*
 	 * Reliable writes are used to implement Forced Unit Access and
@@ -844,225 +1014,135 @@
 		(rq_data_dir(req) == WRITE) &&
 		(md->flags & MMC_BLK_REL_WR);
 
-	do {
-		u32 readcmd, writecmd;
+	memset(brq, 0, sizeof(struct mmc_blk_request));
+	brq->mrq.cmd = &brq->cmd;
+	brq->mrq.data = &brq->data;
 
-		memset(&brq, 0, sizeof(struct mmc_blk_request));
-		brq.mrq.cmd = &brq.cmd;
-		brq.mrq.data = &brq.data;
+	brq->cmd.arg = blk_rq_pos(req);
+	if (!mmc_card_blockaddr(card))
+		brq->cmd.arg <<= 9;
+	brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+	brq->data.blksz = 512;
+	brq->stop.opcode = MMC_STOP_TRANSMISSION;
+	brq->stop.arg = 0;
+	brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+	brq->data.blocks = blk_rq_sectors(req);
 
-		brq.cmd.arg = blk_rq_pos(req);
-		if (!mmc_card_blockaddr(card))
-			brq.cmd.arg <<= 9;
-		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-		brq.data.blksz = 512;
-		brq.stop.opcode = MMC_STOP_TRANSMISSION;
-		brq.stop.arg = 0;
-		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-		brq.data.blocks = blk_rq_sectors(req);
+	/*
+	 * The block layer doesn't support all sector count
+	 * restrictions, so we need to be prepared for too big
+	 * requests.
+	 */
+	if (brq->data.blocks > card->host->max_blk_count)
+		brq->data.blocks = card->host->max_blk_count;
 
+	if (brq->data.blocks > 1) {
 		/*
-		 * The block layer doesn't support all sector count
-		 * restrictions, so we need to be prepared for too big
-		 * requests.
+		 * After a read error, we redo the request one sector
+		 * at a time in order to accurately determine which
+		 * sectors can be read successfully.
 		 */
-		if (brq.data.blocks > card->host->max_blk_count)
-			brq.data.blocks = card->host->max_blk_count;
+		if (disable_multi)
+			brq->data.blocks = 1;
 
-		/*
-		 * After a read error, we redo the request one sector at a time
-		 * in order to accurately determine which sectors can be read
-		 * successfully.
+		/* Some controllers can't do multiblock reads due to hw bugs */
+		if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
+		    rq_data_dir(req) == READ)
+			brq->data.blocks = 1;
+	}
+
+	if (brq->data.blocks > 1 || do_rel_wr) {
+		/* SPI multiblock writes terminate using a special
+		 * token, not a STOP_TRANSMISSION request.
 		 */
-		if (disable_multi && brq.data.blocks > 1)
-			brq.data.blocks = 1;
+		if (!mmc_host_is_spi(card->host) ||
+		    rq_data_dir(req) == READ)
+			brq->mrq.stop = &brq->stop;
+		readcmd = MMC_READ_MULTIPLE_BLOCK;
+		writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+	} else {
+		brq->mrq.stop = NULL;
+		readcmd = MMC_READ_SINGLE_BLOCK;
+		writecmd = MMC_WRITE_BLOCK;
+	}
+	if (rq_data_dir(req) == READ) {
+		brq->cmd.opcode = readcmd;
+		brq->data.flags |= MMC_DATA_READ;
+	} else {
+		brq->cmd.opcode = writecmd;
+		brq->data.flags |= MMC_DATA_WRITE;
+	}
 
-		if (brq.data.blocks > 1 || do_rel_wr) {
-			/* SPI multiblock writes terminate using a special
-			 * token, not a STOP_TRANSMISSION request.
-			 */
-			if (!mmc_host_is_spi(card->host) ||
-			    rq_data_dir(req) == READ)
-				brq.mrq.stop = &brq.stop;
-			readcmd = MMC_READ_MULTIPLE_BLOCK;
-			writecmd = MMC_WRITE_MULTIPLE_BLOCK;
-		} else {
-			brq.mrq.stop = NULL;
-			readcmd = MMC_READ_SINGLE_BLOCK;
-			writecmd = MMC_WRITE_BLOCK;
-		}
-		if (rq_data_dir(req) == READ) {
-			brq.cmd.opcode = readcmd;
-			brq.data.flags |= MMC_DATA_READ;
-		} else {
-			brq.cmd.opcode = writecmd;
-			brq.data.flags |= MMC_DATA_WRITE;
-		}
+	if (do_rel_wr)
+		mmc_apply_rel_rw(brq, card, req);
 
-		if (do_rel_wr)
-			mmc_apply_rel_rw(&brq, card, req);
+	/*
+	 * Pre-defined multi-block transfers are preferable to
+	 * open ended-ones (and necessary for reliable writes).
+	 * However, it is not sufficient to just send CMD23,
+	 * and avoid the final CMD12, as on an error condition
+	 * CMD12 (stop) needs to be sent anyway. This, coupled
+	 * with Auto-CMD23 enhancements provided by some
+	 * hosts, means that the complexity of dealing
+	 * with this is best left to the host. If CMD23 is
+	 * supported by card and host, we'll fill sbc in and let
+	 * the host deal with handling it correctly. This means
+	 * that for hosts that don't expose MMC_CAP_CMD23, no
+	 * change of behavior will be observed.
+	 *
+	 * N.B: Some MMC cards experience perf degradation.
+	 * We'll avoid using CMD23-bounded multiblock writes for
+	 * these, while retaining features like reliable writes.
+	 */
 
-		/*
-		 * Pre-defined multi-block transfers are preferable to
-		 * open ended-ones (and necessary for reliable writes).
-		 * However, it is not sufficient to just send CMD23,
-		 * and avoid the final CMD12, as on an error condition
-		 * CMD12 (stop) needs to be sent anyway. This, coupled
-		 * with Auto-CMD23 enhancements provided by some
-		 * hosts, means that the complexity of dealing
-		 * with this is best left to the host. If CMD23 is
-		 * supported by card and host, we'll fill sbc in and let
-		 * the host deal with handling it correctly. This means
-		 * that for hosts that don't expose MMC_CAP_CMD23, no
-		 * change of behavior will be observed.
-		 *
-		 * N.B: Some MMC cards experience perf degradation.
-		 * We'll avoid using CMD23-bounded multiblock writes for
-		 * these, while retaining features like reliable writes.
-		 */
+	if ((md->flags & MMC_BLK_CMD23) &&
+	    mmc_op_multi(brq->cmd.opcode) &&
+	    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+		brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+		brq->sbc.arg = brq->data.blocks |
+			(do_rel_wr ? (1 << 31) : 0);
+		brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+		brq->mrq.sbc = &brq->sbc;
+	}
 
-		if ((md->flags & MMC_BLK_CMD23) &&
-		    mmc_op_multi(brq.cmd.opcode) &&
-		    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
-			brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
-			brq.sbc.arg = brq.data.blocks |
-				(do_rel_wr ? (1 << 31) : 0);
-			brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
-			brq.mrq.sbc = &brq.sbc;
-		}
+	mmc_set_data_timeout(&brq->data, card);
 
-		mmc_set_data_timeout(&brq.data, card);
+	brq->data.sg = mqrq->sg;
+	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
 
-		brq.data.sg = mq->sg;
-		brq.data.sg_len = mmc_queue_map_sg(mq);
+	/*
+	 * Adjust the sg list so it is the same size as the
+	 * request.
+	 */
+	if (brq->data.blocks != blk_rq_sectors(req)) {
+		int i, data_size = brq->data.blocks << 9;
+		struct scatterlist *sg;
 
-		/*
-		 * Adjust the sg list so it is the same size as the
-		 * request.
-		 */
-		if (brq.data.blocks != blk_rq_sectors(req)) {
-			int i, data_size = brq.data.blocks << 9;
-			struct scatterlist *sg;
-
-			for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
-				data_size -= sg->length;
-				if (data_size <= 0) {
-					sg->length += data_size;
-					i++;
-					break;
-				}
-			}
-			brq.data.sg_len = i;
-		}
-
-		mmc_queue_bounce_pre(mq);
-
-		mmc_wait_for_req(card->host, &brq.mrq);
-
-		mmc_queue_bounce_post(mq);
-
-		/*
-		 * sbc.error indicates a problem with the set block count
-		 * command.  No data will have been transferred.
-		 *
-		 * cmd.error indicates a problem with the r/w command.  No
-		 * data will have been transferred.
-		 *
-		 * stop.error indicates a problem with the stop command.  Data
-		 * may have been transferred, or may still be transferring.
-		 */
-		if (brq.sbc.error || brq.cmd.error || brq.stop.error) {
-			switch (mmc_blk_cmd_recovery(card, req, &brq)) {
-			case ERR_RETRY:
-				if (retry++ < 5)
-					continue;
-			case ERR_ABORT:
-			case ERR_NOMEDIUM:
-				goto cmd_abort;
-			case ERR_CONTINUE:
+		for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
+			data_size -= sg->length;
+			if (data_size <= 0) {
+				sg->length += data_size;
+				i++;
 				break;
 			}
 		}
+		brq->data.sg_len = i;
+	}
 
-		/*
-		 * Check for errors relating to the execution of the
-		 * initial command - such as address errors.  No data
-		 * has been transferred.
-		 */
-		if (brq.cmd.resp[0] & CMD_ERRORS) {
-			pr_err("%s: r/w command failed, status = %#x\n",
-				req->rq_disk->disk_name, brq.cmd.resp[0]);
-			goto cmd_abort;
-		}
+	mqrq->mmc_active.mrq = &brq->mrq;
+	mqrq->mmc_active.err_check = mmc_blk_err_check;
 
-		/*
-		 * Everything else is either success, or a data error of some
-		 * kind.  If it was a write, we may have transitioned to
-		 * program mode, which we have to wait for it to complete.
-		 */
-		if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
-			u32 status;
-			do {
-				int err = get_card_status(card, &status, 5);
-				if (err) {
-					printk(KERN_ERR "%s: error %d requesting status\n",
-					       req->rq_disk->disk_name, err);
-					goto cmd_err;
-				}
-				/*
-				 * Some cards mishandle the status bits,
-				 * so make sure to check both the busy
-				 * indication and the card state.
-				 */
-			} while (!(status & R1_READY_FOR_DATA) ||
-				 (R1_CURRENT_STATE(status) == R1_STATE_PRG));
-		}
+	mmc_queue_bounce_pre(mqrq);
+}
 
-		if (brq.data.error) {
-			pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
-				req->rq_disk->disk_name, brq.data.error,
-				(unsigned)blk_rq_pos(req),
-				(unsigned)blk_rq_sectors(req),
-				brq.cmd.resp[0], brq.stop.resp[0]);
-
-			if (rq_data_dir(req) == READ) {
-				if (brq.data.blocks > 1) {
-					/* Redo read one sector at a time */
-					pr_warning("%s: retrying using single block read\n",
-						req->rq_disk->disk_name);
-					disable_multi = 1;
-					continue;
-				}
-
-				/*
-				 * After an error, we redo I/O one sector at a
-				 * time, so we only reach here after trying to
-				 * read a single sector.
-				 */
-				spin_lock_irq(&md->lock);
-				ret = __blk_end_request(req, -EIO, brq.data.blksz);
-				spin_unlock_irq(&md->lock);
-				continue;
-			} else {
-				goto cmd_err;
-			}
-		}
-
-		/*
-		 * A block was successfully transferred.
-		 */
-		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
-		spin_unlock_irq(&md->lock);
-	} while (ret);
-
-	return 1;
-
- cmd_err:
- 	/*
- 	 * If this is an SD card and we're writing, we can first
- 	 * mark the known good sectors as ok.
- 	 *
+static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
+			   struct mmc_blk_request *brq, struct request *req,
+			   int ret)
+{
+	/*
+	 * If this is an SD card and we're writing, we can first
+	 * mark the known good sectors as ok.
+	 *
 	 * If the card is not SD, we can still ok written sectors
 	 * as reported by the controller (which might be less than
 	 * the real number of written sectors, but never more).
@@ -1078,9 +1158,122 @@
 		}
 	} else {
 		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
+		ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
 		spin_unlock_irq(&md->lock);
 	}
+	return ret;
+}
+
+static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+{
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
+	int ret = 1, disable_multi = 0, retry = 0, type;
+	enum mmc_blk_status status;
+	struct mmc_queue_req *mq_rq;
+	struct request *req;
+	struct mmc_async_req *areq;
+
+	if (!rqc && !mq->mqrq_prev->req)
+		return 0;
+
+	do {
+		if (rqc) {
+			mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+			areq = &mq->mqrq_cur->mmc_active;
+		} else
+			areq = NULL;
+		areq = mmc_start_req(card->host, areq, (int *) &status);
+		if (!areq)
+			return 0;
+
+		mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
+		brq = &mq_rq->brq;
+		req = mq_rq->req;
+		type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+		mmc_queue_bounce_post(mq_rq);
+
+		switch (status) {
+		case MMC_BLK_SUCCESS:
+		case MMC_BLK_PARTIAL:
+			/*
+			 * A block was successfully transferred.
+			 */
+			mmc_blk_reset_success(md, type);
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(req, 0,
+						brq->data.bytes_xfered);
+			spin_unlock_irq(&md->lock);
+			/*
+			 * If the blk_end_request function returns non-zero even
+			 * though all data has been transferred and no errors
+			 * were returned by the host controller, it's a bug.
+			 */
+			if (status == MMC_BLK_SUCCESS && ret) {
+				printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n",
+				       __func__, blk_rq_bytes(req),
+				       brq->data.bytes_xfered);
+				rqc = NULL;
+				goto cmd_abort;
+			}
+			break;
+		case MMC_BLK_CMD_ERR:
+			ret = mmc_blk_cmd_err(md, card, brq, req, ret);
+			if (!mmc_blk_reset(md, card->host, type))
+				break;
+			goto cmd_abort;
+		case MMC_BLK_RETRY:
+			if (retry++ < 5)
+				break;
+			/* Fall through */
+		case MMC_BLK_ABORT:
+			if (!mmc_blk_reset(md, card->host, type))
+				break;
+			goto cmd_abort;
+		case MMC_BLK_DATA_ERR: {
+			int err;
+
+			err = mmc_blk_reset(md, card->host, type);
+			if (!err)
+				break;
+			if (err == -ENODEV)
+				goto cmd_abort;
+			/* Fall through */
+		}
+		case MMC_BLK_ECC_ERR:
+			if (brq->data.blocks > 1) {
+				/* Redo read one sector at a time */
+				pr_warning("%s: retrying using single block read\n",
+					   req->rq_disk->disk_name);
+				disable_multi = 1;
+				break;
+			}
+			/*
+			 * After an error, we redo I/O one sector at a
+			 * time, so we only reach here after trying to
+			 * read a single sector.
+			 */
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(req, -EIO,
+						brq->data.blksz);
+			spin_unlock_irq(&md->lock);
+			if (!ret)
+				goto start_new_req;
+			break;
+		}
+
+		if (ret) {
+			/*
+			 * In case of a incomplete request
+			 * prepare it again and resend.
+			 */
+			mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
+			mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
+		}
+	} while (ret);
+
+	return 1;
 
  cmd_abort:
 	spin_lock_irq(&md->lock);
@@ -1090,6 +1283,12 @@
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
 	spin_unlock_irq(&md->lock);
 
+ start_new_req:
+	if (rqc) {
+		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+		mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
+	}
+
 	return 0;
 }
 
@@ -1109,26 +1308,42 @@
 	}
 #endif
 
-	mmc_claim_host(card->host);
+	if (req && !mq->mqrq_prev->req)
+		/* claim host only for the first request */
+		mmc_claim_host(card->host);
+
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
+		if (req) {
+			spin_lock_irq(&md->lock);
+			__blk_end_request_all(req, -EIO);
+			spin_unlock_irq(&md->lock);
+		}
 		ret = 0;
 		goto out;
 	}
 
-	if (req->cmd_flags & REQ_DISCARD) {
+	if (req && req->cmd_flags & REQ_DISCARD) {
+		/* complete ongoing async transfer before issuing discard */
+		if (card->host->areq)
+			mmc_blk_issue_rw_rq(mq, NULL);
 		if (req->cmd_flags & REQ_SECURE)
 			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
 			ret = mmc_blk_issue_discard_rq(mq, req);
-	} else if (req->cmd_flags & REQ_FLUSH) {
+	} else if (req && req->cmd_flags & REQ_FLUSH) {
+		/* complete ongoing async transfer before issuing flush */
+		if (card->host->areq)
+			mmc_blk_issue_rw_rq(mq, NULL);
 		ret = mmc_blk_issue_flush(mq, req);
 	} else {
 		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
 
 out:
-	mmc_release_host(card->host);
+	if (!req)
+		/* release host only when there are no more requests */
+		mmc_release_host(card->host);
 	return ret;
 }
 
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 233cdfa..a2b005e 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -22,6 +22,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/seq_file.h>
+#include <linux/module.h>
 
 #define RESULT_OK		0
 #define RESULT_FAIL		1
@@ -148,6 +149,27 @@
 	struct mmc_test_general_result	*gr;
 };
 
+enum mmc_test_prep_media {
+	MMC_TEST_PREP_NONE = 0,
+	MMC_TEST_PREP_WRITE_FULL = 1 << 0,
+	MMC_TEST_PREP_ERASE = 1 << 1,
+};
+
+struct mmc_test_multiple_rw {
+	unsigned int *sg_len;
+	unsigned int *bs;
+	unsigned int len;
+	unsigned int size;
+	bool do_write;
+	bool do_nonblock_req;
+	enum mmc_test_prep_media prepare;
+};
+
+struct mmc_test_async_req {
+	struct mmc_async_req areq;
+	struct mmc_test_card *test;
+};
+
 /*******************************************************************/
 /*  General helper functions                                       */
 /*******************************************************************/
@@ -203,7 +225,7 @@
 static int mmc_test_busy(struct mmc_command *cmd)
 {
 	return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
-		(R1_CURRENT_STATE(cmd->resp[0]) == 7);
+		(R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
 }
 
 /*
@@ -367,21 +389,26 @@
  * Map memory into a scatterlist.  Optionally allow the same memory to be
  * mapped more than once.
  */
-static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
+static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
 			   struct scatterlist *sglist, int repeat,
 			   unsigned int max_segs, unsigned int max_seg_sz,
-			   unsigned int *sg_len)
+			   unsigned int *sg_len, int min_sg_len)
 {
 	struct scatterlist *sg = NULL;
 	unsigned int i;
+	unsigned long sz = size;
 
 	sg_init_table(sglist, max_segs);
+	if (min_sg_len > max_segs)
+		min_sg_len = max_segs;
 
 	*sg_len = 0;
 	do {
 		for (i = 0; i < mem->cnt; i++) {
 			unsigned long len = PAGE_SIZE << mem->arr[i].order;
 
+			if (min_sg_len && (size / min_sg_len < len))
+				len = ALIGN(size / min_sg_len, 512);
 			if (len > sz)
 				len = sz;
 			if (len > max_seg_sz)
@@ -554,11 +581,12 @@
 
 	printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
 			 "%lu.%09lu seconds (%u kB/s, %u KiB/s, "
-			 "%u.%02u IOPS)\n",
+			 "%u.%02u IOPS, sg_len %d)\n",
 			 mmc_hostname(test->card->host), count, sectors, count,
 			 sectors >> 1, (sectors & 1 ? ".5" : ""),
 			 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
-			 rate / 1000, rate / 1024, iops / 100, iops % 100);
+			 rate / 1000, rate / 1024, iops / 100, iops % 100,
+			 test->area.sg_len);
 
 	mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
 }
@@ -661,7 +689,7 @@
  * Checks that a normal transfer didn't have any errors
  */
 static int mmc_test_check_result(struct mmc_test_card *test,
-	struct mmc_request *mrq)
+				 struct mmc_request *mrq)
 {
 	int ret;
 
@@ -685,6 +713,17 @@
 	return ret;
 }
 
+static int mmc_test_check_result_async(struct mmc_card *card,
+				       struct mmc_async_req *areq)
+{
+	struct mmc_test_async_req *test_async =
+		container_of(areq, struct mmc_test_async_req, areq);
+
+	mmc_test_wait_busy(test_async->test);
+
+	return mmc_test_check_result(test_async->test, areq->mrq);
+}
+
 /*
  * Checks that a "short transfer" behaved as expected
  */
@@ -720,6 +759,85 @@
 }
 
 /*
+ * Tests nonblock transfer with certain parameters
+ */
+static void mmc_test_nonblock_reset(struct mmc_request *mrq,
+				    struct mmc_command *cmd,
+				    struct mmc_command *stop,
+				    struct mmc_data *data)
+{
+	memset(mrq, 0, sizeof(struct mmc_request));
+	memset(cmd, 0, sizeof(struct mmc_command));
+	memset(data, 0, sizeof(struct mmc_data));
+	memset(stop, 0, sizeof(struct mmc_command));
+
+	mrq->cmd = cmd;
+	mrq->data = data;
+	mrq->stop = stop;
+}
+static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
+				      struct scatterlist *sg, unsigned sg_len,
+				      unsigned dev_addr, unsigned blocks,
+				      unsigned blksz, int write, int count)
+{
+	struct mmc_request mrq1;
+	struct mmc_command cmd1;
+	struct mmc_command stop1;
+	struct mmc_data data1;
+
+	struct mmc_request mrq2;
+	struct mmc_command cmd2;
+	struct mmc_command stop2;
+	struct mmc_data data2;
+
+	struct mmc_test_async_req test_areq[2];
+	struct mmc_async_req *done_areq;
+	struct mmc_async_req *cur_areq = &test_areq[0].areq;
+	struct mmc_async_req *other_areq = &test_areq[1].areq;
+	int i;
+	int ret;
+
+	test_areq[0].test = test;
+	test_areq[1].test = test;
+
+	mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+	mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+
+	cur_areq->mrq = &mrq1;
+	cur_areq->err_check = mmc_test_check_result_async;
+	other_areq->mrq = &mrq2;
+	other_areq->err_check = mmc_test_check_result_async;
+
+	for (i = 0; i < count; i++) {
+		mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
+				     blocks, blksz, write);
+		done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
+
+		if (ret || (!done_areq && i > 0))
+			goto err;
+
+		if (done_areq) {
+			if (done_areq->mrq == &mrq2)
+				mmc_test_nonblock_reset(&mrq2, &cmd2,
+							&stop2, &data2);
+			else
+				mmc_test_nonblock_reset(&mrq1, &cmd1,
+							&stop1, &data1);
+		}
+		done_areq = cur_areq;
+		cur_areq = other_areq;
+		other_areq = done_areq;
+		dev_addr += blocks;
+	}
+
+	done_areq = mmc_start_req(test->card->host, NULL, &ret);
+
+	return ret;
+err:
+	return ret;
+}
+
+/*
  * Tests a basic transfer with certain parameters
  */
 static int mmc_test_simple_transfer(struct mmc_test_card *test,
@@ -1302,7 +1420,7 @@
  * Map sz bytes so that it can be transferred.
  */
 static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
-			     int max_scatter)
+			     int max_scatter, int min_sg_len)
 {
 	struct mmc_test_area *t = &test->area;
 	int err;
@@ -1315,7 +1433,7 @@
 				       &t->sg_len);
 	} else {
 		err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
-				      t->max_seg_sz, &t->sg_len);
+				      t->max_seg_sz, &t->sg_len, min_sg_len);
 	}
 	if (err)
 		printk(KERN_INFO "%s: Failed to map sg list\n",
@@ -1336,14 +1454,17 @@
 }
 
 /*
- * Map and transfer bytes.
+ * Map and transfer bytes for multiple transfers.
  */
-static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
-			    unsigned int dev_addr, int write, int max_scatter,
-			    int timed)
+static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
+				unsigned int dev_addr, int write,
+				int max_scatter, int timed, int count,
+				bool nonblock, int min_sg_len)
 {
 	struct timespec ts1, ts2;
-	int ret;
+	int ret = 0;
+	int i;
+	struct mmc_test_area *t = &test->area;
 
 	/*
 	 * In the case of a maximally scattered transfer, the maximum transfer
@@ -1361,14 +1482,21 @@
 			sz = max_tfr;
 	}
 
-	ret = mmc_test_area_map(test, sz, max_scatter);
+	ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len);
 	if (ret)
 		return ret;
 
 	if (timed)
 		getnstimeofday(&ts1);
+	if (nonblock)
+		ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
+				 dev_addr, t->blocks, 512, write, count);
+	else
+		for (i = 0; i < count && ret == 0; i++) {
+			ret = mmc_test_area_transfer(test, dev_addr, write);
+			dev_addr += sz >> 9;
+		}
 
-	ret = mmc_test_area_transfer(test, dev_addr, write);
 	if (ret)
 		return ret;
 
@@ -1376,11 +1504,19 @@
 		getnstimeofday(&ts2);
 
 	if (timed)
-		mmc_test_print_rate(test, sz, &ts1, &ts2);
+		mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
 
 	return 0;
 }
 
+static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
+			    unsigned int dev_addr, int write, int max_scatter,
+			    int timed)
+{
+	return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
+				    timed, 1, false, 0);
+}
+
 /*
  * Write the test area entirely.
  */
@@ -1954,6 +2090,270 @@
 	return mmc_test_large_seq_perf(test, 1);
 }
 
+static int mmc_test_rw_multiple(struct mmc_test_card *test,
+				struct mmc_test_multiple_rw *tdata,
+				unsigned int reqsize, unsigned int size,
+				int min_sg_len)
+{
+	unsigned int dev_addr;
+	struct mmc_test_area *t = &test->area;
+	int ret = 0;
+
+	/* Set up test area */
+	if (size > mmc_test_capacity(test->card) / 2 * 512)
+		size = mmc_test_capacity(test->card) / 2 * 512;
+	if (reqsize > t->max_tfr)
+		reqsize = t->max_tfr;
+	dev_addr = mmc_test_capacity(test->card) / 4;
+	if ((dev_addr & 0xffff0000))
+		dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
+	else
+		dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
+	if (!dev_addr)
+		goto err;
+
+	if (reqsize > size)
+		return 0;
+
+	/* prepare test area */
+	if (mmc_can_erase(test->card) &&
+	    tdata->prepare & MMC_TEST_PREP_ERASE) {
+		ret = mmc_erase(test->card, dev_addr,
+				size / 512, MMC_SECURE_ERASE_ARG);
+		if (ret)
+			ret = mmc_erase(test->card, dev_addr,
+					size / 512, MMC_ERASE_ARG);
+		if (ret)
+			goto err;
+	}
+
+	/* Run test */
+	ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
+				   tdata->do_write, 0, 1, size / reqsize,
+				   tdata->do_nonblock_req, min_sg_len);
+	if (ret)
+		goto err;
+
+	return ret;
+ err:
+	printk(KERN_INFO "[%s] error\n", __func__);
+	return ret;
+}
+
+static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
+				     struct mmc_test_multiple_rw *rw)
+{
+	int ret = 0;
+	int i;
+	void *pre_req = test->card->host->ops->pre_req;
+	void *post_req = test->card->host->ops->post_req;
+
+	if (rw->do_nonblock_req &&
+	    ((!pre_req && post_req) || (pre_req && !post_req))) {
+		printk(KERN_INFO "error: only one of pre/post is defined\n");
+		return -EINVAL;
+	}
+
+	for (i = 0 ; i < rw->len && ret == 0; i++) {
+		ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
+				       struct mmc_test_multiple_rw *rw)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0 ; i < rw->len && ret == 0; i++) {
+		ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
+					   rw->sg_len[i]);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+/*
+ * Multiple blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = true,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = true,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = false,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = false,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = true,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = true,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = false,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = false,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * eMMC hardware reset.
+ */
+static int mmc_test_hw_reset(struct mmc_test_card *test)
+{
+	struct mmc_card *card = test->card;
+	struct mmc_host *host = card->host;
+	int err;
+
+	err = mmc_hw_reset_check(host);
+	if (!err)
+		return RESULT_OK;
+
+	if (err == -ENOSYS)
+		return RESULT_FAIL;
+
+	if (err != -EOPNOTSUPP)
+		return err;
+
+	if (!mmc_can_reset(card))
+		return RESULT_UNSUP_CARD;
+
+	return RESULT_UNSUP_HOST;
+}
+
 static const struct mmc_test_case mmc_test_cases[] = {
 	{
 		.name = "Basic write (no data verification)",
@@ -2221,6 +2621,66 @@
 		.cleanup = mmc_test_area_cleanup,
 	},
 
+	{
+		.name = "Write performance with blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_write_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance with non-blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_write_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance with blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_read_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance with non-blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_read_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_wr_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance non-blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_wr_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_r_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance non-blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_r_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "eMMC hardware reset",
+		.run = mmc_test_hw_reset,
+	},
 };
 
 static DEFINE_MUTEX(mmc_test_lock);
@@ -2445,6 +2905,32 @@
 	.release	= single_release,
 };
 
+static int mtf_testlist_show(struct seq_file *sf, void *data)
+{
+	int i;
+
+	mutex_lock(&mmc_test_lock);
+
+	for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
+		seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
+
+	mutex_unlock(&mmc_test_lock);
+
+	return 0;
+}
+
+static int mtf_testlist_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mtf_testlist_show, inode->i_private);
+}
+
+static const struct file_operations mmc_test_fops_testlist = {
+	.open		= mtf_testlist_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static void mmc_test_free_file_test(struct mmc_card *card)
 {
 	struct mmc_test_dbgfs_file *df, *dfs;
@@ -2476,7 +2962,18 @@
 
 	if (IS_ERR_OR_NULL(file)) {
 		dev_err(&card->dev,
-			"Can't create file. Perhaps debugfs is disabled.\n");
+			"Can't create test. Perhaps debugfs is disabled.\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (card->debugfs_root)
+		file = debugfs_create_file("testlist", S_IRUGO,
+			card->debugfs_root, card, &mmc_test_fops_testlist);
+
+	if (IS_ERR_OR_NULL(file)) {
+		dev_err(&card->dev,
+			"Can't create testlist. Perhaps debugfs is disabled.\n");
 		ret = -ENODEV;
 		goto err;
 	}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b2fb161..73f63c9 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -53,26 +53,23 @@
 	struct request_queue *q = mq->queue;
 	struct request *req;
 
-#ifdef CONFIG_MMC_PERF_PROFILING
-	ktime_t start, diff;
-	struct mmc_host *host = mq->card->host;
-	unsigned long bytes_xfer;
-#endif
-
-
 	current->flags |= PF_MEMALLOC;
 
 	down(&mq->thread_sem);
 	do {
+		struct mmc_queue_req *tmp;
 		req = NULL;	/* Must be set to NULL at each iteration */
 
 		spin_lock_irq(q->queue_lock);
 		set_current_state(TASK_INTERRUPTIBLE);
 		req = blk_fetch_request(q);
-		mq->req = req;
+		mq->mqrq_cur->req = req;
 		spin_unlock_irq(q->queue_lock);
 
-		if (!req) {
+		if (req || mq->mqrq_prev->req) {
+			set_current_state(TASK_RUNNING);
+			mq->issue_fn(mq, req);
+		} else {
 			if (kthread_should_stop()) {
 				set_current_state(TASK_RUNNING);
 				break;
@@ -80,30 +77,14 @@
 			up(&mq->thread_sem);
 			schedule();
 			down(&mq->thread_sem);
-			continue;
 		}
-		set_current_state(TASK_RUNNING);
 
-#ifdef CONFIG_MMC_PERF_PROFILING
-		bytes_xfer = blk_rq_bytes(req);
-		if (rq_data_dir(req) == READ) {
-			start = ktime_get();
-			mq->issue_fn(mq, req);
-			diff = ktime_sub(ktime_get(), start);
-			host->perf.rbytes_mmcq += bytes_xfer;
-			host->perf.rtime_mmcq =
-				ktime_add(host->perf.rtime_mmcq, diff);
-		} else {
-			start = ktime_get();
-			mq->issue_fn(mq, req);
-			diff = ktime_sub(ktime_get(), start);
-			host->perf.wbytes_mmcq += bytes_xfer;
-			host->perf.wtime_mmcq =
-				ktime_add(host->perf.wtime_mmcq, diff);
-		}
-#else
-			mq->issue_fn(mq, req);
-#endif
+		/* Current request becomes previous request and vice versa. */
+		mq->mqrq_prev->brq.mrq.data = NULL;
+		mq->mqrq_prev->req = NULL;
+		tmp = mq->mqrq_prev;
+		mq->mqrq_prev = mq->mqrq_cur;
+		mq->mqrq_cur = tmp;
 	} while (1);
 	up(&mq->thread_sem);
 
@@ -129,10 +110,46 @@
 		return;
 	}
 
-	if (!mq->req)
+	if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
 		wake_up_process(mq->thread);
 }
 
+struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
+{
+	struct scatterlist *sg;
+
+	sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
+	if (!sg)
+		*err = -ENOMEM;
+	else {
+		*err = 0;
+		sg_init_table(sg, sg_len);
+	}
+
+	return sg;
+}
+
+static void mmc_queue_setup_discard(struct request_queue *q,
+				    struct mmc_card *card)
+{
+	unsigned max_discard;
+
+	max_discard = mmc_calc_max_discard(card);
+	if (!max_discard)
+		return;
+
+	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+	q->limits.max_discard_sectors = max_discard;
+	if (card->erased_byte == 0)
+		q->limits.discard_zeroes_data = 1;
+	q->limits.discard_granularity = card->pref_erase << 9;
+	/* granularity must not be greater than max. discard */
+	if (card->pref_erase > max_discard)
+		q->limits.discard_granularity = 0;
+	if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
@@ -148,6 +165,8 @@
 	struct mmc_host *host = card->host;
 	u64 limit = BLK_BOUNCE_HIGH;
 	int ret;
+	struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+	struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
 
 	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
 		limit = *mmc_dev(host)->dma_mask;
@@ -157,21 +176,16 @@
 	if (!mq->queue)
 		return -ENOMEM;
 
+	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+	mq->mqrq_cur = mqrq_cur;
+	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
-	mq->req = NULL;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
-	if (mmc_can_erase(card)) {
-		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
-		mq->queue->limits.max_discard_sectors = UINT_MAX;
-		if (card->erased_byte == 0)
-			mq->queue->limits.discard_zeroes_data = 1;
-		mq->queue->limits.discard_granularity = card->pref_erase << 9;
-		if (mmc_can_secure_erase_trim(card))
-			queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD,
-						mq->queue);
-	}
+	if (mmc_can_erase(card))
+		mmc_queue_setup_discard(mq->queue, card);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_segs == 1) {
@@ -187,53 +201,64 @@
 			bouncesz = host->max_blk_count * 512;
 
 		if (bouncesz > 512) {
-			mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
-			if (!mq->bounce_buf) {
+			mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+			if (!mqrq_cur->bounce_buf) {
 				printk(KERN_WARNING "%s: unable to "
-					"allocate bounce buffer\n",
+					"allocate bounce cur buffer\n",
 					mmc_card_name(card));
 			}
+			mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+			if (!mqrq_prev->bounce_buf) {
+				printk(KERN_WARNING "%s: unable to "
+					"allocate bounce prev buffer\n",
+					mmc_card_name(card));
+				kfree(mqrq_cur->bounce_buf);
+				mqrq_cur->bounce_buf = NULL;
+			}
 		}
 
-		if (mq->bounce_buf) {
+		if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
 			blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
 			blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
 			blk_queue_max_segments(mq->queue, bouncesz / 512);
 			blk_queue_max_segment_size(mq->queue, bouncesz);
 
-			mq->sg = kmalloc(sizeof(struct scatterlist),
-				GFP_KERNEL);
-			if (!mq->sg) {
-				ret = -ENOMEM;
+			mqrq_cur->sg = mmc_alloc_sg(1, &ret);
+			if (ret)
 				goto cleanup_queue;
-			}
-			sg_init_table(mq->sg, 1);
 
-			mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
-				bouncesz / 512, GFP_KERNEL);
-			if (!mq->bounce_sg) {
-				ret = -ENOMEM;
+			mqrq_cur->bounce_sg =
+				mmc_alloc_sg(bouncesz / 512, &ret);
+			if (ret)
 				goto cleanup_queue;
-			}
-			sg_init_table(mq->bounce_sg, bouncesz / 512);
+
+			mqrq_prev->sg = mmc_alloc_sg(1, &ret);
+			if (ret)
+				goto cleanup_queue;
+
+			mqrq_prev->bounce_sg =
+				mmc_alloc_sg(bouncesz / 512, &ret);
+			if (ret)
+				goto cleanup_queue;
 		}
 	}
 #endif
 
-	if (!mq->bounce_buf) {
+	if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
 		blk_queue_bounce_limit(mq->queue, limit);
 		blk_queue_max_hw_sectors(mq->queue,
 			min(host->max_blk_count, host->max_req_size / 512));
 		blk_queue_max_segments(mq->queue, host->max_segs);
 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
-		mq->sg = kmalloc(sizeof(struct scatterlist) *
-			host->max_segs, GFP_KERNEL);
-		if (!mq->sg) {
-			ret = -ENOMEM;
+		mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
+		if (ret)
 			goto cleanup_queue;
-		}
-		sg_init_table(mq->sg, host->max_segs);
+
+
+		mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
+		if (ret)
+			goto cleanup_queue;
 	}
 
 	sema_init(&mq->thread_sem, 1);
@@ -248,16 +273,22 @@
 
 	return 0;
  free_bounce_sg:
- 	if (mq->bounce_sg)
- 		kfree(mq->bounce_sg);
- 	mq->bounce_sg = NULL;
+	kfree(mqrq_cur->bounce_sg);
+	mqrq_cur->bounce_sg = NULL;
+	kfree(mqrq_prev->bounce_sg);
+	mqrq_prev->bounce_sg = NULL;
+
  cleanup_queue:
- 	if (mq->sg)
-		kfree(mq->sg);
-	mq->sg = NULL;
-	if (mq->bounce_buf)
-		kfree(mq->bounce_buf);
-	mq->bounce_buf = NULL;
+	kfree(mqrq_cur->sg);
+	mqrq_cur->sg = NULL;
+	kfree(mqrq_cur->bounce_buf);
+	mqrq_cur->bounce_buf = NULL;
+
+	kfree(mqrq_prev->sg);
+	mqrq_prev->sg = NULL;
+	kfree(mqrq_prev->bounce_buf);
+	mqrq_prev->bounce_buf = NULL;
+
 	blk_cleanup_queue(mq->queue);
 	return ret;
 }
@@ -266,6 +297,8 @@
 {
 	struct request_queue *q = mq->queue;
 	unsigned long flags;
+	struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+	struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
 
 	/* Make sure the queue isn't suspended, as that will deadlock */
 	mmc_queue_resume(mq);
@@ -279,16 +312,23 @@
 	blk_start_queue(q);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 
- 	if (mq->bounce_sg)
- 		kfree(mq->bounce_sg);
- 	mq->bounce_sg = NULL;
+	kfree(mqrq_cur->bounce_sg);
+	mqrq_cur->bounce_sg = NULL;
 
-	kfree(mq->sg);
-	mq->sg = NULL;
+	kfree(mqrq_cur->sg);
+	mqrq_cur->sg = NULL;
 
-	if (mq->bounce_buf)
-		kfree(mq->bounce_buf);
-	mq->bounce_buf = NULL;
+	kfree(mqrq_cur->bounce_buf);
+	mqrq_cur->bounce_buf = NULL;
+
+	kfree(mqrq_prev->bounce_sg);
+	mqrq_prev->bounce_sg = NULL;
+
+	kfree(mqrq_prev->sg);
+	mqrq_prev->sg = NULL;
+
+	kfree(mqrq_prev->bounce_buf);
+	mqrq_prev->bounce_buf = NULL;
 
 	mq->card = NULL;
 }
@@ -341,27 +381,27 @@
 /*
  * Prepare the sg list(s) to be handed of to the host driver
  */
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
+unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
 {
 	unsigned int sg_len;
 	size_t buflen;
 	struct scatterlist *sg;
 	int i;
 
-	if (!mq->bounce_buf)
-		return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
+	if (!mqrq->bounce_buf)
+		return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
 
-	BUG_ON(!mq->bounce_sg);
+	BUG_ON(!mqrq->bounce_sg);
 
-	sg_len = blk_rq_map_sg(mq->queue, mq->req, mq->bounce_sg);
+	sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
 
-	mq->bounce_sg_len = sg_len;
+	mqrq->bounce_sg_len = sg_len;
 
 	buflen = 0;
-	for_each_sg(mq->bounce_sg, sg, sg_len, i)
+	for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
 		buflen += sg->length;
 
-	sg_init_one(mq->sg, mq->bounce_buf, buflen);
+	sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
 
 	return 1;
 }
@@ -370,31 +410,30 @@
  * If writing, bounce the data to the buffer before the request
  * is sent to the host driver
  */
-void mmc_queue_bounce_pre(struct mmc_queue *mq)
+void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
 {
-	if (!mq->bounce_buf)
+	if (!mqrq->bounce_buf)
 		return;
 
-	if (rq_data_dir(mq->req) != WRITE)
+	if (rq_data_dir(mqrq->req) != WRITE)
 		return;
 
-	sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
-		mq->bounce_buf, mq->sg[0].length);
+	sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+		mqrq->bounce_buf, mqrq->sg[0].length);
 }
 
 /*
  * If reading, bounce the data from the buffer after the request
  * has been handled by the host driver
  */
-void mmc_queue_bounce_post(struct mmc_queue *mq)
+void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
 {
-	if (!mq->bounce_buf)
+	if (!mqrq->bounce_buf)
 		return;
 
-	if (rq_data_dir(mq->req) != READ)
+	if (rq_data_dir(mqrq->req) != READ)
 		return;
 
-	sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
-		mq->bounce_buf, mq->sg[0].length);
+	sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+		mqrq->bounce_buf, mqrq->sg[0].length);
 }
-
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 6223ef8..d2a1eb4 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -4,19 +4,35 @@
 struct request;
 struct task_struct;
 
+struct mmc_blk_request {
+	struct mmc_request	mrq;
+	struct mmc_command	sbc;
+	struct mmc_command	cmd;
+	struct mmc_command	stop;
+	struct mmc_data		data;
+};
+
+struct mmc_queue_req {
+	struct request		*req;
+	struct mmc_blk_request	brq;
+	struct scatterlist	*sg;
+	char			*bounce_buf;
+	struct scatterlist	*bounce_sg;
+	unsigned int		bounce_sg_len;
+	struct mmc_async_req	mmc_active;
+};
+
 struct mmc_queue {
 	struct mmc_card		*card;
 	struct task_struct	*thread;
 	struct semaphore	thread_sem;
 	unsigned int		flags;
-	struct request		*req;
 	int			(*issue_fn)(struct mmc_queue *, struct request *);
 	void			*data;
 	struct request_queue	*queue;
-	struct scatterlist	*sg;
-	char			*bounce_buf;
-	struct scatterlist	*bounce_sg;
-	unsigned int		bounce_sg_len;
+	struct mmc_queue_req	mqrq[2];
+	struct mmc_queue_req	*mqrq_cur;
+	struct mmc_queue_req	*mqrq_prev;
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -25,8 +41,9 @@
 extern void mmc_queue_suspend(struct mmc_queue *);
 extern void mmc_queue_resume(struct mmc_queue *);
 
-extern unsigned int mmc_queue_map_sg(struct mmc_queue *);
-extern void mmc_queue_bounce_pre(struct mmc_queue *);
-extern void mmc_queue_bounce_post(struct mmc_queue *);
+extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
+				     struct mmc_queue_req *);
+extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
+extern void mmc_queue_bounce_post(struct mmc_queue_req *);
 
 #endif
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 51434b6..1eb9d5f 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -106,12 +106,12 @@
 	}
 
 	if (err && cmd->retries && !mmc_card_removed(host->card)) {
-		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
-			mmc_hostname(host), cmd->opcode, err);
-
-		cmd->retries--;
-		cmd->error = 0;
-		host->ops->request(host, mrq);
+		/*
+		 * Request starter must handle retries - see
+		 * mmc_wait_for_req_done().
+		 */
+		if (mrq->done)
+			mrq->done(mrq);
 	} else {
 		led_trigger_event(host->led, LED_OFF);
 
@@ -220,9 +220,123 @@
 
 static void mmc_wait_done(struct mmc_request *mrq)
 {
-	complete(mrq->done_data);
+	complete(&mrq->completion);
 }
 
+static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+	init_completion(&mrq->completion);
+	mrq->done = mmc_wait_done;
+	mmc_start_request(host, mrq);
+}
+
+static void mmc_wait_for_req_done(struct mmc_host *host,
+				  struct mmc_request *mrq)
+{
+	struct mmc_command *cmd;
+
+	while (1) {
+		wait_for_completion(&mrq->completion);
+
+		cmd = mrq->cmd;
+		if (!cmd->error || !cmd->retries)
+			break;
+
+		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+			 mmc_hostname(host), cmd->opcode, cmd->error);
+		cmd->retries--;
+		cmd->error = 0;
+		host->ops->request(host, mrq);
+	}
+}
+
+/**
+ *	mmc_pre_req - Prepare for a new request
+ *	@host: MMC host to prepare command
+ *	@mrq: MMC request to prepare for
+ *	@is_first_req: true if there is no previous started request
+ *                     that may run in parellel to this call, otherwise false
+ *
+ *	mmc_pre_req() is called in prior to mmc_start_req() to let
+ *	host prepare for the new request. Preparation of a request may be
+ *	performed while another request is running on the host.
+ */
+static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+		 bool is_first_req)
+{
+	if (host->ops->pre_req)
+		host->ops->pre_req(host, mrq, is_first_req);
+}
+
+/**
+ *	mmc_post_req - Post process a completed request
+ *	@host: MMC host to post process command
+ *	@mrq: MMC request to post process for
+ *	@err: Error, if non zero, clean up any resources made in pre_req
+ *
+ *	Let the host post process a completed request. Post processing of
+ *	a request may be performed while another reuqest is running.
+ */
+static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+			 int err)
+{
+	if (host->ops->post_req)
+		host->ops->post_req(host, mrq, err);
+}
+
+/**
+ *	mmc_start_req - start a non-blocking request
+ *	@host: MMC host to start command
+ *	@areq: async request to start
+ *	@error: out parameter returns 0 for success, otherwise non zero
+ *
+ *	Start a new MMC custom command request for a host.
+ *	If there is on ongoing async request wait for completion
+ *	of that request and start the new one and return.
+ *	Does not wait for the new request to complete.
+ *
+ *      Returns the completed request, NULL in case of none completed.
+ *	Wait for the an ongoing request (previoulsy started) to complete and
+ *	return the completed request. If there is no ongoing request, NULL
+ *	is returned without waiting. NULL is not an error condition.
+ */
+struct mmc_async_req *mmc_start_req(struct mmc_host *host,
+				    struct mmc_async_req *areq, int *error)
+{
+	int err = 0;
+	struct mmc_async_req *data = host->areq;
+
+	/* Prepare a new request */
+	if (areq)
+		mmc_pre_req(host, areq->mrq, !host->areq);
+
+	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 (host->areq)
+		mmc_post_req(host, host->areq->mrq, 0);
+
+	host->areq = areq;
+ out:
+	if (error)
+		*error = err;
+	return data;
+}
+EXPORT_SYMBOL(mmc_start_req);
+
 /**
  *	mmc_wait_for_req - start a request and wait for completion
  *	@host: MMC host to start command
@@ -234,21 +348,67 @@
  */
 void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 {
-	DECLARE_COMPLETION_ONSTACK(complete);
+	__mmc_start_req(host, mrq);
+	mmc_wait_for_req_done(host, mrq);
+}
+EXPORT_SYMBOL(mmc_wait_for_req);
 
-	mrq->done_data = &complete;
-	mrq->done = mmc_wait_done;
-	if (mmc_card_removed(host->card)) {
-		mrq->cmd->error = -ENOMEDIUM;
-		return;
+/**
+ *	mmc_interrupt_hpi - Issue for High priority Interrupt
+ *	@card: the MMC card associated with the HPI transfer
+ *
+ *	Issued High Priority Interrupt, and check for card status
+ *	util out-of prg-state.
+ */
+int mmc_interrupt_hpi(struct mmc_card *card)
+{
+	int err;
+	u32 status;
+
+	BUG_ON(!card);
+
+	if (!card->ext_csd.hpi_en) {
+		pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
+		return 1;
 	}
 
-	mmc_start_request(host, mrq);
+	mmc_claim_host(card->host);
+	err = mmc_send_status(card, &status);
+	if (err) {
+		pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
+		goto out;
+	}
 
-	wait_for_completion_io(&complete);
+	/*
+	 * If the card status is in PRG-state, we can send the HPI command.
+	 */
+	if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
+		do {
+			/*
+			 * We don't know when the HPI command will finish
+			 * processing, so we need to resend HPI until out
+			 * of prg-state, and keep checking the card status
+			 * with SEND_STATUS.  If a timeout error occurs when
+			 * sending the HPI command, we are already out of
+			 * prg-state.
+			 */
+			err = mmc_send_hpi_cmd(card, &status);
+			if (err)
+				pr_debug("%s: abort HPI (%d error)\n",
+					 mmc_hostname(card->host), err);
+
+			err = mmc_send_status(card, &status);
+			if (err)
+				break;
+		} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+	} else
+		pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+
+out:
+	mmc_release_host(card->host);
+	return err;
 }
-
-EXPORT_SYMBOL(mmc_wait_for_req);
+EXPORT_SYMBOL(mmc_interrupt_hpi);
 
 /**
  *	mmc_wait_for_cmd - start a command and wait for completion
@@ -262,7 +422,7 @@
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 
 	WARN_ON(!host->claimed);
 
@@ -1035,6 +1195,46 @@
 	mmc_host_clk_release(host);
 }
 
+static void mmc_poweroff_notify(struct mmc_host *host)
+{
+	struct mmc_card *card;
+	unsigned int timeout;
+	unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
+	int err = 0;
+
+	card = host->card;
+
+	/*
+	 * Send power notify command only if card
+	 * is mmc and notify state is powered ON
+	 */
+	if (card && mmc_card_mmc(card) &&
+	    (card->poweroff_notify_state == MMC_POWERED_ON)) {
+
+		if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
+			notify_type = EXT_CSD_POWER_OFF_SHORT;
+			timeout = card->ext_csd.generic_cmd6_time;
+			card->poweroff_notify_state = MMC_POWEROFF_SHORT;
+		} else {
+			notify_type = EXT_CSD_POWER_OFF_LONG;
+			timeout = card->ext_csd.power_off_longtime;
+			card->poweroff_notify_state = MMC_POWEROFF_LONG;
+		}
+
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_OFF_NOTIFICATION,
+				 notify_type, timeout);
+
+		if (err && err != -EBADMSG)
+			pr_err("Device failed to respond within %d poweroff "
+			       "time. Forcefully powering down the device\n",
+			       timeout);
+
+		/* Set the card state to no notification after the poweroff */
+		card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
+	}
+}
+
 /*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
@@ -1091,13 +1291,15 @@
 	mmc_host_clk_release(host);
 }
 
-static void mmc_power_off(struct mmc_host *host)
+void mmc_power_off(struct mmc_host *host)
 {
 	mmc_host_clk_hold(host);
 
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
 
+	mmc_poweroff_notify(host);
+
 	/*
 	 * Reset ocr mask to be the highest possible voltage supported for
 	 * this mmc host. This value will be used at next power up.
@@ -1452,7 +1654,7 @@
 	if (err) {
 		printk(KERN_ERR "mmc_erase: group start error %d, "
 		       "status %#x\n", err, cmd.resp[0]);
-		err = -EINVAL;
+		err = -EIO;
 		goto out;
 	}
 
@@ -1467,7 +1669,7 @@
 	if (err) {
 		printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n",
 		       err, cmd.resp[0]);
-		err = -EINVAL;
+		err = -EIO;
 		goto out;
 	}
 
@@ -1501,7 +1703,7 @@
 			goto out;
 		}
 	} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
-		 R1_CURRENT_STATE(cmd.resp[0]) == 7);
+		 R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
 out:
 	return err;
 }
@@ -1586,10 +1788,32 @@
 {
 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
 		return 1;
+	if (mmc_can_discard(card))
+		return 1;
 	return 0;
 }
 EXPORT_SYMBOL(mmc_can_trim);
 
+int mmc_can_discard(struct mmc_card *card)
+{
+	/*
+	 * As there's no way to detect the discard support bit at v4.5
+	 * use the s/w feature support filed.
+	 */
+	if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_discard);
+
+int mmc_can_sanitize(struct mmc_card *card)
+{
+	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_sanitize);
+
 int mmc_can_secure_erase_trim(struct mmc_card *card)
 {
 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
@@ -1609,6 +1833,82 @@
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
+static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
+					    unsigned int arg)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
+	unsigned int last_timeout = 0;
+
+	if (card->erase_shift)
+		max_qty = UINT_MAX >> card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_qty = UINT_MAX;
+	else
+		max_qty = UINT_MAX / card->erase_size;
+
+	/* Find the largest qty with an OK timeout */
+	do {
+		y = 0;
+		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
+			timeout = mmc_erase_timeout(card, arg, qty + x);
+			if (timeout > host->max_discard_to)
+				break;
+			if (timeout < last_timeout)
+				break;
+			last_timeout = timeout;
+			y = x;
+		}
+		qty += y;
+	} while (y);
+
+	if (!qty)
+		return 0;
+
+	if (qty == 1)
+		return 1;
+
+	/* Convert qty to sectors */
+	if (card->erase_shift)
+		max_discard = --qty << card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_discard = qty;
+	else
+		max_discard = --qty * card->erase_size;
+
+	return max_discard;
+}
+
+unsigned int mmc_calc_max_discard(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, max_trim;
+
+	if (!host->max_discard_to)
+		return UINT_MAX;
+
+	/*
+	 * Without erase_group_def set, MMC erase timeout depends on clock
+	 * frequence which can change.  In that case, the best choice is
+	 * just the preferred erase size.
+	 */
+	if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
+		return card->pref_erase;
+
+	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
+	if (mmc_can_trim(card)) {
+		max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
+		if (max_trim < max_discard)
+			max_discard = max_trim;
+	} else if (max_discard < card->erase_size) {
+		max_discard = 0;
+	}
+	pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
+		 mmc_hostname(host), max_discard, host->max_discard_to);
+	return max_discard;
+}
+EXPORT_SYMBOL(mmc_calc_max_discard);
+
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
@@ -1623,6 +1923,94 @@
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
+static void mmc_hw_reset_for_init(struct mmc_host *host)
+{
+	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+		return;
+	mmc_host_clk_hold(host);
+	host->ops->hw_reset(host);
+	mmc_host_clk_release(host);
+}
+
+int mmc_can_reset(struct mmc_card *card)
+{
+	u8 rst_n_function;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+	rst_n_function = card->ext_csd.rst_n_function;
+	if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
+		return 0;
+	return 1;
+}
+EXPORT_SYMBOL(mmc_can_reset);
+
+static int mmc_do_hw_reset(struct mmc_host *host, int check)
+{
+	struct mmc_card *card = host->card;
+
+	if (!host->bus_ops->power_restore)
+		return -EOPNOTSUPP;
+
+	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+		return -EOPNOTSUPP;
+
+	if (!card)
+		return -EINVAL;
+
+	if (!mmc_can_reset(card))
+		return -EOPNOTSUPP;
+
+	mmc_host_clk_hold(host);
+	mmc_set_clock(host, host->f_init);
+
+	host->ops->hw_reset(host);
+
+	/* If the reset has happened, then a status command will fail */
+	if (check) {
+		struct mmc_command cmd = {0};
+		int err;
+
+		cmd.opcode = MMC_SEND_STATUS;
+		if (!mmc_host_is_spi(card->host))
+			cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+		err = mmc_wait_for_cmd(card->host, &cmd, 0);
+		if (!err) {
+			mmc_host_clk_release(host);
+			return -ENOSYS;
+		}
+	}
+
+	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
+	if (mmc_host_is_spi(host)) {
+		host->ios.chip_select = MMC_CS_HIGH;
+		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+	} else {
+		host->ios.chip_select = MMC_CS_DONTCARE;
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	}
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
+	host->ios.timing = MMC_TIMING_LEGACY;
+	mmc_set_ios(host);
+
+	mmc_host_clk_release(host);
+
+	return host->bus_ops->power_restore(host);
+}
+
+int mmc_hw_reset(struct mmc_host *host)
+{
+	return mmc_do_hw_reset(host, 0);
+}
+EXPORT_SYMBOL(mmc_hw_reset);
+
+int mmc_hw_reset_check(struct mmc_host *host)
+{
+	return mmc_do_hw_reset(host, 1);
+}
+EXPORT_SYMBOL(mmc_hw_reset_check);
+
 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 {
 	host->f_init = freq;
@@ -1634,6 +2022,12 @@
 	mmc_power_up(host);
 
 	/*
+	 * Some eMMCs (with VCCQ always on) may not be reset after power up, so
+	 * do a hardware reset if possible.
+	 */
+	mmc_hw_reset_for_init(host);
+
+	/*
 	 * sdio_reset sends CMD52 to reset card.  Since we do not know
 	 * if the card is being re-initialized, just send it.  CMD52
 	 * should be ignored by SD/eMMC cards.
@@ -1870,7 +2264,7 @@
 
 	mmc_bus_get(host);
 
-	if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+	if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
 		err = host->bus_ops->sleep(host);
 
 	mmc_bus_put(host);
@@ -1889,6 +2283,65 @@
 }
 EXPORT_SYMBOL(mmc_card_can_sleep);
 
+/*
+ * Flush the cache to the non-volatile storage.
+ */
+int mmc_flush_cache(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
+		return err;
+
+	if (mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0) &&
+			(card->ext_csd.cache_ctrl & 1)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_FLUSH_CACHE, 1, 0);
+		if (err)
+			pr_err("%s: cache flush error %d\n",
+					mmc_hostname(card->host), err);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_flush_cache);
+
+/*
+ * Turn the cache ON/OFF.
+ * Turning the cache OFF shall trigger flushing of the data
+ * to the non-volatile storage.
+ */
+int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
+{
+	struct mmc_card *card = host->card;
+	int err = 0;
+
+	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
+			mmc_card_is_removable(host))
+		return err;
+
+	if (card && mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0)) {
+		enable = !!enable;
+
+		if (card->ext_csd.cache_ctrl ^ enable)
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_CACHE_CTRL, enable, 0);
+		if (err)
+			pr_err("%s: cache %s error %d\n",
+					mmc_hostname(card->host),
+					enable ? "on" : "off",
+					err);
+		else
+			card->ext_csd.cache_ctrl = enable;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_cache_ctrl);
+
 #ifdef CONFIG_PM
 
 /**
@@ -1907,6 +2360,9 @@
 	if (cancel_delayed_work(&host->detect))
 		wake_unlock(&host->detect_wake_lock);
 	mmc_flush_scheduled_work();
+	err = mmc_cache_ctrl(host, 0);
+	if (err)
+		goto out;
 
 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
@@ -1928,8 +2384,15 @@
 				err = -EBUSY;
 
 		if (!err) {
-			if (host->bus_ops->suspend)
+			if (host->bus_ops->suspend) {
+				/*
+				 * For eMMC 4.5 device send notify command
+				 * before sleep, because in sleep state eMMC 4.5
+				 * devices respond to only RESET and AWAKE cmd
+				 */
+				mmc_poweroff_notify(host);
 				err = host->bus_ops->suspend(host);
+			}
 			if (!(host->card && mmc_card_sdio(host->card)))
 				mmc_do_release_host(host);
 
@@ -1954,6 +2417,7 @@
 	if (!err && !mmc_card_keep_power(host))
 		mmc_power_off(host);
 
+out:
 	return err;
 }
 
@@ -2029,6 +2493,7 @@
 			break;
 		}
 		host->rescan_disable = 1;
+		host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
 		spin_unlock_irqrestore(&host->lock, flags);
 		if (cancel_delayed_work_sync(&host->detect))
 			wake_unlock(&host->detect_wake_lock);
@@ -2056,6 +2521,7 @@
 			break;
 		}
 		host->rescan_disable = 0;
+		host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
 		spin_unlock_irqrestore(&host->lock, flags);
 		mmc_detect_change(host, 0);
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 79d6e97..0c70d4a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -259,7 +259,7 @@
 	}
 
 	card->ext_csd.rev = ext_csd[EXT_CSD_REV];
-	if (card->ext_csd.rev > 5) {
+	if (card->ext_csd.rev > 6) {
 		printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
 			mmc_hostname(card->host), card->ext_csd.rev);
 		err = -EINVAL;
@@ -359,6 +359,7 @@
 		 * card has the Enhanced area enabled.  If so, export enhanced
 		 * area offset and size to user by adding sysfs interface.
 		 */
+		card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
 		if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
 		    (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
 			u8 hc_erase_grp_sz =
@@ -402,14 +403,48 @@
 			ext_csd[EXT_CSD_TRIM_MULT];
 	}
 
-	if (card->ext_csd.rev >= 5)
-		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+	if (card->ext_csd.rev >= 5) {
+		/* check whether the eMMC card supports HPI */
+		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+			card->ext_csd.hpi = 1;
+			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
+				card->ext_csd.hpi_cmd =	MMC_STOP_TRANSMISSION;
+			else
+				card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
+			/*
+			 * Indicate the maximum timeout to close
+			 * a command interrupted by HPI
+			 */
+			card->ext_csd.out_of_int_time =
+				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
+		}
 
+		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+	}
+
+	card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
 	if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
 		card->erased_byte = 0xFF;
 	else
 		card->erased_byte = 0x0;
 
+	/* eMMC v4.5 or later */
+	if (card->ext_csd.rev >= 6) {
+		card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
+
+		card->ext_csd.generic_cmd6_time = 10 *
+			ext_csd[EXT_CSD_GENERIC_CMD6_TIME];
+		card->ext_csd.power_off_longtime = 10 *
+			ext_csd[EXT_CSD_POWER_OFF_LONG_TIME];
+
+		card->ext_csd.cache_size =
+			ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+	}
+
 out:
 	return err;
 }
@@ -530,6 +565,86 @@
 };
 
 /*
+ * Select the PowerClass for the current bus width
+ * If power class is defined for 4/8 bit bus in the
+ * extended CSD register, select it by executing the
+ * mmc_switch command.
+ */
+static int mmc_select_powerclass(struct mmc_card *card,
+		unsigned int bus_width, u8 *ext_csd)
+{
+	int err = 0;
+	unsigned int pwrclass_val;
+	unsigned int index = 0;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+	BUG_ON(!host);
+
+	if (ext_csd == NULL)
+		return 0;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == EXT_CSD_BUS_WIDTH_1)
+		return 0;
+
+	switch (1 << host->ios.vdd) {
+	case MMC_VDD_165_195:
+		if (host->ios.clock <= 26000000)
+			index = EXT_CSD_PWR_CL_26_195;
+		else if	(host->ios.clock <= 52000000)
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_52_195 :
+				EXT_CSD_PWR_CL_DDR_52_195;
+		else if (host->ios.clock <= 200000000)
+			index = EXT_CSD_PWR_CL_200_195;
+		break;
+	case MMC_VDD_32_33:
+	case MMC_VDD_33_34:
+	case MMC_VDD_34_35:
+	case MMC_VDD_35_36:
+		if (host->ios.clock <= 26000000)
+			index = EXT_CSD_PWR_CL_26_360;
+		else if	(host->ios.clock <= 52000000)
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_52_360 :
+				EXT_CSD_PWR_CL_DDR_52_360;
+		else if (host->ios.clock <= 200000000)
+			index = EXT_CSD_PWR_CL_200_360;
+		break;
+	default:
+		pr_warning("%s: Voltage range not supported "
+			   "for power class.\n", mmc_hostname(host));
+		return -EINVAL;
+	}
+
+	pwrclass_val = ext_csd[index];
+
+	if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
+		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
+				EXT_CSD_PWR_CL_8BIT_SHIFT;
+	else
+		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
+				EXT_CSD_PWR_CL_4BIT_SHIFT;
+
+	/* If the power class is different from the default value */
+	if (pwrclass_val > 0) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_CLASS,
+				 pwrclass_val,
+				 card->ext_csd.generic_cmd6_time);
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -671,7 +786,8 @@
 	 */
 	if (card->ext_csd.enhanced_area_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_ERASE_GROUP_DEF, 1, 0);
+				 EXT_CSD_ERASE_GROUP_DEF, 1,
+				 card->ext_csd.generic_cmd6_time);
 
 		if (err && err != -EBADMSG)
 			goto free_card;
@@ -709,12 +825,34 @@
 	}
 
 	/*
+	 * If the host supports the power_off_notify capability then
+	 * set the notification byte in the ext_csd register of device
+	 */
+	if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
+	    (card->ext_csd.rev >= 6)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_OFF_NOTIFICATION,
+				 EXT_CSD_POWER_ON,
+				 card->ext_csd.generic_cmd6_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
+
+		/*
+		 * The err can be -EBADMSG or 0,
+		 * so check for success and update the flag
+		 */
+		if (!err)
+			card->poweroff_notify_state = MMC_POWERED_ON;
+	}
+
+	/*
 	 * Activate high speed (if supported)
 	 */
 	if ((card->ext_csd.hs_max_dtr != 0) &&
 		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 1, 0);
+				 EXT_CSD_HS_TIMING, 1,
+				 card->ext_csd.generic_cmd6_time);
 		if (err && err != -EBADMSG)
 			goto free_card;
 
@@ -729,6 +867,22 @@
 	}
 
 	/*
+	 * Enable HPI feature (if supported)
+	 */
+	if (card->ext_csd.hpi) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_HPI_MGMT, 1, 0);
+		if (err && err != -EBADMSG)
+			goto free_card;
+		if (err) {
+			pr_warning("%s: Enabling HPI failed\n",
+				   mmc_hostname(card->host));
+			err = 0;
+		} else
+			card->ext_csd.hpi_en = 1;
+	}
+
+	/*
 	 * Compute bus speed.
 	 */
 	max_dtr = (unsigned int)-1;
@@ -783,10 +937,18 @@
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
+			err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
+						    ext_csd);
+			if (err)
+				pr_err("%s: power class selection to "
+				       "bus width %d failed\n",
+				       mmc_hostname(card->host),
+				       1 << bus_width);
+
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][0],
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 			if (!err) {
 				mmc_set_bus_width(card->host, bus_width);
 
@@ -806,10 +968,18 @@
 		}
 
 		if (!err && ddr) {
+			err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
+						    ext_csd);
+			if (err)
+				pr_err("%s: power class selection to "
+				       "bus width %d ddr %d failed\n",
+				       mmc_hostname(card->host),
+				       1 << bus_width, ddr);
+
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 		}
 		if (err) {
 			printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
@@ -843,6 +1013,23 @@
 		}
 	}
 
+	/*
+	 * If cache size is higher than 0, this indicates
+	 * the existence of cache and it can be turned on.
+	 */
+	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
+			card->ext_csd.cache_size > 0) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_CACHE_CTRL, 1, 0);
+		if (err && err != -EBADMSG)
+			goto free_card;
+
+		/*
+		 * Only if no error, cache is turned on successfully.
+		 */
+		card->ext_csd.cache_ctrl = err ? 0 : 1;
+	}
+
 	if (!oldcard)
 		host->card = card;
 
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 2e39d2c..2438176 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -233,7 +233,7 @@
 mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
 		u32 opcode, void *buf, unsigned len)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -408,7 +408,7 @@
 			break;
 		if (mmc_host_is_spi(card->host))
 			break;
-	} while (R1_CURRENT_STATE(status) == 7);
+	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
 	if (mmc_host_is_spi(card->host)) {
 		if (status & R1_SPI_ILLEGAL_COMMAND)
@@ -455,7 +455,7 @@
 mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
 		  u8 len)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -551,3 +551,34 @@
 	err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
 	return err;
 }
+
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
+{
+	struct mmc_command cmd = {0};
+	unsigned int opcode;
+	unsigned int flags;
+	int err;
+
+	opcode = card->ext_csd.hpi_cmd;
+	if (opcode == MMC_STOP_TRANSMISSION)
+		flags = MMC_RSP_R1 | MMC_CMD_AC;
+	else if (opcode == MMC_SEND_STATUS)
+		flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	cmd.opcode = opcode;
+	cmd.arg = card->rca << 16 | 1;
+	cmd.flags = flags;
+	cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err) {
+		pr_warn("%s: error %d interrupting operation. "
+			"HPI command response %#x\n", mmc_hostname(card->host),
+			err, cmd.resp[0]);
+		return err;
+	}
+	if (status)
+		*status = cmd.resp[0];
+
+	return 0;
+}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 9276946..3dd8941 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -26,6 +26,7 @@
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 int mmc_card_sleepawake(struct mmc_host *host, int sleep);
 int mmc_bus_test(struct mmc_card *card, u8 bus_width);
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
 
 #endif
 
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed1..46a7854 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -67,7 +67,7 @@
 int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
 	struct mmc_command *cmd, int retries)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 
 	int i, err;
 
@@ -244,7 +244,7 @@
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 {
 	int err;
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -303,7 +303,7 @@
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 	u8 value, u8 *resp)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -348,7 +348,7 @@
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
 {
 	int err;
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index f087d87..4addbe9 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -121,7 +121,7 @@
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7c1e16a..92946b8 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/bio.h>
 #include <linux/dma-mapping.h>
 #include <linux/crc7.h>
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index d513d47..99b449d 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -37,6 +37,7 @@
 #include <linux/mmc/sdio.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/module.h>
 
 #include <mach/mxs.h>
 #include <mach/common.h>
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index ba40d6d..6be0a24 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -15,6 +15,7 @@
 
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 68ddb75..aaea044 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -20,6 +20,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 936bbca..67c8709 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -14,6 +14,7 @@
 
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 60a4c97..a152b5c 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 343c97e..bb1ae46 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
+#include <linux/module.h>
 
 #include <mach/gpio.h>
 #include <mach/sdhci.h>
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aad27c8..9cf813e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/highmem.h>
 #include <linux/io.h>
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
@@ -2558,6 +2559,15 @@
 	if (caps[1] & SDHCI_DRIVER_TYPE_D)
 		mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
 
+	/*
+	 * If Power Off Notify capability is enabled by the host,
+	 * set notify to short power off notify timeout value.
+	 */
+	if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
+	else
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
+
 	/* Initial value for re-tuning timer count */
 	host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
 			      SDHCI_RETUNING_TIMER_COUNT_SHIFT;
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index 496b7ef..7009f17 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -26,6 +26,7 @@
 */
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/scatterlist.h>
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 14f8edb..51b68cc 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -31,6 +31,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/spinlock.h>
+#include <linux/module.h>
 
 #define DRIVER_NAME	"sh_mmcif"
 #define DRIVER_VERSION	"2010-04-28"
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index ce500f0..f5ce77b 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 457c26e..90c6b1b 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -16,6 +16,7 @@
 #include <linux/mmc/host.h>
 #include <linux/highmem.h>
 #include <linux/scatterlist.h>
+#include <linux/module.h>
 #include <asm/io.h>
 
 #define DRIVER_NAME "tifm_sd"
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 4dfe2c0..faf3594 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/highmem.h>
 #include <linux/delay.h>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 3104daf..709583a 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -103,7 +103,7 @@
 	unsigned int		charging_began;
 	unsigned int		start_percent;
 	unsigned int		end_percent;
-
+	enum battery_type	batt_type;
 	uint16_t		ocv_reading_at_100;
 	int			cc_reading_at_100;
 	int			max_voltage_uv;
@@ -1565,38 +1565,60 @@
 	}
 	pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
 						result.measurement);
-	return result.physical;
+	return result.adc_code;
 }
 
-#define PALLADIUM_ID_MIN  2500
-#define PALLADIUM_ID_MAX  4000
+#define PALLADIUM_ID_MIN	0x7F40
+#define PALLADIUM_ID_MAX	0x7F5A
+#define DESAY_5200_ID_MIN	0x7F7F
+#define DESAY_5200_ID_MAX	0x802F
 static int set_battery_data(struct pm8921_bms_chip *chip)
 {
 	int64_t battery_id;
 
-	battery_id = read_battery_id(chip);
+	if (chip->batt_type == BATT_DESAY)
+		goto desay;
+	else if (chip->batt_type == BATT_PALLADIUM)
+		goto palladium;
 
+	battery_id = read_battery_id(chip);
 	if (battery_id < 0) {
 		pr_err("cannot read battery id err = %lld\n", battery_id);
 		return battery_id;
 	}
 
 	if (is_between(PALLADIUM_ID_MIN, PALLADIUM_ID_MAX, battery_id)) {
-		chip->fcc = palladium_1500_data.fcc;
-		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
-		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
-		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
-		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
-		return 0;
+		goto palladium;
+	} else if (is_between(DESAY_5200_ID_MIN, DESAY_5200_ID_MAX,
+				battery_id)) {
+		goto desay;
 	} else {
-		pr_warn("invalid battery id, palladium 1500 assumed\n");
+		goto unknown;
+	}
+
+palladium:
 		chip->fcc = palladium_1500_data.fcc;
 		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
 		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
 		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
 		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
 		return 0;
-	}
+desay:
+		chip->fcc = desay_5200_data.fcc;
+		chip->fcc_temp_lut = desay_5200_data.fcc_temp_lut;
+		chip->fcc_sf_lut = desay_5200_data.fcc_sf_lut;
+		chip->pc_temp_ocv_lut = desay_5200_data.pc_temp_ocv_lut;
+		chip->pc_sf_lut = desay_5200_data.pc_sf_lut;
+		return 0;
+unknown:
+		pr_warn("invalid battery id, palladium 1500 assumed batt_id %llx\n",
+				battery_id);
+		chip->fcc = palladium_1500_data.fcc;
+		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
+		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
+		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
+		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
+		return 0;
 }
 
 enum {
@@ -1867,6 +1889,7 @@
 	chip->v_failure = pdata->v_failure;
 	chip->calib_delay_ms = pdata->calib_delay_ms;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
+	chip->batt_type = pdata->battery_type;
 	chip->start_percent = -EINVAL;
 	chip->end_percent = -EINVAL;
 	rc = set_battery_data(chip);
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index cb42d89..93730ae 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -155,7 +155,7 @@
 		ram_console.flags &= ~CON_ENABLED;
 }
 
-static void __init
+static void __devinit
 ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo,
 	char *dest)
 {
@@ -239,7 +239,7 @@
 	}
 }
 
-static int __init ram_console_init(struct ram_console_buffer *buffer,
+static int __devinit ram_console_init(struct ram_console_buffer *buffer,
 				   size_t buffer_size, const char *bootinfo,
 				   char *old_buf)
 {
@@ -336,7 +336,7 @@
 		ram_console_old_log_init_buffer);
 }
 #else
-static int ram_console_driver_probe(struct platform_device *pdev)
+static int __devinit ram_console_driver_probe(struct platform_device *pdev)
 {
 	struct resource *res = pdev->resource;
 	size_t start;
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index b71e309..caa5fda 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -651,6 +651,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ssu100.
 
+config USB_SERIAL_CSVT
+	tristate "USB serial driver for Circuit-Switched Video Telephony"
+	help
+	  Say Y here if you want to use usb serial driver for Circuit-Switched
+	  Video Telephony
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called csvt.
+
 config USB_SERIAL_DEBUG
 	tristate "USB Debugging Device"
 	help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 9e536ee..2d085b2 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -60,3 +60,4 @@
 obj-$(CONFIG_USB_SERIAL_XIRCOM)			+= keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)		+= vivopay-serial.o
 obj-$(CONFIG_USB_SERIAL_ZIO)			+= zio.o
+obj-$(CONFIG_USB_SERIAL_CSVT)			+= csvt.o
diff --git a/drivers/usb/serial/csvt.c b/drivers/usb/serial/csvt.c
new file mode 100644
index 0000000..5bfb2dc
--- /dev/null
+++ b/drivers/usb/serial/csvt.c
@@ -0,0 +1,446 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/serial.h>
+#include <asm/unaligned.h>
+
+
+/* output control lines*/
+#define CSVT_CTRL_DTR		0x01
+#define CSVT_CTRL_RTS		0x02
+
+/* input control lines*/
+#define CSVT_CTRL_CTS		0x01
+#define CSVT_CTRL_DSR		0x02
+#define CSVT_CTRL_RI		0x04
+#define CSVT_CTRL_CD		0x08
+
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+struct csvt_ctrl_dev {
+	struct mutex		dev_lock;
+
+	/* input control lines (DSR, CTS, CD, RI) */
+	unsigned int		cbits_tolocal;
+
+	/* output control lines (DTR, RTS) */
+	unsigned int		cbits_tomdm;
+};
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0x00, 0xff)},
+	{}, /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver csvt_driver = {
+	.name			= "qc_csvt",
+	.probe			= usb_serial_probe,
+	.disconnect		= usb_serial_disconnect,
+	.id_table		= id_table,
+	.suspend		= usb_serial_suspend,
+	.resume			= usb_serial_resume,
+	.supports_autosuspend	= true,
+};
+
+#define CSVT_IFC_NUM	4
+
+static int csvt_probe(struct usb_serial *serial, const struct usb_device_id *id)
+{
+	struct usb_host_interface	*intf =
+		serial->interface->cur_altsetting;
+
+	pr_debug("%s:\n", __func__);
+
+	if (intf->desc.bInterfaceNumber != CSVT_IFC_NUM)
+		return -ENODEV;
+
+	usb_enable_autosuspend(serial->dev);
+
+	return 0;
+}
+
+static int csvt_ctrl_write_cmd(struct csvt_ctrl_dev	*dev,
+	struct usb_serial_port *port)
+{
+	struct usb_device	*udev = port->serial->dev;
+	struct usb_interface	*iface = port->serial->interface;
+	unsigned int		iface_num;
+	int			retval = 0;
+
+	retval = usb_autopm_get_interface(iface);
+	if (retval < 0) {
+		dev_err(&port->dev, "%s: Unable to resume interface: %d\n",
+			__func__, retval);
+		return retval;
+	}
+
+	dev_dbg(&port->dev, "%s: cbits to mdm 0x%x\n", __func__,
+		dev->cbits_tomdm);
+
+	iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
+	retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+		USB_CDC_REQ_SET_CONTROL_LINE_STATE,
+		(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
+		dev->cbits_tomdm,
+		iface_num,
+		NULL, 0, USB_CTRL_SET_TIMEOUT);
+	usb_autopm_put_interface(iface);
+
+	return retval;
+}
+
+static void csvt_ctrl_dtr_rts(struct usb_serial_port *port, int on)
+{
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	if (!dev)
+		return;
+
+	dev_dbg(&port->dev, "%s", __func__);
+
+	mutex_lock(&dev->dev_lock);
+	if (on) {
+		dev->cbits_tomdm |= CSVT_CTRL_DTR;
+		dev->cbits_tomdm |= CSVT_CTRL_RTS;
+	} else {
+		dev->cbits_tomdm &= ~CSVT_CTRL_DTR;
+		dev->cbits_tomdm &= ~CSVT_CTRL_RTS;
+	}
+	mutex_unlock(&dev->dev_lock);
+
+	csvt_ctrl_write_cmd(dev, port);
+}
+
+static int get_serial_info(struct usb_serial_port *port,
+			   struct serial_struct __user *retinfo)
+{
+	struct serial_struct	tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.line            = port->serial->minor;
+	tmp.port            = port->number;
+	tmp.baud_base       = tty_get_baud_rate(port->port.tty);
+	tmp.close_delay	    = port->port.close_delay / 10;
+	tmp.closing_wait    =
+		port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+				 ASYNC_CLOSING_WAIT_NONE :
+				 port->port.closing_wait / 10;
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_serial_info(struct usb_serial_port *port,
+			   struct serial_struct __user *newinfo)
+{
+	struct serial_struct	new_serial;
+	unsigned int		closing_wait;
+	unsigned int		close_delay;
+	int			retval = 0;
+
+	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+		return -EFAULT;
+
+	close_delay = new_serial.close_delay * 10;
+	closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+			ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+	mutex_lock(&port->port.mutex);
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((close_delay != port->port.close_delay) ||
+		    (closing_wait != port->port.closing_wait))
+			retval = -EPERM;
+		else
+			retval = -EOPNOTSUPP;
+	} else {
+		port->port.close_delay  = close_delay;
+		port->port.closing_wait = closing_wait;
+	}
+
+	mutex_unlock(&port->port.mutex);
+	return retval;
+}
+
+static int csvt_ctrl_ioctl(struct tty_struct *tty, unsigned int cmd,
+	unsigned long arg)
+{
+	struct usb_serial_port	*port = tty->driver_data;
+
+	dev_dbg(&port->dev, "%s cmd 0x%04x", __func__, cmd);
+
+	switch (cmd) {
+	case TIOCGSERIAL:
+		return get_serial_info(port,
+				       (struct serial_struct __user *) arg);
+	case TIOCSSERIAL:
+		return set_serial_info(port,
+				       (struct serial_struct __user *) arg);
+	default:
+		break;
+	}
+
+	dev_err(&port->dev, "%s arg not supported", __func__);
+
+	return -ENOIOCTLCMD;
+}
+
+static int csvt_ctrl_tiocmget(struct tty_struct *tty)
+{
+	struct usb_serial_port	*port = tty->driver_data;
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+	unsigned int		control_state = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->dev_lock);
+	control_state = (dev->cbits_tomdm & CSVT_CTRL_DTR ? TIOCM_DTR : 0) |
+		(dev->cbits_tomdm & CSVT_CTRL_RTS ? TIOCM_RTS : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_DSR ? TIOCM_DSR : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_RI ? TIOCM_RI : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_CD ? TIOCM_CD : 0) |
+		(dev->cbits_tolocal & CSVT_CTRL_CTS ? TIOCM_CTS : 0);
+	mutex_unlock(&dev->dev_lock);
+
+	dev_dbg(&port->dev, "%s -- %x", __func__, control_state);
+
+	return control_state;
+}
+
+static int csvt_ctrl_tiocmset(struct tty_struct *tty,
+			       unsigned int set, unsigned int clear)
+{
+	struct usb_serial_port	*port = tty->driver_data;
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	if (!dev)
+		return -ENODEV;
+
+	dev_dbg(&port->dev, "%s\n", __func__);
+
+	mutex_lock(&dev->dev_lock);
+	if (set & CSVT_CTRL_DTR)
+		dev->cbits_tomdm |= TIOCM_DTR;
+	if (set & CSVT_CTRL_RTS)
+		dev->cbits_tomdm |= TIOCM_RTS;
+
+	if (clear & CSVT_CTRL_DTR)
+		dev->cbits_tomdm &= ~TIOCM_DTR;
+	if (clear & CSVT_CTRL_RTS)
+		dev->cbits_tomdm &= ~TIOCM_RTS;
+	mutex_unlock(&dev->dev_lock);
+
+	return csvt_ctrl_write_cmd(dev, port);
+}
+
+static void csvt_ctrl_set_termios(struct tty_struct *tty,
+			  struct usb_serial_port *port,
+			  struct ktermios *old_termios)
+{
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	if (!dev)
+		return;
+
+	dev_dbg(&port->dev, "%s", __func__);
+
+	/* Doesn't support option setting */
+	tty_termios_copy_hw(tty->termios, old_termios);
+
+	csvt_ctrl_write_cmd(dev, port);
+}
+
+static void csvt_ctrl_int_cb(struct urb *urb)
+{
+	int				status;
+	struct usb_cdc_notification	*ctrl;
+	struct usb_serial_port		*port = urb->context;
+	struct csvt_ctrl_dev		*dev;
+	unsigned int			ctrl_bits;
+	unsigned char			*data;
+
+	switch (urb->status) {
+	case 0:
+		/*success*/
+		break;
+	case -ESHUTDOWN:
+	case -ENOENT:
+	case -ECONNRESET:
+	case -EPROTO:
+		 /* unplug */
+		 return;
+	case -EPIPE:
+		dev_err(&port->dev, "%s: stall on int endpoint\n", __func__);
+		/* TBD : halt to be cleared in work */
+	case -EOVERFLOW:
+	default:
+		pr_debug_ratelimited("%s: non zero urb status = %d\n",
+					__func__, urb->status);
+		goto resubmit_int_urb;
+	}
+
+	dev = usb_get_serial_port_data(port);
+	if (!dev)
+		return;
+
+	ctrl = urb->transfer_buffer;
+	data = (unsigned char *)(ctrl + 1);
+
+	usb_serial_debug_data(debug, &port->dev, __func__,
+					urb->actual_length, data);
+
+	switch (ctrl->bNotificationType) {
+	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+		dev_dbg(&port->dev, "%s network\n", ctrl->wValue ?
+					"connected to" : "disconnected from");
+		break;
+	case USB_CDC_NOTIFY_SERIAL_STATE:
+		ctrl_bits = get_unaligned_le16(data);
+		dev_dbg(&port->dev, "serial state: %d\n", ctrl_bits);
+		dev->cbits_tolocal = ctrl_bits;
+		break;
+	default:
+		dev_err(&port->dev, "%s: unknown notification %d received:"
+			"index %d len %d data0 %d data1 %d",
+			__func__, ctrl->bNotificationType, ctrl->wIndex,
+			ctrl->wLength, data[0], data[1]);
+	}
+
+resubmit_int_urb:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status)
+		dev_err(&port->dev, "%s: Error re-submitting Int URB %d\n",
+		__func__, status);
+
+}
+
+static int csvt_ctrl_open(struct tty_struct *tty,
+					struct usb_serial_port *port)
+{
+	int	retval;
+
+	dev_dbg(&port->dev, "%s port %d", __func__, port->number);
+
+	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (retval) {
+		dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
+		return retval;
+	}
+
+	retval = usb_serial_generic_open(tty, port);
+	if (retval)
+		usb_kill_urb(port->interrupt_in_urb);
+
+	return retval;
+}
+
+static void csvt_ctrl_close(struct usb_serial_port *port)
+{
+	dev_dbg(&port->dev, "%s port %d", __func__, port->number);
+
+	usb_serial_generic_close(port);
+	usb_kill_urb(port->interrupt_in_urb);
+}
+
+static int csvt_ctrl_attach(struct usb_serial *serial)
+{
+	struct csvt_ctrl_dev	*dev;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	mutex_init(&dev->dev_lock);
+	usb_set_serial_port_data(serial->port[0], dev);
+
+	return 0;
+}
+
+static void csvt_ctrl_release(struct usb_serial *serial)
+{
+	struct usb_serial_port	*port = serial->port[0];
+	struct csvt_ctrl_dev	*dev = usb_get_serial_port_data(port);
+
+	dev_dbg(&port->dev, "%s", __func__);
+
+	kfree(dev);
+	usb_set_serial_port_data(port, NULL);
+}
+
+static struct usb_serial_driver csvt_device = {
+	.driver			= {
+		.owner	= THIS_MODULE,
+		.name	= "qc_csvt",
+	},
+	.description		= "qc_csvt",
+	.id_table		= id_table,
+	.usb_driver		= &csvt_driver,
+	.num_ports		= 1,
+	.open			= csvt_ctrl_open,
+	.close			= csvt_ctrl_close,
+	.probe			= csvt_probe,
+	.dtr_rts		= csvt_ctrl_dtr_rts,
+	.tiocmget		= csvt_ctrl_tiocmget,
+	.tiocmset		= csvt_ctrl_tiocmset,
+	.ioctl			= csvt_ctrl_ioctl,
+	.set_termios		= csvt_ctrl_set_termios,
+	.read_int_callback	= csvt_ctrl_int_cb,
+	.attach			= csvt_ctrl_attach,
+	.release		= csvt_ctrl_release,
+};
+
+static int __init csvt_init(void)
+{
+	int	retval;
+
+	retval = usb_serial_register(&csvt_device);
+	if (retval) {
+		err("%s: usb serial register failed\n", __func__);
+		return retval;
+	}
+
+	retval = usb_register(&csvt_driver);
+	if (retval) {
+		usb_serial_deregister(&csvt_device);
+		err("%s: usb register failed\n", __func__);
+		return retval;
+	}
+
+	return 0;
+}
+
+static void __exit csvt_exit(void)
+{
+	usb_deregister(&csvt_driver);
+	usb_serial_deregister(&csvt_device);
+}
+
+module_init(csvt_init);
+module_exit(csvt_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index b29a974..44e887c 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -1,7 +1,7 @@
 /*
  * Qualcomm Serial USB driver
  *
- *	Copyright (c) 2008 QUALCOMM Incorporated.
+ *	Copyright (c) 2008, 2012 QUALCOMM Incorporated.
  *	Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de>
  *	Copyright (c) 2009 Novell Inc.
  *
@@ -82,7 +82,8 @@
 	{USB_DEVICE(0x16d8, 0x8002)},	/* CMDTech Gobi 2000 Modem device (VU922) */
 	{USB_DEVICE(0x05c6, 0x9204)},	/* Gobi 2000 QDL device */
 	{USB_DEVICE(0x05c6, 0x9205)},	/* Gobi 2000 Modem device */
-	{USB_DEVICE(0x05c6, 0x9048)},
+	{USB_DEVICE(0x05c6, 0x9048)},	/* MDM9x15 device */
+	{USB_DEVICE(0x05c6, 0x904C)},	/* MDM9x15 device */
 	{ }				/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index d8987e2..de91ade 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -145,6 +145,315 @@
 
 static uint32 mdp_prim_panel_type = NO_PANEL;
 #ifndef CONFIG_FB_MSM_MDP22
+
+struct list_head mdp_hist_lut_list;
+DEFINE_MUTEX(mdp_hist_lut_list_mutex);
+
+uint32_t mdp_block2base(uint32_t block)
+{
+	uint32_t base = 0x0;
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+		base = 0x90000;
+		break;
+	case MDP_BLOCK_DMA_S:
+		base = 0xA0000;
+		break;
+	case MDP_BLOCK_VG_1:
+		base = 0x20000;
+		break;
+	case MDP_BLOCK_VG_2:
+		base = 0x30000;
+		break;
+	case MDP_BLOCK_RGB_1:
+		base = 0x40000;
+		break;
+	case MDP_BLOCK_RGB_2:
+		base = 0x50000;
+		break;
+	default:
+		break;
+	}
+	return base;
+}
+
+static uint32_t mdp_pp_block2hist_lut(uint32_t block)
+{
+	uint32_t valid = 0;
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_DMA_S:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_VG_1:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_VG_2:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	default:
+		break;
+	}
+	return valid;
+}
+
+static void mdp_hist_lut_init_mgmt(struct mdp_hist_lut_mgmt *mgmt,
+		uint32_t block)
+{
+	mutex_init(&mgmt->lock);
+	mgmt->block = block;
+
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_add(&mgmt->list, &mdp_hist_lut_list);
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+}
+
+static int mdp_hist_lut_init(void)
+{
+	struct mdp_hist_lut_mgmt *temp;
+	struct list_head *pos, *q;
+	INIT_LIST_HEAD(&mdp_hist_lut_list);
+
+	if (mdp_rev >= MDP_REV_30) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_P);
+	}
+
+	if (mdp_rev >= MDP_REV_40) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_1);
+
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_2);
+	}
+
+	if (mdp_rev > MDP_REV_42) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_S);
+	}
+	return 0;
+
+exit_list:
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_for_each_safe(pos, q, &mdp_hist_lut_list) {
+		temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
+		list_del(pos);
+		kfree(temp);
+	}
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+exit:
+	pr_err("Failed initializing histogram LUT memory\n");
+	return -ENOMEM;
+}
+
+static int mdp_hist_lut_block2mgmt(uint32_t block,
+		struct mdp_hist_lut_mgmt **mgmt)
+{
+	struct mdp_hist_lut_mgmt *temp, *output;
+	int ret = 0;
+
+	output = NULL;
+
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_for_each_entry(temp, &mdp_hist_lut_list, list) {
+		if (temp->block == block)
+			output = temp;
+	}
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+
+	if (output == NULL)
+		ret = -EINVAL;
+	else
+		*mgmt = output;
+
+	return ret;
+}
+
+#define MDP_HIST_LUT_SIZE (256)
+static int mdp_hist_lut_write_off(struct mdp_hist_lut_data *data,
+		struct mdp_hist_lut_info *info, uint32_t offset)
+{
+	int i;
+	uint32_t element[MDP_HIST_LUT_SIZE];
+	uint32_t base = mdp_block2base(info->block);
+	uint32_t sel = info->bank_sel;
+
+
+	if (data->len != MDP_HIST_LUT_SIZE) {
+		pr_err("%s: data->len != %d", __func__, MDP_HIST_LUT_SIZE);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&element, data->data,
+				MDP_HIST_LUT_SIZE * sizeof(uint32_t))) {
+		pr_err("%s: Error copying histogram data", __func__);
+		return -ENOMEM;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < MDP_HIST_LUT_SIZE; i++)
+		MDP_OUTP(MDP_BASE + base + offset + (0x400*(sel)) + (4*i),
+				element[i]);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return 0;
+}
+
+static int mdp_hist_lut_write(struct mdp_hist_lut_data *data,
+						struct mdp_hist_lut_info *info)
+{
+	int ret = 0;
+
+	if (data->block != info->block) {
+		ret = -1;
+		pr_err("%s, data/info mdp_block mismatch! %d != %d\n",
+				__func__, data->block, info->block);
+		goto error;
+	}
+
+	switch (data->block) {
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+		ret = mdp_hist_lut_write_off(data, info, 0x3400);
+		break;
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		ret = mdp_hist_lut_write_off(data, info, 0x4800);
+		break;
+	default:
+		ret = -EINVAL;
+		goto error;
+	}
+
+error:
+	return ret;
+}
+
+#define MDP_HIST_LUT_VG_EN_MASK (0x20000)
+#define MDP_HIST_LUT_VG_EN_SHIFT (17)
+#define MDP_HIST_LUT_VG_EN_OFFSET (0x0058)
+#define MDP_HIST_LUT_VG_SEL_OFFSET (0x0064)
+static void mdp_hist_lut_commit_vg(struct mdp_hist_lut_info *info)
+{
+	uint32_t out_en, temp_en;
+	uint32_t base = mdp_block2base(info->block);
+	temp_en = (info->is_enabled) ? (1 << MDP_HIST_LUT_VG_EN_SHIFT) : 0x0;
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	out_en = inpdw(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET) &
+						~MDP_HIST_LUT_VG_EN_MASK;
+	MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET, out_en | temp_en);
+
+	if (info->has_sel_update)
+		MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_SEL_OFFSET,
+								info->bank_sel);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+#define MDP_HIST_LUT_DMA_EN_MASK (0x7)
+#define MDP_HIST_LUT_DMA_SEL_MASK (0x400)
+#define MDP_HIST_LUT_DMA_SEL_SHIFT (10)
+#define MDP_HIST_LUT_DMA_P_OFFSET (0x0070)
+#define MDP_HIST_LUT_DMA_S_OFFSET (0x0028)
+static void mdp_hist_lut_commit_dma(struct mdp_hist_lut_info *info)
+{
+	uint32_t out, temp, mask;
+	uint32_t base = mdp_block2base(info->block);
+	uint32_t offset = (info->block == MDP_BLOCK_DMA_P) ?
+		MDP_HIST_LUT_DMA_P_OFFSET : MDP_HIST_LUT_DMA_S_OFFSET;
+
+	mask = MDP_HIST_LUT_DMA_EN_MASK;
+	temp = (info->is_enabled) ? 0x7 : 0x0;
+
+	if (info->has_sel_update) {
+		mask |= MDP_HIST_LUT_DMA_SEL_MASK;
+		temp |=  ((info->bank_sel & 0x1) << MDP_HIST_LUT_DMA_SEL_SHIFT);
+	}
+
+	out = inpdw(MDP_BASE + base + offset) & ~mask;
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	MDP_OUTP(MDP_BASE + base + offset, out | temp);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+static void mdp_hist_lut_commit_info(struct mdp_hist_lut_info *info)
+{
+	switch (info->block) {
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+		mdp_hist_lut_commit_vg(info);
+		break;
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		mdp_hist_lut_commit_dma(info);
+		break;
+	default:
+		goto error;
+	}
+
+error:
+	return;
+}
+
+static void mdp_hist_lut_update_info(struct mdp_hist_lut_info *info, int ops)
+{
+	info->bank_sel = (ops & 0x8) >> 3;
+	info->is_enabled = (ops & 0x1) ? TRUE : FALSE;
+	info->has_sel_update = (ops & 0x10) ? TRUE : FALSE;
+}
+
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data)
+{
+	struct mdp_hist_lut_mgmt *mgmt = NULL;
+	struct mdp_hist_lut_info info;
+	int ret = 0;
+
+	if (!mdp_pp_block2hist_lut(data->block)) {
+		ret = -ENOTTY;
+		goto error;
+	}
+
+	ret = mdp_hist_lut_block2mgmt(data->block, &mgmt);
+	if (ret)
+		goto error;
+
+	mutex_lock(&mgmt->lock);
+
+	info.block = mgmt->block;
+
+	mdp_hist_lut_update_info(&info, data->ops);
+
+	switch ((data->ops & 0x6) >> 1) {
+	case 0x1:
+		pr_info("%s: histogram LUT read not supported\n", __func__);
+		break;
+	case 0x2:
+		ret = mdp_hist_lut_write(data, &info);
+		if (ret)
+			goto error_lock;
+		break;
+	default:
+		break;
+	}
+
+	mdp_hist_lut_commit_info(&info);
+
+error_lock:
+	mutex_unlock(&mgmt->lock);
+error:
+	return ret;
+}
+
+
 DEFINE_MUTEX(mdp_lut_push_sem);
 static int mdp_lut_i;
 static int mdp_lut_hw_update(struct fb_cmap *cmap)
@@ -1535,6 +1844,9 @@
 	mfd->ov0_blt_state  = 0;
 	mfd->use_ov0_blt = 0 ;
 
+    /* initialize Post Processing data*/
+	mdp_hist_lut_init();
+
 	/* add panel data */
 	if (platform_device_add_data
 	    (msm_fb_dev, pdev->dev.platform_data,
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 3d3668e..6c5a9f9 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -225,6 +225,20 @@
 	struct completion dmap_comp;
 };
 
+extern struct list_head mdp_hist_lut_list;
+extern struct mutex mdp_hist_lut_list_mutex;
+struct mdp_hist_lut_mgmt {
+	uint32_t block;
+	struct mutex lock;
+	struct list_head list;
+};
+
+struct mdp_hist_lut_info {
+	uint32_t block;
+	boolean is_enabled, has_sel_update;
+	int bank_sel;
+};
+
 #define MDP_CMD_DEBUG_ACCESS_BASE   (MDP_BASE+0x10000)
 
 #define MDP_DMA2_TERM 0x1
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 77e8cd1..f7f48e4 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -707,6 +707,9 @@
 int mdp4_writeback_init(struct fb_info *info);
 int mdp4_writeback_terminate(struct fb_info *info);
 
+uint32_t mdp_block2base(uint32_t block);
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data);
+
 void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl);
 void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe);
 int mdp4_csc_config(struct mdp_csc_cfg_data *config);
@@ -719,4 +722,5 @@
 void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
 #endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index a9efc1c..c020755 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -277,6 +277,7 @@
 void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc)
 {
 	uint32	dma2_cfg_reg;
+	uint32 mask, curr;
 
 	dma2_cfg_reg = DMA_DITHER_EN;
 #ifdef BLT_RGB565
@@ -309,6 +310,9 @@
 #endif
 
 	/* dma2 config register */
+	curr = inpdw(MDP_BASE + 0x90000);
+	mask = 0xBFFFFFFF;
+	dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
 	MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -442,6 +446,7 @@
 	char *rgb_base;
 	uint32 src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern;
+	uint32 curr, mask;
 	uint32 offset = 0;
 	int pnum;
 
@@ -473,6 +478,12 @@
 
 	mdp4_scale_setup(pipe);
 
+	/* Ensure proper covert matrix loaded when color space swaps */
+	curr = inpdw(rgb_base + 0x0058);
+	/* Don't touch bits you don't want to configure*/
+	mask = 0xFFFEFFFF;
+	pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	outpdw(rgb_base + 0x0000, src_size);	/* MDP_RGB_SRC_SIZE */
@@ -558,7 +569,7 @@
 	char *vg_base;
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
-	uint32 mask, curr;
+	uint32 mask, curr, addr;
 	int pnum, ptype;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -625,13 +636,20 @@
 	/* Ensure proper covert matrix loaded when color space swaps */
 	curr = inpdw(vg_base + 0x0058);
 	mask = 0x600;
+
 	if ((curr & mask) != (pipe->op_mode & mask)) {
-		curr = ((uint32_t)vg_base) + 0x4000;
+		addr = ((uint32_t)vg_base) + 0x4000;
 		if (ptype != OVERLAY_TYPE_RGB)
-			mdp4_csc_write(&(mdp_csc_convert[1]), curr);
+			mdp4_csc_write(&(mdp_csc_convert[1]), addr);
 		else
-			mdp4_csc_write(&(mdp_csc_convert[0]), curr);
+			mdp4_csc_write(&(mdp_csc_convert[0]), addr);
+
+		mask = 0xFFFCFFFF;
+	} else {
+		/* Don't touch bits you don't want to configure*/
+		mask = 0xFFFCF1FF;
 	}
+	pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
 
 	/* luma component plane */
 	outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset);
@@ -2315,8 +2333,7 @@
 #endif
 	}
 
-	if (mfd->mdp_rev >= MDP_REV_42 && !mfd->use_ov0_blt &&
-	    !(ctrl->panel_mode & (MDP4_PANEL_MDDI | MDP4_PANEL_DSI_CMD))) {
+	if (mfd->mdp_rev >= MDP_REV_42 && !mfd->use_ov0_blt) {
 		ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
 	} else {
 		mdp4_mixer_stage_down(pipe);
@@ -2326,6 +2343,11 @@
 			if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
 				if (mfd->panel_power_on)
 					mdp4_dsi_cmd_overlay_restore();
+			} else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+				pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+				if (mfd->panel_power_on)
+					mdp4_overlay_dsi_video_vsync_push(mfd,
+									  pipe);
 			}
 #else
 			if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
@@ -2336,6 +2358,11 @@
 					mdp4_mddi_overlay_restore();
 			}
 #endif
+			else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+				pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+				if (mfd->panel_power_on)
+					mdp4_overlay_lcdc_vsync_push(mfd, pipe);
+			}
 			mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
 			mdp4_overlay_update_blt_mode(mfd);
 			if (!mfd->use_ov0_blt)
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 590ad65..635b104 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -369,6 +369,9 @@
 {
 	int result = 0;
 
+	pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+	mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+
 	if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE &&
 			pipe->pipe_type == OVERLAY_TYPE_RGB) {
 		result = mdp4_dtv_stop(mfd);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index d8a55ed..b69a2fc 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2989,3 +2989,144 @@
 	return ret;
 }
 
+static uint32_t mdp4_pp_block2igc(uint32_t block)
+{
+	uint32_t valid = 0;
+	switch (block) {
+	case MDP_BLOCK_VG_1:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_VG_2:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_RGB_1:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_RGB_2:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_DMA_P:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_DMA_S:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	default:
+		break;
+	}
+	return valid;
+}
+
+static int mdp4_igc_lut_write(struct mdp_igc_lut_data *cfg, uint32_t en_off,
+		uint32_t lut_off)
+{
+	int i;
+	uint32_t base, *off_low, *off_high;
+	uint32_t low[cfg->len];
+	uint32_t high[cfg->len];
+
+	base = mdp_block2base(cfg->block);
+
+	if (cfg->len != 256)
+		return -EINVAL;
+
+	off_low = (uint32_t *)(MDP_BASE + base + lut_off);
+	off_high = (uint32_t *)(MDP_BASE + base + lut_off + 0x800);
+	if (copy_from_user(&low, cfg->c0_c1_data, cfg->len * sizeof(uint32_t)))
+		return -EFAULT;
+	if (copy_from_user(&high, cfg->c2_data, cfg->len * sizeof(uint32_t)))
+		return -EFAULT;
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < cfg->len; i++) {
+		MDP_OUTP(off_low++, low[i]);
+		/*low address write should occur before high address write*/
+		wmb();
+		MDP_OUTP(off_high++, high[i]);
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	return 0;
+}
+
+static int mdp4_igc_lut_ctrl(struct mdp_igc_lut_data *cfg)
+{
+	uint32_t mask, out;
+	uint32_t base = mdp_block2base(cfg->block);
+	int8_t shift = 0;
+
+	switch (cfg->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		base = base;
+		shift = 30;
+		break;
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+	case MDP_BLOCK_RGB_1:
+	case MDP_BLOCK_RGB_2:
+		base += 0x58;
+		shift = 16;
+		break;
+	default:
+		return -EINVAL;
+
+	}
+	out = 1<<shift;
+	mask = ~out;
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	out = inpdw(MDP_BASE + base) & mask;
+	MDP_OUTP(MDP_BASE + base, out | ((cfg->ops & 0x1)<<shift));
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return 0;
+}
+
+static int mdp4_igc_lut_write_cfg(struct mdp_igc_lut_data *cfg)
+{
+	int ret = 0;
+
+	switch (cfg->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		ret = mdp4_igc_lut_write(cfg, 0x00, 0x9000);
+		break;
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+	case MDP_BLOCK_RGB_1:
+	case MDP_BLOCK_RGB_2:
+		ret = mdp4_igc_lut_write(cfg, 0x58, 0x5000);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg)
+{
+	int ret = 0;
+
+	if (!mdp4_pp_block2igc(cfg->block)) {
+		ret = -ENOTTY;
+		goto error;
+	}
+
+	switch ((cfg->ops & 0x6) >> 1) {
+	case 0x1:
+		pr_info("%s: IGC LUT read not supported\n", __func__);
+		break;
+	case 0x2:
+		ret = mdp4_igc_lut_write_cfg(cfg);
+		if (ret)
+			goto error;
+		break;
+	default:
+		break;
+	}
+
+	ret = mdp4_igc_lut_ctrl(cfg);
+
+error:
+	return ret;
+}
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 0e76a07..3c89d8b 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -75,6 +75,7 @@
 	struct msm_fb_data_type *mfd;
 	struct msm_panel_info *panel_info;
 	int ret;
+	uint32 mask, curr;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	panel_info = &mfd->panel_info;
@@ -163,6 +164,9 @@
 	MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x10, 0);
 
 	/* dma config */
+	curr = inpdw(MDP_BASE + 0x90000);
+	mask = 0xBFFFFFFF;
+	dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
 	MDP_OUTP(MDP_BASE + DMA_P_BASE, dma2_cfg_reg);
 
 	/*
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 69e0423..593f10b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -2952,6 +2952,9 @@
 	case mdp_op_lut_cfg:
 		switch (pp_ptr->data.lut_cfg_data.lut_type) {
 		case mdp_lut_igc:
+			ret = mdp4_igc_lut_config(
+					(struct mdp_igc_lut_data *)
+					&pp_ptr->data.lut_cfg_data.data);
 			break;
 
 		case mdp_lut_pgc:
@@ -2960,6 +2963,9 @@
 			break;
 
 		case mdp_lut_hist:
+			ret = mdp_hist_lut_config(
+					(struct mdp_hist_lut_data *)
+					&pp_ptr->data.lut_cfg_data.data);
 			break;
 
 		default:
diff --git a/include/linux/mfd/Kbuild b/include/linux/mfd/Kbuild
index 1acc78f..bba647c 100644
--- a/include/linux/mfd/Kbuild
+++ b/include/linux/mfd/Kbuild
@@ -1,3 +1,3 @@
 header-y += timpani-audio.h
 header-y += msm-adie-codec.h
-header-y += wcd9310/
+header-y += wcd9xxx/
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 82db9a4..e2d4d93 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.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
@@ -95,8 +95,15 @@
 	unsigned int	batt_id_channel;
 };
 
+enum battery_type {
+	BATT_UNKNOWN = 0,
+	BATT_PALLADIUM,
+	BATT_DESAY,
+};
+
 /**
  * struct pm8921_bms_platform_data -
+ * @batt_type:		allows to force chose battery calibration data
  * @r_sense:		sense resistor value in (mOhms)
  * @i_test:		current at which the unusable charger cutoff is to be
  *			calculated or the peak system current (mA)
@@ -105,6 +112,7 @@
  */
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
+	enum battery_type		battery_type;
 	unsigned int			r_sense;
 	unsigned int			i_test;
 	unsigned int			v_failure;
@@ -114,6 +122,7 @@
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
 extern struct pm8921_bms_battery_data  palladium_1500_data;
+extern struct pm8921_bms_battery_data  desay_5200_data;
 /**
  * pm8921_bms_get_vsense_avg - return the voltage across the sense
  *				resitor in microvolts
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 22293fe..bdaee74 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -142,6 +142,7 @@
 	struct pm8xxx_led_platform_data		*leds_pdata;
 	struct pm8xxx_vibrator_platform_data	*vibrator_pdata;
 	struct pm8xxx_ccadc_platform_data	*ccadc_pdata;
+	struct pm8xxx_pwm_platform_data		*pwm_pdata;
 };
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/pwm.h b/include/linux/mfd/pm8xxx/pwm.h
index 9169e90..09b165e 100644
--- a/include/linux/mfd/pm8xxx/pwm.h
+++ b/include/linux/mfd/pm8xxx/pwm.h
@@ -19,7 +19,6 @@
 
 #define PM8XXX_PWM_PERIOD_MIN	7 /* usec: 19.2M, n=6, m=0, pre=2 */
 #define PM8XXX_PWM_PERIOD_MAX	(384 * USEC_PER_SEC) /* 1K, n=9, m=7, pre=6 */
-
 #define PM_PWM_LUT_SIZE			64
 #define PM_PWM_LUT_DUTY_TIME_MAX	512	/* ms */
 #define PM_PWM_LUT_PAUSE_MAX		(7000 * PM_PWM_LUT_DUTY_TIME_MAX)
@@ -92,6 +91,14 @@
 };
 
 /**
+ * struct pm8xxx_pwm_platform_data - PWM platform data
+ * dtest_channel - Enable LPG DTEST mode for this LPG channel
+ */
+struct pm8xxx_pwm_platform_data {
+	int dtest_channel;
+};
+
+/**
  * pm8xxx_pwm_config_period - change PWM period
  *
  * @pwm: the PWM device
diff --git a/include/linux/mfd/wcd9310/Kbuild b/include/linux/mfd/wcd9310/Kbuild
deleted file mode 100644
index 2702ec6..0000000
--- a/include/linux/mfd/wcd9310/Kbuild
+++ /dev/null
@@ -1 +0,0 @@
-header-y += registers.h
diff --git a/include/linux/mfd/wcd9310/core.h b/include/linux/mfd/wcd9310/core.h
deleted file mode 100644
index 8605ac6..0000000
--- a/include/linux/mfd/wcd9310/core.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* 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
- * 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 __MFD_TABLA_CORE_H__
-#define __MFD_TABLA_CORE_H__
-
-#include <linux/interrupt.h>
-#include <linux/wakelock.h>
-
-#define TABLA_NUM_IRQ_REGS 3
-
-#define TABLA_SLIM_NUM_PORT_REG 3
-
-#define TABLA_INTERFACE_TYPE_SLIMBUS	0x00
-#define TABLA_INTERFACE_TYPE_I2C	0x01
-
-#define TABLA_VERSION_1_0	0
-#define TABLA_VERSION_1_1	1
-#define TABLA_VERSION_2_0	2
-#define TABLA_IS_1_X(ver) \
-	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
-#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
-
-enum {
-	TABLA_IRQ_SLIMBUS = 0,
-	TABLA_IRQ_MBHC_REMOVAL,
-	TABLA_IRQ_MBHC_SHORT_TERM,
-	TABLA_IRQ_MBHC_PRESS,
-	TABLA_IRQ_MBHC_RELEASE,
-	TABLA_IRQ_MBHC_POTENTIAL,
-	TABLA_IRQ_MBHC_INSERTION,
-	TABLA_IRQ_BG_PRECHARGE,
-	TABLA_IRQ_PA1_STARTUP,
-	TABLA_IRQ_PA2_STARTUP,
-	TABLA_IRQ_PA3_STARTUP,
-	TABLA_IRQ_PA4_STARTUP,
-	TABLA_IRQ_PA5_STARTUP,
-	TABLA_IRQ_MICBIAS1_PRECHARGE,
-	TABLA_IRQ_MICBIAS2_PRECHARGE,
-	TABLA_IRQ_MICBIAS3_PRECHARGE,
-	TABLA_IRQ_HPH_PA_OCPL_FAULT,
-	TABLA_IRQ_HPH_PA_OCPR_FAULT,
-	TABLA_IRQ_EAR_PA_OCPL_FAULT,
-	TABLA_IRQ_HPH_L_PA_STARTUP,
-	TABLA_IRQ_HPH_R_PA_STARTUP,
-	TABLA_IRQ_EAR_PA_STARTUP,
-	TABLA_NUM_IRQS,
-};
-
-enum tabla_pm_state {
-	TABLA_PM_SLEEPABLE,
-	TABLA_PM_AWAKE,
-	TABLA_PM_ASLEEP,
-};
-
-struct tabla {
-	struct device *dev;
-	struct slim_device *slim;
-	struct slim_device *slim_slave;
-	struct mutex io_lock;
-	struct mutex xfer_lock;
-	struct mutex irq_lock;
-	u8 version;
-
-	unsigned int irq_base;
-	unsigned int irq;
-	u8 irq_masks_cur[TABLA_NUM_IRQ_REGS];
-	u8 irq_masks_cache[TABLA_NUM_IRQ_REGS];
-	u8 irq_level[TABLA_NUM_IRQ_REGS];
-
-	int reset_gpio;
-
-	int (*read_dev)(struct tabla *tabla, unsigned short reg,
-			int bytes, void *dest, bool interface_reg);
-	int (*write_dev)(struct tabla *tabla, unsigned short reg,
-			 int bytes, void *src, bool interface_reg);
-
-	struct regulator_bulk_data *supplies;
-
-	enum tabla_pm_state pm_state;
-	struct mutex pm_lock;
-	/* pm_wq notifies change of pm_state */
-	wait_queue_head_t pm_wq;
-	struct wake_lock wlock;
-	int wlock_holders;
-};
-
-int tabla_reg_read(struct tabla *tabla, unsigned short reg);
-int tabla_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
-int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg);
-int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
-int tabla_bulk_read(struct tabla *tabla, unsigned short reg, int count,
-		    u8 *buf);
-int tabla_bulk_write(struct tabla *tabla, unsigned short reg, int count,
-		     u8 *buf);
-int tabla_irq_init(struct tabla *tabla);
-void tabla_irq_exit(struct tabla *tabla);
-int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-int tabla_get_intf_type(void);
-
-void tabla_lock_sleep(struct tabla *tabla);
-void tabla_unlock_sleep(struct tabla *tabla);
-enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
-				     enum tabla_pm_state n);
-
-static inline int tabla_request_irq(struct tabla *tabla, int irq,
-				     irq_handler_t handler, const char *name,
-				     void *data)
-{
-	if (!tabla->irq_base)
-		return -EINVAL;
-	return request_threaded_irq(tabla->irq_base + irq, NULL, handler,
-				    IRQF_TRIGGER_RISING, name,
-				    data);
-}
-static inline void tabla_free_irq(struct tabla *tabla, int irq, void *data)
-{
-	if (!tabla->irq_base)
-		return;
-	free_irq(tabla->irq_base + irq, data);
-}
-static inline void tabla_enable_irq(struct tabla *tabla, int irq)
-{
-	if (!tabla->irq_base)
-		return;
-	enable_irq(tabla->irq_base + irq);
-}
-static inline void tabla_disable_irq(struct tabla *tabla, int irq)
-{
-	if (!tabla->irq_base)
-		return;
-	disable_irq_nosync(tabla->irq_base + irq);
-}
-
-#endif
diff --git a/include/linux/mfd/wcd9xxx/Kbuild b/include/linux/mfd/wcd9xxx/Kbuild
new file mode 100644
index 0000000..acfab6e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/Kbuild
@@ -0,0 +1,2 @@
+header-y += wcd9xxx_registers.h
+header-y += wcd9310_registers.h
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
new file mode 100644
index 0000000..0d99e37
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -0,0 +1,177 @@
+/* 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
+ * 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 __MFD_TABLA_CORE_H__
+#define __MFD_TABLA_CORE_H__
+
+#include <linux/interrupt.h>
+#include <linux/wakelock.h>
+
+#define WCD9XXX_NUM_IRQ_REGS 3
+
+#define WCD9XXX_SLIM_NUM_PORT_REG 3
+
+#define WCD9XXX_INTERFACE_TYPE_SLIMBUS	0x00
+#define WCD9XXX_INTERFACE_TYPE_I2C	0x01
+
+#define TABLA_VERSION_1_0	0
+#define TABLA_VERSION_1_1	1
+#define TABLA_VERSION_2_0	2
+#define TABLA_IS_1_X(ver) \
+	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
+#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
+
+enum {
+	TABLA_IRQ_SLIMBUS = 0,
+	TABLA_IRQ_MBHC_REMOVAL,
+	TABLA_IRQ_MBHC_SHORT_TERM,
+	TABLA_IRQ_MBHC_PRESS,
+	TABLA_IRQ_MBHC_RELEASE,
+	TABLA_IRQ_MBHC_POTENTIAL,
+	TABLA_IRQ_MBHC_INSERTION,
+	TABLA_IRQ_BG_PRECHARGE,
+	TABLA_IRQ_PA1_STARTUP,
+	TABLA_IRQ_PA2_STARTUP,
+	TABLA_IRQ_PA3_STARTUP,
+	TABLA_IRQ_PA4_STARTUP,
+	TABLA_IRQ_PA5_STARTUP,
+	TABLA_IRQ_MICBIAS1_PRECHARGE,
+	TABLA_IRQ_MICBIAS2_PRECHARGE,
+	TABLA_IRQ_MICBIAS3_PRECHARGE,
+	TABLA_IRQ_HPH_PA_OCPL_FAULT,
+	TABLA_IRQ_HPH_PA_OCPR_FAULT,
+	TABLA_IRQ_EAR_PA_OCPL_FAULT,
+	TABLA_IRQ_HPH_L_PA_STARTUP,
+	TABLA_IRQ_HPH_R_PA_STARTUP,
+	TABLA_IRQ_EAR_PA_STARTUP,
+	TABLA_NUM_IRQS,
+};
+
+enum {
+	SITAR_IRQ_SLIMBUS = 0,
+	SITAR_IRQ_MBHC_REMOVAL,
+	SITAR_IRQ_MBHC_SHORT_TERM,
+	SITAR_IRQ_MBHC_PRESS,
+	SITAR_IRQ_MBHC_RELEASE,
+	SITAR_IRQ_MBHC_POTENTIAL,
+	SITAR_IRQ_MBHC_INSERTION,
+	SITAR_IRQ_BG_PRECHARGE,
+	SITAR_IRQ_PA1_STARTUP,
+	SITAR_IRQ_PA2_STARTUP,
+	SITAR_IRQ_PA3_STARTUP,
+	SITAR_IRQ_PA4_STARTUP,
+	SITAR_IRQ_PA5_STARTUP,
+	SITAR_IRQ_MICBIAS1_PRECHARGE,
+	SITAR_IRQ_MICBIAS2_PRECHARGE,
+	SITAR_IRQ_MICBIAS3_PRECHARGE,
+	SITAR_IRQ_HPH_PA_OCPL_FAULT,
+	SITAR_IRQ_HPH_PA_OCPR_FAULT,
+	SITAR_IRQ_EAR_PA_OCPL_FAULT,
+	SITAR_IRQ_HPH_L_PA_STARTUP,
+	SITAR_IRQ_HPH_R_PA_STARTUP,
+	SITAR_IRQ_EAR_PA_STARTUP,
+	SITAR_NUM_IRQS,
+};
+
+
+enum wcd9xxx_pm_state {
+	WCD9XXX_PM_SLEEPABLE,
+	WCD9XXX_PM_AWAKE,
+	WCD9XXX_PM_ASLEEP,
+};
+
+struct wcd9xxx {
+	struct device *dev;
+	struct slim_device *slim;
+	struct slim_device *slim_slave;
+	struct mutex io_lock;
+	struct mutex xfer_lock;
+	struct mutex irq_lock;
+	u8 version;
+
+	unsigned int irq_base;
+	unsigned int irq;
+	u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
+	u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
+	u8 irq_level[WCD9XXX_NUM_IRQ_REGS];
+
+	int reset_gpio;
+
+	int (*read_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *dest, bool interface_reg);
+	int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			 int bytes, void *src, bool interface_reg);
+
+	struct regulator_bulk_data *supplies;
+
+	enum wcd9xxx_pm_state pm_state;
+	struct mutex pm_lock;
+	/* pm_wq notifies change of pm_state */
+	wait_queue_head_t pm_wq;
+	struct wake_lock wlock;
+	int wlock_holders;
+	int num_rx_port;
+	int num_tx_port;
+};
+
+int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
+int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		u8 val);
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		u8 val);
+int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int count, u8 *buf);
+int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int count, u8 *buf);
+int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
+int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
+int wcd9xxx_get_intf_type(void);
+
+void wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
+				enum wcd9xxx_pm_state o,
+				enum wcd9xxx_pm_state n);
+
+static inline int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
+				     irq_handler_t handler, const char *name,
+				     void *data)
+{
+	if (!wcd9xxx->irq_base)
+		return -EINVAL;
+	return request_threaded_irq(wcd9xxx->irq_base + irq, NULL, handler,
+				    IRQF_TRIGGER_RISING, name,
+				    data);
+}
+static inline void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx,
+				int irq, void *data)
+{
+	if (!wcd9xxx->irq_base)
+		return;
+	free_irq(wcd9xxx->irq_base + irq, data);
+}
+static inline void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+	if (!wcd9xxx->irq_base)
+		return;
+	enable_irq(wcd9xxx->irq_base + irq);
+}
+static inline void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+	if (!wcd9xxx->irq_base)
+		return;
+	disable_irq_nosync(wcd9xxx->irq_base + irq);
+}
+
+#endif
diff --git a/include/linux/mfd/wcd9310/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
similarity index 71%
rename from include/linux/mfd/wcd9310/pdata.h
rename to include/linux/mfd/wcd9xxx/pdata.h
index af801f0..db76294 100644
--- a/include/linux/mfd/wcd9310/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.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
@@ -16,6 +16,15 @@
 
 #include <linux/slimbus/slimbus.h>
 
+#define SITAR_LDOH_1P95_V 0x0
+#define SITAR_LDOH_2P35_V 0x1
+#define SITAR_LDOH_2P75_V 0x2
+#define SITAR_LDOH_2P85_V 0x3
+
+#define SITAR_CFILT1_SEL 0x0
+#define SITAR_CFILT2_SEL 0x1
+#define SITAR_CFILT3_SEL 0x2
+
 #define TABLA_LDOH_1P95_V 0x0
 #define TABLA_LDOH_2P35_V 0x1
 #define TABLA_LDOH_2P75_V 0x2
@@ -51,7 +60,7 @@
 #define TABLA_DCYCLE_3839 0xE
 #define TABLA_DCYCLE_4095 0xF
 
-struct tabla_amic {
+struct wcd9xxx_amic {
 	/*legacy mode, txfe_enable and txfe_buff take 7 input
 	 * each bit represent the channel / TXFE number
 	 * and numbered as below
@@ -75,7 +84,7 @@
  * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
  */
 
-struct tabla_micbias_setting {
+struct wcd9xxx_micbias_setting {
 	u8 ldoh_v;
 	u32 cfilt1_mv; /* in mv */
 	u32 cfilt2_mv; /* in mv */
@@ -86,7 +95,7 @@
 	u8 bias4_cfilt_sel;
 };
 
-struct tabla_ocp_setting {
+struct wcd9xxx_ocp_setting {
 	unsigned int	use_pdata:1; /* 0 - use sys default as recommended */
 	unsigned int	num_attempts:4; /* up to 15 attempts */
 	unsigned int	run_time:4; /* in duty cycle */
@@ -94,15 +103,39 @@
 	unsigned int	hph_ocp_limit:3; /* Headphone OCP current limit */
 };
 
-struct tabla_pdata {
+#define MAX_REGULATOR	6
+/*
+ *      format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
+ *
+ *      <POWER_SUPPLY_PIN_NAME> from Tabla objective spec
+*/
+
+#define  WCD9XXX_CDC_VDDA_CP_CUR_MAX      500000
+#define  WCD9XXX_CDC_VDDA_RX_CUR_MAX      20000
+#define  WCD9XXX_CDC_VDDA_TX_CUR_MAX      20000
+#define  WCD9XXX_VDDIO_CDC_CUR_MAX        5000
+
+#define  WCD9XXX_VDDD_CDC_D_CUR_MAX       5000
+#define  WCD9XXX_VDDD_CDC_A_CUR_MAX       5000
+
+struct wcd9xxx_regulator {
+	const char *name;
+	int min_uV;
+	int max_uV;
+	int optimum_uA;
+	struct regulator *regulator;
+};
+
+struct wcd9xxx_pdata {
 	int irq;
 	int irq_base;
 	int num_irqs;
 	int reset_gpio;
-	struct tabla_amic amic_settings;
+	struct wcd9xxx_amic amic_settings;
 	struct slim_device slimbus_slave_device;
-	struct tabla_micbias_setting micbias;
-	struct tabla_ocp_setting ocp;
+	struct wcd9xxx_micbias_setting micbias;
+	struct wcd9xxx_ocp_setting ocp;
+	struct wcd9xxx_regulator regulator[MAX_REGULATOR];
 };
 
 #endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
new file mode 100644
index 0000000..df54e02
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
@@ -0,0 +1,742 @@
+/* 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 SITAR_CODEC_DIGITAL_H
+#define SITAR_CODEC_DIGITAL_H
+
+#define SITAR_A_PIN_CTL_OE0			(0x10)
+#define SITAR_A_PIN_CTL_OE0__POR			(0x00000000)
+#define SITAR_A_PIN_CTL_OE1			(0x11)
+#define SITAR_A_PIN_CTL_OE1__POR			(0x00000000)
+#define SITAR_A_PIN_CTL_DATA0			(0x12)
+#define SITAR_A_PIN_CTL_DATA0__POR			(0x00000000)
+#define SITAR_A_PIN_CTL_DATA1			(0x13)
+#define SITAR_A_PIN_CTL_DATA1__POR			(0x00000000)
+#define SITAR_A_HDRIVE_GENERIC			(0x18)
+#define SITAR_A_HDRIVE_GENERIC__POR			(0x00000000)
+#define SITAR_A_HDRIVE_OVERRIDE			(0x19)
+#define SITAR_A_HDRIVE_OVERRIDE__POR			(0x00000008)
+#define SITAR_A_ANA_CSR_WAIT_STATE			(0x20)
+#define SITAR_A_ANA_CSR_WAIT_STATE__POR			(0x00000044)
+#define SITAR_A_PROCESS_MONITOR_CTL0			(0x40)
+#define SITAR_A_PROCESS_MONITOR_CTL0__POR			(0x00000080)
+#define SITAR_A_PROCESS_MONITOR_CTL1			(0x41)
+#define SITAR_A_PROCESS_MONITOR_CTL1__POR			(0x00000000)
+#define SITAR_A_PROCESS_MONITOR_CTL2			(0x42)
+#define SITAR_A_PROCESS_MONITOR_CTL2__POR			(0x00000000)
+#define SITAR_A_PROCESS_MONITOR_CTL3			(0x43)
+#define SITAR_A_PROCESS_MONITOR_CTL3__POR			(0x00000001)
+#define SITAR_A_QFUSE_CTL			(0x48)
+#define SITAR_A_QFUSE_CTL__POR			(0x00000000)
+#define SITAR_A_QFUSE_STATUS			(0x49)
+#define SITAR_A_QFUSE_STATUS__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT0			(0x4A)
+#define SITAR_A_QFUSE_DATA_OUT0__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT1			(0x4B)
+#define SITAR_A_QFUSE_DATA_OUT1__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT2			(0x4C)
+#define SITAR_A_QFUSE_DATA_OUT2__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT3			(0x4D)
+#define SITAR_A_QFUSE_DATA_OUT3__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT4			(0x4E)
+#define SITAR_A_QFUSE_DATA_OUT4__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT5			(0x4F)
+#define SITAR_A_QFUSE_DATA_OUT5__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT6			(0x50)
+#define SITAR_A_QFUSE_DATA_OUT6__POR			(0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT7			(0x51)
+#define SITAR_A_QFUSE_DATA_OUT7__POR			(0x00000000)
+#define SITAR_A_CDC_CTL			(0x80)
+#define SITAR_A_CDC_CTL__POR			(0x00000000)
+#define SITAR_A_LEAKAGE_CTL			(0x88)
+#define SITAR_A_LEAKAGE_CTL__POR			(0x00000004)
+#define SITAR_A_INTR_MODE			(0x90)
+#define SITAR_A_INTR_MODE__POR			(0x00000000)
+#define SITAR_A_INTR_MASK0			(0x94)
+#define SITAR_A_INTR_MASK0__POR			(0x000000ff)
+#define SITAR_A_INTR_MASK1			(0x95)
+#define SITAR_A_INTR_MASK1__POR			(0x000000ff)
+#define SITAR_A_INTR_MASK2			(0x96)
+#define SITAR_A_INTR_MASK2__POR			(0x000000ff)
+#define SITAR_A_INTR_STATUS0			(0x98)
+#define SITAR_A_INTR_STATUS0__POR			(0x00000000)
+#define SITAR_A_INTR_STATUS1			(0x99)
+#define SITAR_A_INTR_STATUS1__POR			(0x00000000)
+#define SITAR_A_INTR_STATUS2			(0x9A)
+#define SITAR_A_INTR_STATUS2__POR			(0x00000000)
+#define SITAR_A_INTR_CLEAR0			(0x9C)
+#define SITAR_A_INTR_CLEAR0__POR			(0x00000000)
+#define SITAR_A_INTR_CLEAR1			(0x9D)
+#define SITAR_A_INTR_CLEAR1__POR			(0x00000000)
+#define SITAR_A_INTR_CLEAR2			(0x9E)
+#define SITAR_A_INTR_CLEAR2__POR			(0x00000000)
+#define SITAR_A_INTR_LEVEL0			(0xA0)
+#define SITAR_A_INTR_LEVEL0__POR			(0x00000001)
+#define SITAR_A_INTR_LEVEL1			(0xA1)
+#define SITAR_A_INTR_LEVEL1__POR			(0x00000000)
+#define SITAR_A_INTR_LEVEL2			(0xA2)
+#define SITAR_A_INTR_LEVEL2__POR			(0x00000000)
+#define SITAR_A_INTR_TEST0			(0xA4)
+#define SITAR_A_INTR_TEST0__POR			(0x00000000)
+#define SITAR_A_INTR_TEST1			(0xA5)
+#define SITAR_A_INTR_TEST1__POR			(0x00000000)
+#define SITAR_A_INTR_TEST2			(0xA6)
+#define SITAR_A_INTR_TEST2__POR			(0x00000000)
+#define SITAR_A_INTR_SET0			(0xA8)
+#define SITAR_A_INTR_SET0__POR			(0x00000000)
+#define SITAR_A_INTR_SET1			(0xA9)
+#define SITAR_A_INTR_SET1__POR			(0x00000000)
+#define SITAR_A_INTR_SET2			(0xAA)
+#define SITAR_A_INTR_SET2__POR			(0x00000000)
+#define SITAR_A_CDC_TX_I2S_SCK_MODE			(0xC0)
+#define SITAR_A_CDC_TX_I2S_SCK_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_TX_I2S_WS_MODE			(0xC1)
+#define SITAR_A_CDC_TX_I2S_WS_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_DATA0_MODE			(0xC4)
+#define SITAR_A_CDC_DMIC_DATA0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_CLK0_MODE			(0xC5)
+#define SITAR_A_CDC_DMIC_CLK0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_DATA1_MODE			(0xC6)
+#define SITAR_A_CDC_DMIC_DATA1_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_DMIC_CLK1_MODE			(0xC7)
+#define SITAR_A_CDC_DMIC_CLK1_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_TX_I2S_SD0_MODE			(0xC8)
+#define SITAR_A_CDC_TX_I2S_SD0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_INTR_MODE			(0xC9)
+#define SITAR_A_CDC_INTR_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_RX_I2S_SD0_MODE			(0xCA)
+#define SITAR_A_CDC_RX_I2S_SD0_MODE__POR			(0x00000000)
+#define SITAR_A_CDC_RX_I2S_SD1_MODE			(0xCB)
+#define SITAR_A_CDC_RX_I2S_SD1_MODE__POR			(0x00000000)
+#define SITAR_A_BIAS_REF_CTL			(0x100)
+#define SITAR_A_BIAS_REF_CTL__POR			(0x0000001c)
+#define SITAR_A_BIAS_CENTRAL_BG_CTL			(0x101)
+#define SITAR_A_BIAS_CENTRAL_BG_CTL__POR			(0x00000050)
+#define SITAR_A_BIAS_PRECHRG_CTL			(0x102)
+#define SITAR_A_BIAS_PRECHRG_CTL__POR			(0x00000007)
+#define SITAR_A_BIAS_CURR_CTL_1			(0x103)
+#define SITAR_A_BIAS_CURR_CTL_1__POR			(0x00000052)
+#define SITAR_A_BIAS_CURR_CTL_2			(0x104)
+#define SITAR_A_BIAS_CURR_CTL_2__POR			(0x00000000)
+#define SITAR_A_BIAS_OSC_BG_CTL			(0x105)
+#define SITAR_A_BIAS_OSC_BG_CTL__POR			(0x00000016)
+#define SITAR_A_CLK_BUFF_EN1			(0x108)
+#define SITAR_A_CLK_BUFF_EN1__POR			(0x00000004)
+#define SITAR_A_CLK_BUFF_EN2			(0x109)
+#define SITAR_A_CLK_BUFF_EN2__POR			(0x00000002)
+#define SITAR_A_LDO_H_MODE_1			(0x110)
+#define SITAR_A_LDO_H_MODE_1__POR			(0x00000065)
+#define SITAR_A_LDO_H_MODE_2			(0x111)
+#define SITAR_A_LDO_H_MODE_2__POR			(0x000000a8)
+#define SITAR_A_LDO_H_LOOP_CTL			(0x112)
+#define SITAR_A_LDO_H_LOOP_CTL__POR			(0x0000006b)
+#define SITAR_A_LDO_H_COMP_1			(0x113)
+#define SITAR_A_LDO_H_COMP_1__POR			(0x00000084)
+#define SITAR_A_LDO_H_COMP_2			(0x114)
+#define SITAR_A_LDO_H_COMP_2__POR			(0x000000e0)
+#define SITAR_A_LDO_H_BIAS_1			(0x115)
+#define SITAR_A_LDO_H_BIAS_1__POR			(0x0000006d)
+#define SITAR_A_LDO_H_BIAS_2			(0x116)
+#define SITAR_A_LDO_H_BIAS_2__POR			(0x000000a5)
+#define SITAR_A_LDO_H_BIAS_3			(0x117)
+#define SITAR_A_LDO_H_BIAS_3__POR			(0x00000060)
+#define SITAR_A_MICB_CFILT_1_CTL			(0x128)
+#define SITAR_A_MICB_CFILT_1_CTL__POR			(0x00000040)
+#define SITAR_A_MICB_CFILT_1_VAL			(0x129)
+#define SITAR_A_MICB_CFILT_1_VAL__POR			(0x00000080)
+#define SITAR_A_MICB_CFILT_1_PRECHRG			(0x12A)
+#define SITAR_A_MICB_CFILT_1_PRECHRG__POR			(0x00000038)
+#define SITAR_A_MICB_1_CTL			(0x12B)
+#define SITAR_A_MICB_1_CTL__POR			(0x00000016)
+#define SITAR_A_MICB_1_INT_RBIAS			(0x12C)
+#define SITAR_A_MICB_1_INT_RBIAS__POR			(0x00000024)
+#define SITAR_A_MICB_1_MBHC			(0x12D)
+#define SITAR_A_MICB_1_MBHC__POR			(0x00000001)
+#define SITAR_A_MICB_CFILT_2_CTL			(0x12E)
+#define SITAR_A_MICB_CFILT_2_CTL__POR			(0x00000040)
+#define SITAR_A_MICB_CFILT_2_VAL			(0x12F)
+#define SITAR_A_MICB_CFILT_2_VAL__POR			(0x00000080)
+#define SITAR_A_MICB_CFILT_2_PRECHRG			(0x130)
+#define SITAR_A_MICB_CFILT_2_PRECHRG__POR			(0x00000038)
+#define SITAR_A_MICB_2_CTL			(0x131)
+#define SITAR_A_MICB_2_CTL__POR			(0x00000016)
+#define SITAR_A_MICB_2_INT_RBIAS			(0x132)
+#define SITAR_A_MICB_2_INT_RBIAS__POR			(0x00000024)
+#define SITAR_A_MICB_2_MBHC			(0x133)
+#define SITAR_A_MICB_2_MBHC__POR			(0x00000002)
+#define SITAR_A_TX_COM_BIAS			(0x14C)
+#define SITAR_A_TX_COM_BIAS__POR			(0x000000e0)
+#define SITAR_A_MBHC_SCALING_MUX_1			(0x14E)
+#define SITAR_A_MBHC_SCALING_MUX_1__POR			(0x00000000)
+#define SITAR_A_MBHC_SCALING_MUX_2			(0x14F)
+#define SITAR_A_MBHC_SCALING_MUX_2__POR			(0x00000080)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_1			(0x151)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_1__POR			(0x00000000)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_2			(0x152)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_2__POR			(0x00000080)
+#define SITAR_A_TX_1_2_EN			(0x153)
+#define SITAR_A_TX_1_2_EN__POR			(0x00000000)
+#define SITAR_A_TX_1_2_TEST_EN			(0x154)
+#define SITAR_A_TX_1_2_TEST_EN__POR			(0x000000cc)
+#define SITAR_A_TX_1_2_ADC_CH1			(0x155)
+#define SITAR_A_TX_1_2_ADC_CH1__POR			(0x00000044)
+#define SITAR_A_TX_1_2_ADC_CH2			(0x156)
+#define SITAR_A_TX_1_2_ADC_CH2__POR			(0x00000044)
+#define SITAR_A_TX_1_2_ATEST_REFCTRL			(0x157)
+#define SITAR_A_TX_1_2_ATEST_REFCTRL__POR			(0x00000000)
+#define SITAR_A_TX_1_2_TEST_CTL			(0x158)
+#define SITAR_A_TX_1_2_TEST_CTL__POR			(0x00000038)
+#define SITAR_A_TX_1_2_TEST_BLOCK_EN			(0x159)
+#define SITAR_A_TX_1_2_TEST_BLOCK_EN__POR			(0x000000fc)
+#define SITAR_A_TX_1_2_TXFE_CLKDIV			(0x15A)
+#define SITAR_A_TX_1_2_TXFE_CLKDIV__POR			(0x000000ee)
+#define SITAR_A_TX_1_2_SAR_ERR_CH1			(0x15B)
+#define SITAR_A_TX_1_2_SAR_ERR_CH1__POR			(0x00000000)
+#define SITAR_A_TX_1_2_SAR_ERR_CH2			(0x15C)
+#define SITAR_A_TX_1_2_SAR_ERR_CH2__POR			(0x00000000)
+#define SITAR_A_TX_3_EN			(0x15D)
+#define SITAR_A_TX_3_EN__POR			(0x00000000)
+#define SITAR_A_TX_3_TEST_EN			(0x15E)
+#define SITAR_A_TX_3_TEST_EN__POR			(0x000000cc)
+#define SITAR_A_TX_3_ADC			(0x15F)
+#define SITAR_A_TX_3_ADC__POR			(0x00000044)
+#define SITAR_A_TX_3_MBHC_ATEST_REFCTRL			(0x161)
+#define SITAR_A_TX_3_MBHC_ATEST_REFCTRL__POR			(0x00000000)
+#define SITAR_A_TX_3_TEST_CTL			(0x162)
+#define SITAR_A_TX_3_TEST_CTL__POR			(0x00000038)
+#define SITAR_A_TX_3_TEST_BLOCK_EN			(0x163)
+#define SITAR_A_TX_3_TEST_BLOCK_EN__POR			(0x000000fc)
+#define SITAR_A_TX_3_TXFE_CKDIV			(0x164)
+#define SITAR_A_TX_3_TXFE_CKDIV__POR			(0x000000ee)
+#define SITAR_A_TX_3_SAR_ERR			(0x165)
+#define SITAR_A_TX_3_SAR_ERR__POR			(0x00000000)
+#define SITAR_A_TX_4_MBHC_EN			(0x171)
+#define SITAR_A_TX_4_MBHC_EN__POR			(0x0000000c)
+#define SITAR_A_TX_4_MBHC_ADC			(0x173)
+#define SITAR_A_TX_4_MBHC_ADC__POR			(0x00000044)
+#define SITAR_A_TX_4_MBHC_TEST_CTL			(0x174)
+#define SITAR_A_TX_4_MBHC_TEST_CTL__POR			(0x00000038)
+#define SITAR_A_TX_4_MBHC_SAR_ERR			(0x175)
+#define SITAR_A_TX_4_MBHC_SAR_ERR__POR			(0x00000000)
+#define SITAR_A_TX_4_TXFE_CLKDIV			(0x176)
+#define SITAR_A_TX_4_TXFE_CLKDIV__POR			(0x0000001c)
+#define SITAR_A_AUX_COM_CTL			(0x180)
+#define SITAR_A_AUX_COM_CTL__POR			(0x00000034)
+#define SITAR_A_AUX_COM_ATEST			(0x181)
+#define SITAR_A_AUX_COM_ATEST__POR			(0x00000000)
+#define SITAR_A_AUX_L_EN			(0x182)
+#define SITAR_A_AUX_L_EN__POR			(0x00000000)
+#define SITAR_A_AUX_L_GAIN			(0x183)
+#define SITAR_A_AUX_L_GAIN__POR			(0x0000001f)
+#define SITAR_A_AUX_L_PA_CONN			(0x184)
+#define SITAR_A_AUX_L_PA_CONN__POR			(0x00000000)
+#define SITAR_A_AUX_L_PA_CONN_INV			(0x185)
+#define SITAR_A_AUX_L_PA_CONN_INV__POR			(0x00000000)
+#define SITAR_A_AUX_R_EN			(0x186)
+#define SITAR_A_AUX_R_EN__POR			(0x00000000)
+#define SITAR_A_AUX_R_GAIN			(0x187)
+#define SITAR_A_AUX_R_GAIN__POR			(0x0000001f)
+#define SITAR_A_AUX_R_PA_CONN			(0x188)
+#define SITAR_A_AUX_R_PA_CONN__POR			(0x00000000)
+#define SITAR_A_AUX_R_PA_CONN_INV			(0x189)
+#define SITAR_A_AUX_R_PA_CONN_INV__POR			(0x00000000)
+#define SITAR_A_CP_EN			(0x192)
+#define SITAR_A_CP_EN__POR			(0x000000e6)
+#define SITAR_A_CP_CLK			(0x193)
+#define SITAR_A_CP_CLK__POR			(0x00000029)
+#define SITAR_A_CP_STATIC			(0x194)
+#define SITAR_A_CP_STATIC__POR			(0x00000010)
+#define SITAR_A_CP_DCC1			(0x195)
+#define SITAR_A_CP_DCC1__POR			(0x00000052)
+#define SITAR_A_CP_DCC3			(0x196)
+#define SITAR_A_CP_DCC3__POR			(0x00000001)
+#define SITAR_A_CP_ATEST			(0x197)
+#define SITAR_A_CP_ATEST__POR			(0x00000000)
+#define SITAR_A_CP_DTEST			(0x198)
+#define SITAR_A_CP_DTEST__POR			(0x00000000)
+#define SITAR_A_RX_COM_TIMER_DIV			(0x19E)
+#define SITAR_A_RX_COM_TIMER_DIV__POR			(0x000000e8)
+#define SITAR_A_RX_COM_OCP_CTL			(0x19F)
+#define SITAR_A_RX_COM_OCP_CTL__POR			(0x0000001f)
+#define SITAR_A_RX_COM_OCP_COUNT			(0x1A0)
+#define SITAR_A_RX_COM_OCP_COUNT__POR			(0x00000077)
+#define SITAR_A_RX_COM_DAC_CTL			(0x1A1)
+#define SITAR_A_RX_COM_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_COM_BIAS			(0x1A2)
+#define SITAR_A_RX_COM_BIAS__POR			(0x00000000)
+#define SITAR_A_RX_HPH_BIAS_PA			(0x1A6)
+#define SITAR_A_RX_HPH_BIAS_PA__POR			(0x00000057)
+#define SITAR_A_RX_HPH_BIAS_LDO			(0x1A7)
+#define SITAR_A_RX_HPH_BIAS_LDO__POR			(0x00000056)
+#define SITAR_A_RX_HPH_BIAS_CNP			(0x1A8)
+#define SITAR_A_RX_HPH_BIAS_CNP__POR			(0x0000008a)
+#define SITAR_A_RX_HPH_BIAS_WG			(0x1A9)
+#define SITAR_A_RX_HPH_BIAS_WG__POR			(0x00000060)
+#define SITAR_A_RX_HPH_OCP_CTL			(0x1AA)
+#define SITAR_A_RX_HPH_OCP_CTL__POR			(0x000000e8)
+#define SITAR_A_RX_HPH_CNP_EN			(0x1AB)
+#define SITAR_A_RX_HPH_CNP_EN__POR			(0x00000080)
+#define SITAR_A_RX_HPH_CNP_WG_CTL			(0x1AC)
+#define SITAR_A_RX_HPH_CNP_WG_CTL__POR			(0x000000dc)
+#define SITAR_A_RX_HPH_CNP_WG_TIME			(0x1AD)
+#define SITAR_A_RX_HPH_CNP_WG_TIME__POR			(0x00000028)
+#define SITAR_A_RX_HPH_L_GAIN			(0x1AE)
+#define SITAR_A_RX_HPH_L_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_HPH_L_TEST			(0x1AF)
+#define SITAR_A_RX_HPH_L_TEST__POR			(0x00000001)
+#define SITAR_A_RX_HPH_L_PA_CTL			(0x1B0)
+#define SITAR_A_RX_HPH_L_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_HPH_L_DAC_CTL			(0x1B1)
+#define SITAR_A_RX_HPH_L_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_HPH_L_ATEST			(0x1B2)
+#define SITAR_A_RX_HPH_L_ATEST__POR			(0x00000000)
+#define SITAR_A_RX_HPH_L_STATUS			(0x1B3)
+#define SITAR_A_RX_HPH_L_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_HPH_R_GAIN			(0x1B4)
+#define SITAR_A_RX_HPH_R_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_HPH_R_TEST			(0x1B5)
+#define SITAR_A_RX_HPH_R_TEST__POR			(0x00000001)
+#define SITAR_A_RX_HPH_R_PA_CTL			(0x1B6)
+#define SITAR_A_RX_HPH_R_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_HPH_R_DAC_CTL			(0x1B7)
+#define SITAR_A_RX_HPH_R_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_HPH_R_ATEST			(0x1B8)
+#define SITAR_A_RX_HPH_R_ATEST__POR			(0x00000000)
+#define SITAR_A_RX_HPH_R_STATUS			(0x1B9)
+#define SITAR_A_RX_HPH_R_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_EAR_BIAS_PA			(0x1BA)
+#define SITAR_A_RX_EAR_BIAS_PA__POR			(0x000000a6)
+#define SITAR_A_RX_EAR_BIAS_CMBUFF			(0x1BB)
+#define SITAR_A_RX_EAR_BIAS_CMBUFF__POR			(0x000000a0)
+#define SITAR_A_RX_EAR_EN			(0x1BC)
+#define SITAR_A_RX_EAR_EN__POR			(0x00000000)
+#define SITAR_A_RX_EAR_GAIN			(0x1BD)
+#define SITAR_A_RX_EAR_GAIN__POR			(0x00000002)
+#define SITAR_A_RX_EAR_CMBUFF			(0x1BE)
+#define SITAR_A_RX_EAR_CMBUFF__POR			(0x00000004)
+#define SITAR_A_RX_EAR_ICTL			(0x1BF)
+#define SITAR_A_RX_EAR_ICTL__POR			(0x00000040)
+#define SITAR_A_RX_EAR_CCOMP			(0x1C0)
+#define SITAR_A_RX_EAR_CCOMP__POR			(0x00000008)
+#define SITAR_A_RX_EAR_VCM			(0x1C1)
+#define SITAR_A_RX_EAR_VCM__POR			(0x00000003)
+#define SITAR_A_RX_EAR_CNP			(0x1C2)
+#define SITAR_A_RX_EAR_CNP__POR			(0x000000f2)
+#define SITAR_A_RX_EAR_ATEST			(0x1C3)
+#define SITAR_A_RX_EAR_ATEST__POR			(0x00000000)
+#define SITAR_A_RX_EAR_STATUS			(0x1C5)
+#define SITAR_A_RX_EAR_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_LINE_BIAS_PA			(0x1C6)
+#define SITAR_A_RX_LINE_BIAS_PA__POR			(0x000000aa)
+#define SITAR_A_RX_LINE_BIAS_LDO			(0x1C7)
+#define SITAR_A_RX_LINE_BIAS_LDO__POR			(0x00000086)
+#define SITAR_A_RX_LINE_BIAS_CNP1			(0x1C8)
+#define SITAR_A_RX_LINE_BIAS_CNP1__POR			(0x00000060)
+#define SITAR_A_RX_LINE_COM			(0x1C9)
+#define SITAR_A_RX_LINE_COM__POR			(0x00000000)
+#define SITAR_A_RX_LINE_CNP_EN			(0x1CA)
+#define SITAR_A_RX_LINE_CNP_EN__POR			(0x00000080)
+#define SITAR_A_RX_LINE_CNP_WG_CTL			(0x1CB)
+#define SITAR_A_RX_LINE_CNP_WG_CTL__POR			(0x000000dc)
+#define SITAR_A_RX_LINE_CNP_WG_TIME			(0x1CC)
+#define SITAR_A_RX_LINE_CNP_WG_TIME__POR			(0x00000028)
+#define SITAR_A_RX_LINE_1_GAIN			(0x1CD)
+#define SITAR_A_RX_LINE_1_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_LINE_1_TEST			(0x1CE)
+#define SITAR_A_RX_LINE_1_TEST__POR			(0x00000001)
+#define SITAR_A_RX_LINE_1_DAC_CTL			(0x1CF)
+#define SITAR_A_RX_LINE_1_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_LINE_1_STATUS			(0x1D0)
+#define SITAR_A_RX_LINE_1_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_LINE_2_GAIN			(0x1D1)
+#define SITAR_A_RX_LINE_2_GAIN__POR			(0x00000000)
+#define SITAR_A_RX_LINE_2_TEST			(0x1D2)
+#define SITAR_A_RX_LINE_2_TEST__POR			(0x00000001)
+#define SITAR_A_RX_LINE_2_DAC_CTL			(0x1D3)
+#define SITAR_A_RX_LINE_2_DAC_CTL__POR			(0x00000000)
+#define SITAR_A_RX_LINE_2_STATUS			(0x1D4)
+#define SITAR_A_RX_LINE_2_STATUS__POR			(0x00000004)
+#define SITAR_A_RX_LINE_BIAS_CNP2			(0x1E1)
+#define SITAR_A_RX_LINE_BIAS_CNP2__POR			(0x0000008a)
+#define SITAR_A_RX_LINE_OCP_CTL			(0x1E2)
+#define SITAR_A_RX_LINE_OCP_CTL__POR			(0x000000e8)
+#define SITAR_A_RX_LINE_1_PA_CTL			(0x1E3)
+#define SITAR_A_RX_LINE_1_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_LINE_2_PA_CTL			(0x1E4)
+#define SITAR_A_RX_LINE_2_PA_CTL__POR			(0x00000040)
+#define SITAR_A_RX_LINE_CNP_DBG			(0x1EC)
+#define SITAR_A_RX_LINE_CNP_DBG__POR			(0x00000000)
+#define SITAR_A_MBHC_HPH			(0x1ED)
+#define SITAR_A_MBHC_HPH__POR			(0x00000048)
+#define SITAR_A_RC_OSC_FREQ			(0x1F7)
+#define SITAR_A_RC_OSC_FREQ__POR			(0x00000046)
+#define SITAR_A_RC_OSC_TEST			(0x1F8)
+#define SITAR_A_RC_OSC_TEST__POR			(0x0000000a)
+#define SITAR_A_RC_OSC_STATUS			(0x1F9)
+#define SITAR_A_RC_OSC_STATUS__POR			(0x0000001c)
+#define SITAR_A_RC_OSC_TUNER			(0x1FA)
+#define SITAR_A_RC_OSC_TUNER__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_CTL			(0x200)
+#define SITAR_A_CDC_ANC1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_SHIFT			(0x201)
+#define SITAR_A_CDC_ANC1_SHIFT__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B1_CTL			(0x202)
+#define SITAR_A_CDC_ANC1_IIR_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B2_CTL			(0x203)
+#define SITAR_A_CDC_ANC1_IIR_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B3_CTL			(0x204)
+#define SITAR_A_CDC_ANC1_IIR_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B4_CTL			(0x205)
+#define SITAR_A_CDC_ANC1_IIR_B4_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B1_CTL			(0x206)
+#define SITAR_A_CDC_ANC1_LPF_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B2_CTL			(0x207)
+#define SITAR_A_CDC_ANC1_LPF_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B3_CTL			(0x208)
+#define SITAR_A_CDC_ANC1_LPF_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_SPARE			(0x209)
+#define SITAR_A_CDC_ANC1_SPARE__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_SMLPF_CTL			(0x20A)
+#define SITAR_A_CDC_ANC1_SMLPF_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_ANC1_DCFLT_CTL			(0x20B)
+#define SITAR_A_CDC_ANC1_DCFLT_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER			(0x220)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN			(0x221)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG			(0x222)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG__POR			(0x00000000)
+#define SITAR_A_CDC_TX1_MUX_CTL			(0x223)
+#define SITAR_A_CDC_TX1_MUX_CTL__POR			(0x00000008)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL			(0x224)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR			(0x00000003)
+#define SITAR_A_CDC_TX1_DMIC_CTL			(0x225)
+#define SITAR_A_CDC_TX1_DMIC_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_SRC1_PDA_CFG			(0x2A0)
+#define SITAR_A_CDC_SRC1_PDA_CFG__POR			(0x00000000)
+#define SITAR_A_CDC_SRC1_FS_CTL			(0x2A1)
+#define SITAR_A_CDC_SRC1_FS_CTL__POR			(0x0000001b)
+
+#define SITAR_A_CDC_RX1_B1_CTL                  (0x000002B0)
+#define SITAR_A_CDC_RX1_B1_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B1_CTL                  (0x000002B8)
+#define SITAR_A_CDC_RX2_B1_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B1_CTL                  (0x000002C0)
+#define SITAR_A_CDC_RX3_B1_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B2_CTL                  (0x000002B1)
+#define SITAR_A_CDC_RX1_B2_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B2_CTL                  (0x000002B9)
+#define SITAR_A_CDC_RX2_B2_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B2_CTL                  (0x000002C1)
+#define SITAR_A_CDC_RX3_B2_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B3_CTL                  (0x000002B2)
+#define SITAR_A_CDC_RX1_B3_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B3_CTL                  (0x000002BA)
+#define SITAR_A_CDC_RX2_B3_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B3_CTL                  (0x000002C2)
+#define SITAR_A_CDC_RX3_B3_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B4_CTL                  (0x000002B3)
+#define SITAR_A_CDC_RX1_B4_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B4_CTL                  (0x000002BB)
+#define SITAR_A_CDC_RX2_B4_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B4_CTL                  (0x000002C3)
+#define SITAR_A_CDC_RX3_B4_CTL__POR                     (0x00000000)
+
+#define SITAR_A_CDC_RX1_B5_CTL                  (0x000002B4)
+#define SITAR_A_CDC_RX1_B5_CTL__POR                     (0x00000060)
+#define SITAR_A_CDC_RX2_B5_CTL                  (0x000002BC)
+#define SITAR_A_CDC_RX2_B5_CTL__POR                     (0x00000060)
+#define SITAR_A_CDC_RX3_B5_CTL                  (0x000002C4)
+#define SITAR_A_CDC_RX3_B5_CTL__POR                     (0x00000060)
+
+#define SITAR_A_CDC_RX1_B6_CTL                  (0x000002B5)
+#define SITAR_A_CDC_RX1_B6_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX2_B6_CTL                  (0x000002BD)
+#define SITAR_A_CDC_RX2_B6_CTL__POR                     (0x00000000)
+#define SITAR_A_CDC_RX3_B6_CTL                  (0x000002C5)
+#define SITAR_A_CDC_RX3_B6_CTL__POR                     (0x00000000)
+
+
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL			(0x2B6)
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL			(0x2B7)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL			(0x300)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL			(0x301)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL			(0x302)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL			(0x303)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_DMIC_CTL			(0x304)
+#define SITAR_A_CDC_CLK_DMIC_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_I2S_CTL			(0x305)
+#define SITAR_A_CDC_CLK_RX_I2S_CTL__POR			(0x00000003)
+#define SITAR_A_CDC_CLK_TX_I2S_CTL			(0x306)
+#define SITAR_A_CDC_CLK_TX_I2S_CTL__POR			(0x00000003)
+#define SITAR_A_CDC_CLK_OTHR_RESET_CTL			(0x307)
+#define SITAR_A_CDC_CLK_OTHR_RESET_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL			(0x308)
+#define SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_OTHR_CTL			(0x30A)
+#define SITAR_A_CDC_CLK_OTHR_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL			(0x30B)
+#define SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_ANC_CLK_EN_CTL			(0x30C)
+#define SITAR_A_CDC_CLK_ANC_CLK_EN_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_B1_CTL			(0x30D)
+#define SITAR_A_CDC_CLK_RX_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_RX_B2_CTL			(0x30E)
+#define SITAR_A_CDC_CLK_RX_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_MCLK_CTL			(0x30F)
+#define SITAR_A_CDC_CLK_MCLK_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_PDM_CTL			(0x310)
+#define SITAR_A_CDC_CLK_PDM_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_SD_CTL			(0x311)
+#define SITAR_A_CDC_CLK_SD_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLK_LP_CTL			(0x312)
+#define SITAR_A_CDC_CLK_LP_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL			(0x320)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR	(0x00000007)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL		(0x321)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR	(0x00000013)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL		(0x322)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR	(0x0000001b)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL		(0x323)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR	(0x0000007f)
+#define SITAR_A_CDC_CLSG_GAIN_THRESH_CTL		(0x324)
+#define SITAR_A_CDC_CLSG_GAIN_THRESH_CTL__POR		(0x00000026)
+#define SITAR_A_CDC_CLSG_TIMER_B1_CFG			(0x325)
+#define SITAR_A_CDC_CLSG_TIMER_B1_CFG__POR		(0x0000000a)
+#define SITAR_A_CDC_CLSG_TIMER_B2_CFG			(0x326)
+#define SITAR_A_CDC_CLSG_TIMER_B2_CFG__POR		(0x00000000)
+#define SITAR_A_CDC_CLSG_CTL			(0x327)
+#define SITAR_A_CDC_CLSG_CTL__POR			(0x00000013)
+#define SITAR_A_CDC_IIR1_GAIN_B1_CTL			(0x340)
+#define SITAR_A_CDC_IIR1_GAIN_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B2_CTL			(0x341)
+#define SITAR_A_CDC_IIR1_GAIN_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B3_CTL			(0x342)
+#define SITAR_A_CDC_IIR1_GAIN_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B4_CTL			(0x343)
+#define SITAR_A_CDC_IIR1_GAIN_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B5_CTL			(0x344)
+#define SITAR_A_CDC_IIR1_GAIN_B5_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B6_CTL			(0x345)
+#define SITAR_A_CDC_IIR1_GAIN_B6_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B7_CTL			(0x346)
+#define SITAR_A_CDC_IIR1_GAIN_B7_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B8_CTL			(0x347)
+#define SITAR_A_CDC_IIR1_GAIN_B8_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_CTL				(0x348)
+#define SITAR_A_CDC_IIR1_CTL__POR			(0x00000040)
+#define SITAR_A_CDC_IIR1_GAIN_TIMER_CTL			(0x349)
+#define SITAR_A_CDC_IIR1_GAIN_TIMER_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B1_CTL			(0x34A)
+#define SITAR_A_CDC_IIR1_COEF_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B2_CTL			(0x34B)
+#define SITAR_A_CDC_IIR1_COEF_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B3_CTL			(0x34C)
+#define SITAR_A_CDC_IIR1_COEF_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B4_CTL			(0x34D)
+#define SITAR_A_CDC_IIR1_COEF_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B5_CTL			(0x34E)
+#define SITAR_A_CDC_IIR1_COEF_B5_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_TOP_GAIN_UPDATE			(0x360)
+#define SITAR_A_CDC_TOP_GAIN_UPDATE__POR		(0x00000000)
+#define SITAR_A_CDC_TOP_RDAC_DOUT_CTL			(0x361)
+#define SITAR_A_CDC_TOP_RDAC_DOUT_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_DEBUG_B1_CTL			(0x368)
+#define SITAR_A_CDC_DEBUG_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B2_CTL			(0x369)
+#define SITAR_A_CDC_DEBUG_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B3_CTL			(0x36A)
+#define SITAR_A_CDC_DEBUG_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B4_CTL			(0x36B)
+#define SITAR_A_CDC_DEBUG_B4_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B5_CTL			(0x36C)
+#define SITAR_A_CDC_DEBUG_B5_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B6_CTL			(0x36D)
+#define SITAR_A_CDC_DEBUG_B6_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_DEBUG_B7_CTL			(0x36E)
+#define SITAR_A_CDC_DEBUG_B7_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_COMP1_B1_CTL			(0x370)
+#define SITAR_A_CDC_COMP1_B1_CTL__POR			(0x00000030)
+#define SITAR_A_CDC_COMP1_B2_CTL			(0x371)
+#define SITAR_A_CDC_COMP1_B2_CTL__POR			(0x000000b5)
+#define SITAR_A_CDC_COMP1_B3_CTL			(0x372)
+#define SITAR_A_CDC_COMP1_B3_CTL__POR			(0x00000028)
+#define SITAR_A_CDC_COMP1_B4_CTL			(0x373)
+#define SITAR_A_CDC_COMP1_B4_CTL__POR			(0x0000003c)
+#define SITAR_A_CDC_COMP1_B5_CTL			(0x374)
+#define SITAR_A_CDC_COMP1_B5_CTL__POR			(0x0000001f)
+#define SITAR_A_CDC_COMP1_B6_CTL			(0x375)
+#define SITAR_A_CDC_COMP1_B6_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS		(0x376)
+#define SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR		(0x00000003)
+#define SITAR_A_CDC_COMP1_FS_CFG			(0x377)
+#define SITAR_A_CDC_COMP1_FS_CFG__POR			(0x0000001b)
+#define SITAR_A_CDC_CONN_RX1_B1_CTL			(0x380)
+#define SITAR_A_CDC_CONN_RX1_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX1_B2_CTL			(0x381)
+#define SITAR_A_CDC_CONN_RX1_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX1_B3_CTL			(0x382)
+#define SITAR_A_CDC_CONN_RX1_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B1_CTL			(0x383)
+#define SITAR_A_CDC_CONN_RX2_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B2_CTL			(0x384)
+#define SITAR_A_CDC_CONN_RX2_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B3_CTL			(0x385)
+#define SITAR_A_CDC_CONN_RX2_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B1_CTL			(0x386)
+#define SITAR_A_CDC_CONN_RX3_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B2_CTL			(0x387)
+#define SITAR_A_CDC_CONN_RX3_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B3_CTL			(0x388)
+#define SITAR_A_CDC_CONN_RX3_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_ANC_B1_CTL			(0x391)
+#define SITAR_A_CDC_CONN_ANC_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_ANC_B2_CTL			(0x392)
+#define SITAR_A_CDC_CONN_ANC_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_B1_CTL			(0x393)
+#define SITAR_A_CDC_CONN_TX_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CONN_TX_B2_CTL			(0x394)
+#define SITAR_A_CDC_CONN_TX_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B1_CTL			(0x397)
+#define SITAR_A_CDC_CONN_EQ1_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B2_CTL			(0x398)
+#define SITAR_A_CDC_CONN_EQ1_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B3_CTL			(0x399)
+#define SITAR_A_CDC_CONN_EQ1_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B4_CTL			(0x39A)
+#define SITAR_A_CDC_CONN_EQ1_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B1_CTL			(0x39B)
+#define SITAR_A_CDC_CONN_EQ2_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B2_CTL			(0x39C)
+#define SITAR_A_CDC_CONN_EQ2_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B3_CTL			(0x39D)
+#define SITAR_A_CDC_CONN_EQ2_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B4_CTL			(0x39E)
+#define SITAR_A_CDC_CONN_EQ2_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC1_B1_CTL			(0x39F)
+#define SITAR_A_CDC_CONN_SRC1_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC1_B2_CTL			(0x3A0)
+#define SITAR_A_CDC_CONN_SRC1_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC2_B1_CTL			(0x3A1)
+#define SITAR_A_CDC_CONN_SRC2_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_SRC2_B2_CTL			(0x3A2)
+#define SITAR_A_CDC_CONN_SRC2_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B1_CTL			(0x3A3)
+#define SITAR_A_CDC_CONN_TX_SB_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B2_CTL			(0x3A4)
+#define SITAR_A_CDC_CONN_TX_SB_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B3_CTL			(0x3A5)
+#define SITAR_A_CDC_CONN_TX_SB_B3_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B4_CTL			(0x3A6)
+#define SITAR_A_CDC_CONN_TX_SB_B4_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B5_CTL			(0x3A7)
+#define SITAR_A_CDC_CONN_TX_SB_B5_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX_SB_B1_CTL			(0x3AE)
+#define SITAR_A_CDC_CONN_RX_SB_B1_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_RX_SB_B2_CTL			(0x3AF)
+#define SITAR_A_CDC_CONN_RX_SB_B2_CTL__POR		(0x00000000)
+#define SITAR_A_CDC_CONN_CLSG_CTL			(0x3B0)
+#define SITAR_A_CDC_CONN_CLSG_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_CONN_SPARE			(0x3B1)
+#define SITAR_A_CDC_CONN_SPARE__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_EN_CTL			(0x3C0)
+#define SITAR_A_CDC_MBHC_EN_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_FIR_B1_CFG			(0x3C1)
+#define SITAR_A_CDC_MBHC_FIR_B1_CFG__POR		(0x00000000)
+#define SITAR_A_CDC_MBHC_FIR_B2_CFG			(0x3C2)
+#define SITAR_A_CDC_MBHC_FIR_B2_CFG__POR		(0x00000006)
+#define SITAR_A_CDC_MBHC_TIMER_B1_CTL			(0x3C3)
+#define SITAR_A_CDC_MBHC_TIMER_B1_CTL__POR		(0x00000003)
+#define SITAR_A_CDC_MBHC_TIMER_B2_CTL			(0x3C4)
+#define SITAR_A_CDC_MBHC_TIMER_B2_CTL__POR		(0x00000009)
+#define SITAR_A_CDC_MBHC_TIMER_B3_CTL			(0x3C5)
+#define SITAR_A_CDC_MBHC_TIMER_B3_CTL__POR		(0x0000001e)
+#define SITAR_A_CDC_MBHC_TIMER_B4_CTL			(0x3C6)
+#define SITAR_A_CDC_MBHC_TIMER_B4_CTL__POR		(0x00000045)
+#define SITAR_A_CDC_MBHC_TIMER_B5_CTL			(0x3C7)
+#define SITAR_A_CDC_MBHC_TIMER_B5_CTL__POR		(0x00000004)
+#define SITAR_A_CDC_MBHC_TIMER_B6_CTL			(0x3C8)
+#define SITAR_A_CDC_MBHC_TIMER_B6_CTL__POR		(0x00000078)
+#define SITAR_A_CDC_MBHC_B1_STATUS			(0x3C9)
+#define SITAR_A_CDC_MBHC_B1_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B2_STATUS			(0x3CA)
+#define SITAR_A_CDC_MBHC_B2_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B3_STATUS			(0x3CB)
+#define SITAR_A_CDC_MBHC_B3_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B4_STATUS			(0x3CC)
+#define SITAR_A_CDC_MBHC_B4_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B5_STATUS			(0x3CD)
+#define SITAR_A_CDC_MBHC_B5_STATUS__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_B1_CTL			(0x3CE)
+#define SITAR_A_CDC_MBHC_B1_CTL__POR			(0x000000c0)
+#define SITAR_A_CDC_MBHC_B2_CTL			(0x3CF)
+#define SITAR_A_CDC_MBHC_B2_CTL__POR			(0x0000005d)
+#define SITAR_A_CDC_MBHC_VOLT_B1_CTL			(0x3D0)
+#define SITAR_A_CDC_MBHC_VOLT_B1_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B2_CTL			(0x3D1)
+#define SITAR_A_CDC_MBHC_VOLT_B2_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B3_CTL			(0x3D2)
+#define SITAR_A_CDC_MBHC_VOLT_B3_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B4_CTL			(0x3D3)
+#define SITAR_A_CDC_MBHC_VOLT_B4_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B5_CTL			(0x3D4)
+#define SITAR_A_CDC_MBHC_VOLT_B5_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B6_CTL			(0x3D5)
+#define SITAR_A_CDC_MBHC_VOLT_B6_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B7_CTL			(0x3D6)
+#define SITAR_A_CDC_MBHC_VOLT_B7_CTL__POR			(0x000000ff)
+#define SITAR_A_CDC_MBHC_VOLT_B8_CTL			(0x3D7)
+#define SITAR_A_CDC_MBHC_VOLT_B8_CTL__POR			(0x00000007)
+#define SITAR_A_CDC_MBHC_VOLT_B9_CTL			(0x3D8)
+#define SITAR_A_CDC_MBHC_VOLT_B9_CTL__POR			(0x000000ff)
+#define SITAR_A_CDC_MBHC_VOLT_B10_CTL			(0x3D9)
+#define SITAR_A_CDC_MBHC_VOLT_B10_CTL__POR			(0x0000007f)
+#define SITAR_A_CDC_MBHC_VOLT_B11_CTL			(0x3DA)
+#define SITAR_A_CDC_MBHC_VOLT_B11_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B12_CTL			(0x3DB)
+#define SITAR_A_CDC_MBHC_VOLT_B12_CTL__POR			(0x00000080)
+#define SITAR_A_CDC_MBHC_CLK_CTL			(0x3DC)
+#define SITAR_A_CDC_MBHC_CLK_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_INT_CTL			(0x3DD)
+#define SITAR_A_CDC_MBHC_INT_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_DEBUG_CTL			(0x3DE)
+#define SITAR_A_CDC_MBHC_DEBUG_CTL__POR			(0x00000000)
+#define SITAR_A_CDC_MBHC_SPARE			(0x3DF)
+#define SITAR_A_CDC_MBHC_SPARE__POR			(0x00000000)
+/* SLIMBUS Slave Registers */
+#define SITAR_SLIM_PGD_PORT_INT_EN0                     (0x30)
+#define SITAR_SLIM_PGD_PORT_INT_STATUS0                 (0x34)
+#define SITAR_SLIM_PGD_PORT_INT_CLR0                    (0x38)
+#define SITAR_SLIM_PGD_PORT_INT_SOURCE0                 (0x60)
+
+/* Macros for Packing Register Writes into a U32 */
+#define SITAR_PACKED_REG_SIZE sizeof(u32)
+
+#define SITAR_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\
+	((mask & 0xff) << 8)|((reg & 0xffff) << 16))
+
+#define SITAR_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+	do { \
+		((reg) = ((packed >> 16) & (0xffff))); \
+		((mask) = ((packed >> 8) & (0xff))); \
+		((val) = ((packed) & (0xff))); \
+	} while (0);
+#endif
diff --git a/include/linux/mfd/wcd9310/registers.h b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
similarity index 95%
rename from include/linux/mfd/wcd9310/registers.h
rename to include/linux/mfd/wcd9xxx/wcd9310_registers.h
index ef27c08..d2736ea 100644
--- a/include/linux/mfd/wcd9310/registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
@@ -1,29 +1,41 @@
+/* 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 TABLA_CODEC_DIGITAL_H
 
 #define TABLA_CODEC_DIGITAL_H
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 
-#define TABLA_A_CHIP_CTL			(0x00)
-#define TABLA_A_CHIP_CTL__POR			(0x00000000)
-#define TABLA_A_CHIP_STATUS			(0x01)
-#define TABLA_A_CHIP_STATUS__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_0			(0x04)
-#define TABLA_A_CHIP_ID_BYTE_0__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_1			(0x05)
-#define TABLA_A_CHIP_ID_BYTE_1__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_2			(0x06)
-#define TABLA_A_CHIP_ID_BYTE_2__POR			(0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_3			(0x07)
-#define TABLA_A_CHIP_ID_BYTE_3__POR			(0x00000001)
-#define TABLA_A_CHIP_VERSION			(0x08)
-#define TABLA_A_CHIP_VERSION__POR			(0x00000020)
-#define TABLA_A_SB_VERSION			(0x09)
-#define TABLA_A_SB_VERSION__POR			(0x00000010)
-#define TABLA_A_SLAVE_ID_1			(0x0C)
-#define TABLA_A_SLAVE_ID_1__POR			(0x00000077)
-#define TABLA_A_SLAVE_ID_2			(0x0D)
-#define TABLA_A_SLAVE_ID_2__POR			(0x00000066)
-#define TABLA_A_SLAVE_ID_3			(0x0E)
-#define TABLA_A_SLAVE_ID_3__POR			(0x00000055)
+#define TABLA_A_CHIP_CTL			WCD9XXX_A_CHIP_CTL
+#define TABLA_A_CHIP_CTL__POR			WCD9XXX_A_CHIP_CTL__POR
+#define TABLA_A_CHIP_STATUS			WCD9XXX_A_CHIP_STATUS
+#define TABLA_A_CHIP_STATUS__POR		WCD9XXX_A_CHIP_STATUS__POR
+#define TABLA_A_CHIP_ID_BYTE_0			WCD9XXX_A_CHIP_ID_BYTE_0
+#define TABLA_A_CHIP_ID_BYTE_0__POR		WCD9XXX_A_CHIP_ID_BYTE_0__POR
+#define TABLA_A_CHIP_ID_BYTE_1			WCD9XXX_A_CHIP_ID_BYTE_1
+#define TABLA_A_CHIP_ID_BYTE_1__POR		WCD9XXX_A_CHIP_ID_BYTE_1__POR
+#define TABLA_A_CHIP_ID_BYTE_2			WCD9XXX_A_CHIP_ID_BYTE_2
+#define TABLA_A_CHIP_ID_BYTE_2__POR		WCD9XXX_A_CHIP_ID_BYTE_2__POR
+#define TABLA_A_CHIP_ID_BYTE_3			WCD9XXX_A_CHIP_ID_BYTE_3
+#define TABLA_A_CHIP_ID_BYTE_3__POR		WCD9XXX_A_CHIP_ID_BYTE_3__POR
+#define TABLA_A_CHIP_VERSION			WCD9XXX_A_CHIP_VERSION
+#define TABLA_A_CHIP_VERSION__POR		WCD9XXX_A_CHIP_VERSION__POR
+#define TABLA_A_SB_VERSION			WCD9XXX_A_SB_VERSION
+#define TABLA_A_SB_VERSION__POR			WCD9XXX_A_SB_VERSION__POR
+#define TABLA_A_SLAVE_ID_1			WCD9XXX_A_SLAVE_ID_1
+#define TABLA_A_SLAVE_ID_1__POR			WCD9XXX_A_SLAVE_ID_1__POR
+#define TABLA_A_SLAVE_ID_2			WCD9XXX_A_SLAVE_ID_2
+#define TABLA_A_SLAVE_ID_2__POR			WCD9XXX_A_SLAVE_ID_2__POR
+#define TABLA_A_SLAVE_ID_3			WCD9XXX_A_SLAVE_ID_3
+#define TABLA_A_SLAVE_ID_3__POR			WCD9XXX_A_SLAVE_ID_3__POR
 #define TABLA_A_PIN_CTL_OE0			(0x10)
 #define TABLA_A_PIN_CTL_OE0__POR			(0x00000000)
 #define TABLA_A_PIN_CTL_OE1			(0x11)
@@ -58,10 +70,10 @@
 #define TABLA_A_QFUSE_DATA_OUT2__POR			(0x00000000)
 #define TABLA_A_QFUSE_DATA_OUT3			(0x4D)
 #define TABLA_A_QFUSE_DATA_OUT3__POR			(0x00000000)
-#define TABLA_A_CDC_CTL			(0x80)
-#define TABLA_A_CDC_CTL__POR			(0x00000000)
-#define TABLA_A_LEAKAGE_CTL			(0x88)
-#define TABLA_A_LEAKAGE_CTL__POR			(0x00000004)
+#define TABLA_A_CDC_CTL				WCD9XXX_A_CDC_CTL
+#define TABLA_A_CDC_CTL__POR			WCD9XXX_A_CDC_CTL__POR
+#define TABLA_A_LEAKAGE_CTL			WCD9XXX_A_LEAKAGE_CTL
+#define TABLA_A_LEAKAGE_CTL__POR		WCD9XXX_A_LEAKAGE_CTL__POR
 #define TABLA_A_INTR_MODE			(0x90)
 #define TABLA_A_INTR_MODE__POR			(0x00000000)
 #define TABLA_A_INTR_MASK0			(0x94)
diff --git a/include/linux/mfd/wcd9310/wcd9310-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
similarity index 84%
rename from include/linux/mfd/wcd9310/wcd9310-slimslave.h
rename to include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 0bbf96f..fcd3bd3 100644
--- a/include/linux/mfd/wcd9310/wcd9310-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -14,7 +14,7 @@
 #define __WCD9310_SLIMSLAVE_H_
 
 #include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
 
 /* Local to the core only */
 #define SLIM_MAX_RX_PORTS 7
@@ -84,19 +84,19 @@
 #define BASE_CH_NUM 128
 
 
-int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la);
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la);
 
-int tabla_deinit_slimslave(struct tabla *tabla);
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx);
 
-int tabla_cfg_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch, unsigned int rate);
-int tabla_cfg_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch, unsigned int rate);
-int tabla_close_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch);
-int tabla_close_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
 				unsigned int tot_ch);
-int tabla_get_channel(struct tabla *tabla,
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
 			unsigned int *rx_ch,
 			unsigned int *tx_ch);
 #endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
new file mode 100644
index 0000000..c66e953
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -0,0 +1,42 @@
+/* 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 WCD9XXX_CODEC_DIGITAL_H
+
+#define WCD9XXX_CODEC_DIGITAL_H
+
+#define WCD9XXX_A_CHIP_CTL			(0x00)
+#define WCD9XXX_A_CHIP_CTL__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_STATUS			(0x01)
+#define WCD9XXX_A_CHIP_STATUS__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_0			(0x04)
+#define WCD9XXX_A_CHIP_ID_BYTE_0__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_1			(0x05)
+#define WCD9XXX_A_CHIP_ID_BYTE_1__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_2			(0x06)
+#define WCD9XXX_A_CHIP_ID_BYTE_2__POR			(0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_3			(0x07)
+#define WCD9XXX_A_CHIP_ID_BYTE_3__POR			(0x00000001)
+#define WCD9XXX_A_CHIP_VERSION			(0x08)
+#define WCD9XXX_A_CHIP_VERSION__POR			(0x00000020)
+#define WCD9XXX_A_SB_VERSION			(0x09)
+#define WCD9XXX_A_SB_VERSION__POR			(0x00000010)
+#define WCD9XXX_A_SLAVE_ID_1			(0x0C)
+#define WCD9XXX_A_SLAVE_ID_1__POR			(0x00000077)
+#define WCD9XXX_A_SLAVE_ID_2			(0x0D)
+#define WCD9XXX_A_SLAVE_ID_2__POR			(0x00000066)
+#define WCD9XXX_A_SLAVE_ID_3			(0x0E)
+#define WCD9XXX_A_SLAVE_ID_3__POR			(0x00000055)
+#define WCD9XXX_A_CDC_CTL			(0x80)
+#define WCD9XXX_A_CDC_CTL__POR			(0x00000000)
+#define WCD9XXX_A_LEAKAGE_CTL			(0x88)
+#define WCD9XXX_A_LEAKAGE_CTL__POR			(0x00000004)
+#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9e82abf8..ff53742 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -50,8 +50,12 @@
 	u8			rel_sectors;
 	u8			rel_param;
 	u8			part_config;
+	u8			cache_ctrl;
+	u8			rst_n_function;
 	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
+	unsigned int		generic_cmd6_time;	/* Units: 10ms */
+	unsigned int            power_off_longtime;     /* Units: ms */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
 	unsigned int		card_type;
@@ -64,10 +68,15 @@
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
 	unsigned int		boot_size;		/* in bytes */
+	unsigned int		cache_size;		/* Units: KB */
+	bool			hpi_en;			/* HPI enablebit */
+	bool			hpi;			/* HPI support bit */
+	unsigned int		hpi_cmd;		/* cmd used as HPI */
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
+	u8			out_of_int_time;	/* 198 */
 	u8			raw_s_a_timeout;		/* 217 */
 	u8			raw_hc_erase_gap_size;	/* 221 */
 	u8			raw_erase_timeout_mult;	/* 223 */
@@ -77,6 +86,9 @@
 	u8			raw_sec_feature_support;/* 231 */
 	u8			raw_trim_mult;		/* 232 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
+
+	unsigned int            feature_support;
+#define MMC_DISCARD_FEATURE	BIT(0)                  /* CMD38 feature */
 };
 
 struct sd_scr {
@@ -189,6 +201,11 @@
 #define MMC_QUIRK_DISABLE_CD	(1<<5)		/* disconnect CD/DAT[3] resistor */
 #define MMC_QUIRK_INAND_CMD38	(1<<6)		/* iNAND devices have broken CMD38 */
 #define MMC_QUIRK_BLK_NO_CMD23	(1<<7)		/* Avoid CMD23 for regular multiblock */
+	unsigned int    poweroff_notify_state;	/* eMMC4.5 notify feature */
+#define MMC_NO_POWER_NOTIFICATION	0
+#define MMC_POWERED_ON			1
+#define MMC_POWEROFF_SHORT		2
+#define MMC_POWEROFF_LONG		3
 
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 279c023..05c126c 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -117,6 +117,7 @@
 
 	unsigned int		sg_len;		/* size of scatter list */
 	struct scatterlist	*sg;		/* I/O scatter list */
+	s32			host_cookie;	/* host private data */
 };
 
 struct mmc_request {
@@ -125,13 +126,17 @@
 	struct mmc_data		*data;
 	struct mmc_command	*stop;
 
-	void			*done_data;	/* completion data */
+	struct completion	completion;
 	void			(*done)(struct mmc_request *);/* completion function */
 };
 
 struct mmc_host;
 struct mmc_card;
+struct mmc_async_req;
 
+extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
+					   struct mmc_async_req *, int *);
+extern int mmc_interrupt_hpi(struct mmc_card *);
 extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
@@ -142,6 +147,7 @@
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
 #define MMC_TRIM_ARG		0x00000001
+#define MMC_DISCARD_ARG		0x00000003
 #define MMC_SECURE_TRIM1_ARG	0x80000001
 #define MMC_SECURE_TRIM2_ARG	0x80008000
 
@@ -152,11 +158,17 @@
 		     unsigned int arg);
 extern int mmc_can_erase(struct mmc_card *card);
 extern int mmc_can_trim(struct mmc_card *card);
+extern int mmc_can_discard(struct mmc_card *card);
+extern int mmc_can_sanitize(struct mmc_card *card);
 extern int mmc_can_secure_erase_trim(struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 				   unsigned int nr);
+extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+extern int mmc_hw_reset(struct mmc_host *host);
+extern int mmc_hw_reset_check(struct mmc_host *host);
+extern int mmc_can_reset(struct mmc_card *card);
 
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
@@ -167,6 +179,7 @@
 extern int mmc_try_claim_host(struct mmc_host *host);
 
 extern int mmc_detect_card_removed(struct mmc_host *host);
+extern int mmc_flush_cache(struct mmc_card *);
 
 /**
  *	mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d90c779..35137d6 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -107,6 +107,15 @@
 	 */
 	int (*enable)(struct mmc_host *host);
 	int (*disable)(struct mmc_host *host, int lazy);
+	/*
+	 * It is optional for the host to implement pre_req and post_req in
+	 * order to support double buffering of requests (prepare one
+	 * request while another request is active).
+	 */
+	void	(*post_req)(struct mmc_host *host, struct mmc_request *req,
+			    int err);
+	void	(*pre_req)(struct mmc_host *host, struct mmc_request *req,
+			   bool is_first_req);
 	void	(*request)(struct mmc_host *host, struct mmc_request *req);
 	/*
 	 * Avoid calling these three functions too often or in a "fast path",
@@ -140,11 +149,22 @@
 	int	(*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*execute_tuning)(struct mmc_host *host);
 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
+	void	(*hw_reset)(struct mmc_host *host);
 };
 
 struct mmc_card;
 struct device;
 
+struct mmc_async_req {
+	/* active mmc request */
+	struct mmc_request	*mrq;
+	/*
+	 * Check error status of completed mmc request.
+	 * Returns 0 if success otherwise non zero.
+	 */
+	int (*err_check) (struct mmc_card *, struct mmc_async_req *);
+};
+
 struct mmc_host {
 	struct device		*parent;
 	struct device		class_dev;
@@ -212,8 +232,19 @@
 #define MMC_CAP_MAX_CURRENT_600	(1 << 28)	/* Host max current limit is 600mA */
 #define MMC_CAP_MAX_CURRENT_800	(1 << 29)	/* Host max current limit is 800mA */
 #define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */
+#define MMC_CAP_HW_RESET	(1 << 31)	/* Hardware reset */
+
+	unsigned int		caps2;		/* More host capabilities */
+
+#define MMC_CAP2_CACHE_CTRL	(1 << 1)	/* Allow cache control */
+#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)	/* Notify poweroff supported */
+#define MMC_CAP2_NO_MULTI_READ	(1 << 3)	/* Multiblock reads don't work */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
+	unsigned int        power_notify_type;
+#define MMC_HOST_PW_NOTIFY_NONE		0
+#define MMC_HOST_PW_NOTIFY_SHORT	1
+#define MMC_HOST_PW_NOTIFY_LONG		2
 
 #ifdef CONFIG_MMC_CLKGATE
 	int			clk_requests;	/* internal reference counter */
@@ -234,6 +265,7 @@
 	unsigned int		max_req_size;	/* maximum number of bytes in one req */
 	unsigned int		max_blk_size;	/* maximum size of one mmc block */
 	unsigned int		max_blk_count;	/* maximum number of blocks in one req */
+	unsigned int		max_discard_to;	/* max. discard timeout in ms */
 
 	/* private data */
 	spinlock_t		lock;		/* lock for claim and bus ops */
@@ -314,6 +346,9 @@
 		ktime_t start;
 	} perf;
 #endif
+
+	struct mmc_async_req	*areq;		/* active async req */
+
 	unsigned long		private[0] ____cacheline_aligned;
 };
 
@@ -362,6 +397,8 @@
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
 
+extern int mmc_cache_ctrl(struct mmc_host *, u8);
+
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
 	host->ops->enable_sdio_irq(host, 0);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 53013f9..0a72bf8 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -271,18 +271,30 @@
  * EXT_CSD fields
  */
 
+#define EXT_CSD_FLUSH_CACHE		32      /* W */
+#define EXT_CSD_CACHE_CTRL		33      /* R/W */
+#define EXT_CSD_POWER_OFF_NOTIFICATION	34	/* R/W */
 #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
+#define EXT_CSD_HPI_MGMT		161	/* R/W */
+#define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
+#define EXT_CSD_SANITIZE_START		165     /* W */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
+#define EXT_CSD_POWER_CLASS		187	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_STRUCTURE		194	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_OUT_OF_INTERRUPT_TIME	198	/* RO */
 #define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
+#define EXT_CSD_PWR_CL_52_195		200	/* RO */
+#define EXT_CSD_PWR_CL_26_195		201	/* RO */
+#define EXT_CSD_PWR_CL_52_360		202	/* RO */
+#define EXT_CSD_PWR_CL_26_360		203	/* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_REL_WR_SEC_C		222	/* RO */
@@ -294,6 +306,14 @@
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
 #define EXT_CSD_TRIM_MULT		232	/* RO */
+#define EXT_CSD_PWR_CL_200_195		236	/* RO */
+#define EXT_CSD_PWR_CL_200_360		237	/* RO */
+#define EXT_CSD_PWR_CL_DDR_52_195	238	/* RO */
+#define EXT_CSD_PWR_CL_DDR_52_360	239	/* RO */
+#define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
+#define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
+#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_HPI_FEATURES		503	/* RO */
 
 /*
  * EXT_CSD field definitions
@@ -328,7 +348,20 @@
 #define EXT_CSD_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
+#define EXT_CSD_SEC_SANITIZE	BIT(6)  /* v4.5 only */
 
+#define EXT_CSD_RST_N_EN_MASK	0x3
+#define EXT_CSD_RST_N_ENABLED	1	/* RST_n is enabled on card */
+
+#define EXT_CSD_NO_POWER_NOTIFICATION	0
+#define EXT_CSD_POWER_ON		1
+#define EXT_CSD_POWER_OFF_SHORT		2
+#define EXT_CSD_POWER_OFF_LONG		3
+
+#define EXT_CSD_PWR_CL_8BIT_MASK	0xF0	/* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_4BIT_MASK	0x0F	/* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_8BIT_SHIFT	4
+#define EXT_CSD_PWR_CL_4BIT_SHIFT	0
 /*
  * MMC_SWITCH access modes
  */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 07784e2..e02597a 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -241,8 +241,17 @@
 #define VPE_SCALER_CONFIG_LEN           260
 #define VPE_DIS_OFFSET_CFG_LEN          12
 
-#define IMEM_Y_OFFSET  0x2E000000
-#define IMEM_CBCR_OFFSET  0x2E00FA00
+
+#define CAPTURE_WIDTH          1280
+#define IMEM_Y_SIZE            (CAPTURE_WIDTH*16)
+#define IMEM_CBCR_SIZE         (CAPTURE_WIDTH*8)
+
+#define IMEM_Y_PING_OFFSET     0x2E000000
+#define IMEM_CBCR_PING_OFFSET  (IMEM_Y_PING_OFFSET + IMEM_Y_SIZE)
+
+#define IMEM_Y_PONG_OFFSET     (IMEM_CBCR_PING_OFFSET + IMEM_CBCR_SIZE)
+#define IMEM_CBCR_PONG_OFFSET  (IMEM_Y_PONG_OFFSET + IMEM_Y_SIZE)
+
 
 struct msm_vpe_op_mode_cfg {
 	uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN];
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index bedfc7c..211d146 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -152,7 +152,7 @@
 	* Here we have IOCTl's that are specific to IRIS
 	* (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28)
 	*/
-	V4L2_CID_PRIVATE_SOFT_MUTE, /* 0x800001E*/
+	V4L2_CID_PRIVATE_SOFT_MUTE,/* 0x800001E*/
 	V4L2_CID_PRIVATE_RIVA_ACCS_ADDR,
 	V4L2_CID_PRIVATE_RIVA_ACCS_LEN,
 	V4L2_CID_PRIVATE_RIVA_PEEK,
@@ -162,16 +162,16 @@
 	V4L2_CID_PRIVATE_SSBI_POKE,
 	V4L2_CID_PRIVATE_TX_TONE,
 	V4L2_CID_PRIVATE_RDS_GRP_COUNTERS,
-	V4L2_CID_PRIVATE_SET_NOTCH_FILTER, /* 0x8000028 */
+	V4L2_CID_PRIVATE_SET_NOTCH_FILTER,/* 0x8000028 */
 
-	V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, /* 0x8000029 */
-	V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION, /* 0x800002A : IRIS command */
-	V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, /* 0x800002B */
-
-	V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD =
-		V4L2_CTRL_CLASS_USER + 0x92B,
-	V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD =
-		V4L2_CTRL_CLASS_USER + 0x92C
+	V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,/* 0x8000029 */
+	V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION,/* 0x800002A : IRIS */
+	V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,/* 0x800002B */
+	V4L2_CID_PRIVATE_IRIS_GET_SINR, /* 0x800002C : IRIS */
+	V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, /* 0x800002D */
+	V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */
+	V4L2_CID_PRIVATE_SINR_THRESHOLD,  /* 0x800002F : IRIS */
+	V4L2_CID_PRIVATE_SINR_SAMPLES,  /* 0x8000030 : IRIS */
 
 };
 
@@ -349,6 +349,7 @@
 	(reg = (reg & ~mask) | (((val) << offset) & mask))
 #define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset)
 #define RSH_DATA(val, offset)    ((val) >> (offset))
+#define LSH_DATA(val, offset)    ((val) << (offset))
 #define GET_ABS_VAL(val)        ((val) & (0xFF))
 
 enum radio_state_t {
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 0104f1a..d3d393d 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -44,6 +44,8 @@
     "alignment.c:720",
     "async.c:122",
     "async.c:270",
+    "block.c:835",
+    "block.c:836",
     "dir.c:43",
     "dm.c:1053",
     "dm.c:1080",
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b923a25..88181a6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -250,6 +250,9 @@
 config SND_SOC_UDA1380
         tristate
 
+config SND_SOC_WCD9304
+	tristate
+
 config SND_SOC_WCD9310
         tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 78740ab..0bd7255 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -38,6 +38,7 @@
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
 snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
@@ -132,6 +133,7 @@
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WCD9304)	+= snd-soc-wcd9304.o
 obj-$(CONFIG_SND_SOC_WCD9310)	+= snd-soc-wcd9310.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd9304-tables.c b/sound/soc/codecs/wcd9304-tables.c
new file mode 100644
index 0000000..823f926
--- /dev/null
+++ b/sound/soc/codecs/wcd9304-tables.c
@@ -0,0 +1,720 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
+#include "wcd9304.h"
+
+const u8 sitar_reg_defaults[SITAR_CACHE_SIZE] = {
+	[WCD9XXX_A_CHIP_CTL] = WCD9XXX_A_CHIP_CTL__POR,
+	[WCD9XXX_A_CHIP_STATUS] = WCD9XXX_A_CHIP_STATUS__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_0] = WCD9XXX_A_CHIP_ID_BYTE_0__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_1] = WCD9XXX_A_CHIP_ID_BYTE_1__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_2] = WCD9XXX_A_CHIP_ID_BYTE_2__POR,
+	[WCD9XXX_A_CHIP_ID_BYTE_3] = WCD9XXX_A_CHIP_ID_BYTE_3__POR,
+	[WCD9XXX_A_CHIP_VERSION] = WCD9XXX_A_CHIP_VERSION__POR,
+	[WCD9XXX_A_SB_VERSION] = WCD9XXX_A_SB_VERSION__POR,
+	[WCD9XXX_A_SLAVE_ID_1] = WCD9XXX_A_SLAVE_ID_1__POR,
+	[WCD9XXX_A_SLAVE_ID_2] = WCD9XXX_A_SLAVE_ID_2__POR,
+	[WCD9XXX_A_SLAVE_ID_3] = WCD9XXX_A_SLAVE_ID_3__POR,
+	[SITAR_A_PIN_CTL_OE0] = SITAR_A_PIN_CTL_OE0__POR,
+	[SITAR_A_PIN_CTL_OE1] = SITAR_A_PIN_CTL_OE1__POR,
+	[SITAR_A_PIN_CTL_DATA0] = SITAR_A_PIN_CTL_DATA0__POR,
+	[SITAR_A_PIN_CTL_DATA1] = SITAR_A_PIN_CTL_DATA1__POR,
+	[SITAR_A_HDRIVE_GENERIC] = SITAR_A_HDRIVE_GENERIC__POR,
+	[SITAR_A_HDRIVE_OVERRIDE] = SITAR_A_HDRIVE_OVERRIDE__POR,
+	[SITAR_A_ANA_CSR_WAIT_STATE] = SITAR_A_ANA_CSR_WAIT_STATE__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL0] = SITAR_A_PROCESS_MONITOR_CTL0__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL1] = SITAR_A_PROCESS_MONITOR_CTL1__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL2] = SITAR_A_PROCESS_MONITOR_CTL2__POR,
+	[SITAR_A_PROCESS_MONITOR_CTL3] = SITAR_A_PROCESS_MONITOR_CTL3__POR,
+	[SITAR_A_QFUSE_CTL] = SITAR_A_QFUSE_CTL__POR,
+	[SITAR_A_QFUSE_STATUS] = SITAR_A_QFUSE_STATUS__POR,
+	[SITAR_A_QFUSE_DATA_OUT0] = SITAR_A_QFUSE_DATA_OUT0__POR,
+	[SITAR_A_QFUSE_DATA_OUT1] = SITAR_A_QFUSE_DATA_OUT1__POR,
+	[SITAR_A_QFUSE_DATA_OUT2] = SITAR_A_QFUSE_DATA_OUT2__POR,
+	[SITAR_A_QFUSE_DATA_OUT3] = SITAR_A_QFUSE_DATA_OUT3__POR,
+	[SITAR_A_CDC_CTL] = SITAR_A_CDC_CTL__POR,
+	[SITAR_A_LEAKAGE_CTL] = SITAR_A_LEAKAGE_CTL__POR,
+	[SITAR_A_INTR_MODE] = SITAR_A_INTR_MODE__POR,
+	[SITAR_A_INTR_MASK0] = SITAR_A_INTR_MASK0__POR,
+	[SITAR_A_INTR_MASK1] = SITAR_A_INTR_MASK1__POR,
+	[SITAR_A_INTR_MASK2] = SITAR_A_INTR_MASK2__POR,
+	[SITAR_A_INTR_STATUS0] = SITAR_A_INTR_STATUS0__POR,
+	[SITAR_A_INTR_STATUS1] = SITAR_A_INTR_STATUS1__POR,
+	[SITAR_A_INTR_STATUS2] = SITAR_A_INTR_STATUS2__POR,
+	[SITAR_A_INTR_CLEAR0] = SITAR_A_INTR_CLEAR0__POR,
+	[SITAR_A_INTR_CLEAR1] = SITAR_A_INTR_CLEAR1__POR,
+	[SITAR_A_INTR_CLEAR2] = SITAR_A_INTR_CLEAR2__POR,
+	[SITAR_A_INTR_LEVEL0] = SITAR_A_INTR_LEVEL0__POR,
+	[SITAR_A_INTR_LEVEL1] = SITAR_A_INTR_LEVEL1__POR,
+	[SITAR_A_INTR_LEVEL2] = SITAR_A_INTR_LEVEL2__POR,
+	[SITAR_A_INTR_TEST0] = SITAR_A_INTR_TEST0__POR,
+	[SITAR_A_INTR_TEST1] = SITAR_A_INTR_TEST1__POR,
+	[SITAR_A_INTR_TEST2] = SITAR_A_INTR_TEST2__POR,
+	[SITAR_A_INTR_SET0] = SITAR_A_INTR_SET0__POR,
+	[SITAR_A_INTR_SET1] = SITAR_A_INTR_SET1__POR,
+	[SITAR_A_INTR_SET2] = SITAR_A_INTR_SET2__POR,
+	[SITAR_A_CDC_TX_I2S_SCK_MODE] = SITAR_A_CDC_TX_I2S_SCK_MODE__POR,
+	[SITAR_A_CDC_TX_I2S_WS_MODE] = SITAR_A_CDC_TX_I2S_WS_MODE__POR,
+	[SITAR_A_CDC_DMIC_DATA0_MODE] = SITAR_A_CDC_DMIC_DATA0_MODE__POR,
+	[SITAR_A_CDC_DMIC_CLK0_MODE] = SITAR_A_CDC_DMIC_CLK0_MODE__POR,
+	[SITAR_A_CDC_DMIC_DATA1_MODE] = SITAR_A_CDC_DMIC_DATA1_MODE__POR,
+	[SITAR_A_CDC_DMIC_CLK1_MODE] = SITAR_A_CDC_DMIC_CLK1_MODE__POR,
+	[SITAR_A_CDC_TX_I2S_SD0_MODE] = SITAR_A_CDC_TX_I2S_SD0_MODE__POR,
+	[SITAR_A_CDC_INTR_MODE] = SITAR_A_CDC_INTR_MODE__POR,
+	[SITAR_A_CDC_RX_I2S_SD0_MODE] = SITAR_A_CDC_RX_I2S_SD0_MODE__POR,
+	[SITAR_A_CDC_RX_I2S_SD1_MODE] = SITAR_A_CDC_RX_I2S_SD1_MODE__POR,
+	[SITAR_A_BIAS_REF_CTL] = SITAR_A_BIAS_REF_CTL__POR,
+	[SITAR_A_BIAS_CENTRAL_BG_CTL] = SITAR_A_BIAS_CENTRAL_BG_CTL__POR,
+	[SITAR_A_BIAS_PRECHRG_CTL] = SITAR_A_BIAS_PRECHRG_CTL__POR,
+	[SITAR_A_BIAS_CURR_CTL_1] = SITAR_A_BIAS_CURR_CTL_1__POR,
+	[SITAR_A_BIAS_CURR_CTL_2] = SITAR_A_BIAS_CURR_CTL_2__POR,
+	[SITAR_A_BIAS_OSC_BG_CTL] = SITAR_A_BIAS_OSC_BG_CTL__POR,
+	[SITAR_A_CLK_BUFF_EN1] = SITAR_A_CLK_BUFF_EN1__POR,
+	[SITAR_A_CLK_BUFF_EN2] = SITAR_A_CLK_BUFF_EN2__POR,
+	[SITAR_A_LDO_H_MODE_1] = SITAR_A_LDO_H_MODE_1__POR,
+	[SITAR_A_LDO_H_MODE_2] = SITAR_A_LDO_H_MODE_2__POR,
+	[SITAR_A_LDO_H_LOOP_CTL] = SITAR_A_LDO_H_LOOP_CTL__POR,
+	[SITAR_A_LDO_H_COMP_1] = SITAR_A_LDO_H_COMP_1__POR,
+	[SITAR_A_LDO_H_COMP_2] = SITAR_A_LDO_H_COMP_2__POR,
+	[SITAR_A_LDO_H_BIAS_1] = SITAR_A_LDO_H_BIAS_1__POR,
+	[SITAR_A_LDO_H_BIAS_2] = SITAR_A_LDO_H_BIAS_2__POR,
+	[SITAR_A_LDO_H_BIAS_3] = SITAR_A_LDO_H_BIAS_3__POR,
+	[SITAR_A_MICB_CFILT_1_CTL] = SITAR_A_MICB_CFILT_1_CTL__POR,
+	[SITAR_A_MICB_CFILT_1_VAL] = SITAR_A_MICB_CFILT_1_VAL__POR,
+	[SITAR_A_MICB_CFILT_1_PRECHRG] = SITAR_A_MICB_CFILT_1_PRECHRG__POR,
+	[SITAR_A_MICB_1_CTL] = SITAR_A_MICB_1_CTL__POR,
+	[SITAR_A_MICB_1_INT_RBIAS] = SITAR_A_MICB_1_INT_RBIAS__POR,
+	[SITAR_A_MICB_1_MBHC] = SITAR_A_MICB_1_MBHC__POR,
+	[SITAR_A_MICB_CFILT_2_CTL] = SITAR_A_MICB_CFILT_2_CTL__POR,
+	[SITAR_A_MICB_CFILT_2_VAL] = SITAR_A_MICB_CFILT_2_VAL__POR,
+	[SITAR_A_MICB_CFILT_2_PRECHRG] = SITAR_A_MICB_CFILT_2_PRECHRG__POR,
+	[SITAR_A_MICB_2_CTL] = SITAR_A_MICB_2_CTL__POR,
+	[SITAR_A_MICB_2_INT_RBIAS] = SITAR_A_MICB_2_INT_RBIAS__POR,
+	[SITAR_A_MICB_2_MBHC] = SITAR_A_MICB_2_MBHC__POR,
+	[SITAR_A_TX_COM_BIAS] = SITAR_A_TX_COM_BIAS__POR,
+	[SITAR_A_MBHC_SCALING_MUX_1] = SITAR_A_MBHC_SCALING_MUX_1__POR,
+	[SITAR_A_MBHC_SCALING_MUX_2] = SITAR_A_MBHC_SCALING_MUX_2__POR,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_1] = SITAR_A_TX_SUP_SWITCH_CTRL_1__POR,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_2] = SITAR_A_TX_SUP_SWITCH_CTRL_2__POR,
+	[SITAR_A_TX_1_2_EN] = SITAR_A_TX_1_2_EN__POR,
+	[SITAR_A_TX_1_2_TEST_EN] = SITAR_A_TX_1_2_TEST_EN__POR,
+	[SITAR_A_TX_1_2_ADC_CH1] = SITAR_A_TX_1_2_ADC_CH1__POR,
+	[SITAR_A_TX_1_2_ADC_CH2] = SITAR_A_TX_1_2_ADC_CH2__POR,
+	[SITAR_A_TX_1_2_ATEST_REFCTRL] = SITAR_A_TX_1_2_ATEST_REFCTRL__POR,
+	[SITAR_A_TX_1_2_TEST_CTL] = SITAR_A_TX_1_2_TEST_CTL__POR,
+	[SITAR_A_TX_1_2_TEST_BLOCK_EN] = SITAR_A_TX_1_2_TEST_BLOCK_EN__POR,
+	[SITAR_A_TX_1_2_TXFE_CLKDIV] = SITAR_A_TX_1_2_TXFE_CLKDIV__POR,
+	[SITAR_A_TX_1_2_SAR_ERR_CH1] = SITAR_A_TX_1_2_SAR_ERR_CH1__POR,
+	[SITAR_A_TX_1_2_SAR_ERR_CH2] = SITAR_A_TX_1_2_SAR_ERR_CH2__POR,
+	[SITAR_A_TX_3_EN] = SITAR_A_TX_3_EN__POR,
+	[SITAR_A_TX_3_TEST_EN] = SITAR_A_TX_3_TEST_EN__POR,
+	[SITAR_A_TX_3_ADC] = SITAR_A_TX_3_ADC__POR,
+	[SITAR_A_TX_3_MBHC_ATEST_REFCTRL] =
+		SITAR_A_TX_3_MBHC_ATEST_REFCTRL__POR,
+	[SITAR_A_TX_3_TEST_CTL] = SITAR_A_TX_3_TEST_CTL__POR,
+	[SITAR_A_TX_3_TEST_BLOCK_EN] = SITAR_A_TX_3_TEST_BLOCK_EN__POR,
+	[SITAR_A_TX_3_TXFE_CKDIV] = SITAR_A_TX_3_TXFE_CKDIV__POR,
+	[SITAR_A_TX_3_SAR_ERR] = SITAR_A_TX_3_SAR_ERR__POR,
+	[SITAR_A_TX_4_MBHC_EN] = SITAR_A_TX_4_MBHC_EN__POR,
+	[SITAR_A_TX_4_MBHC_ADC] = SITAR_A_TX_4_MBHC_ADC__POR,
+	[SITAR_A_TX_4_MBHC_TEST_CTL] = SITAR_A_TX_4_MBHC_TEST_CTL__POR,
+	[SITAR_A_TX_4_MBHC_SAR_ERR] = SITAR_A_TX_4_MBHC_SAR_ERR__POR,
+	[SITAR_A_TX_4_TXFE_CLKDIV] = SITAR_A_TX_4_TXFE_CLKDIV__POR,
+	[SITAR_A_AUX_COM_CTL] = SITAR_A_AUX_COM_CTL__POR,
+	[SITAR_A_AUX_COM_ATEST] = SITAR_A_AUX_COM_ATEST__POR,
+	[SITAR_A_AUX_L_EN] = SITAR_A_AUX_L_EN__POR,
+	[SITAR_A_AUX_L_GAIN] = SITAR_A_AUX_L_GAIN__POR,
+	[SITAR_A_AUX_L_PA_CONN] = SITAR_A_AUX_L_PA_CONN__POR,
+	[SITAR_A_AUX_L_PA_CONN_INV] = SITAR_A_AUX_L_PA_CONN_INV__POR,
+	[SITAR_A_AUX_R_EN] = SITAR_A_AUX_R_EN__POR,
+	[SITAR_A_AUX_R_GAIN] = SITAR_A_AUX_R_GAIN__POR,
+	[SITAR_A_AUX_R_PA_CONN] = SITAR_A_AUX_R_PA_CONN__POR,
+	[SITAR_A_AUX_R_PA_CONN_INV] = SITAR_A_AUX_R_PA_CONN_INV__POR,
+	[SITAR_A_CP_EN] = SITAR_A_CP_EN__POR,
+	[SITAR_A_CP_CLK] = SITAR_A_CP_CLK__POR,
+	[SITAR_A_CP_STATIC] = SITAR_A_CP_STATIC__POR,
+	[SITAR_A_CP_DCC1] = SITAR_A_CP_DCC1__POR,
+	[SITAR_A_CP_DCC3] = SITAR_A_CP_DCC3__POR,
+	[SITAR_A_CP_ATEST] = SITAR_A_CP_ATEST__POR,
+	[SITAR_A_CP_DTEST] = SITAR_A_CP_DTEST__POR,
+	[SITAR_A_RX_COM_TIMER_DIV] = SITAR_A_RX_COM_TIMER_DIV__POR,
+	[SITAR_A_RX_COM_OCP_CTL] = SITAR_A_RX_COM_OCP_CTL__POR,
+	[SITAR_A_RX_COM_OCP_COUNT] = SITAR_A_RX_COM_OCP_COUNT__POR,
+	[SITAR_A_RX_COM_DAC_CTL] = SITAR_A_RX_COM_DAC_CTL__POR,
+	[SITAR_A_RX_COM_BIAS] = SITAR_A_RX_COM_BIAS__POR,
+	[SITAR_A_RX_HPH_BIAS_PA] = SITAR_A_RX_HPH_BIAS_PA__POR,
+	[SITAR_A_RX_HPH_BIAS_LDO] = SITAR_A_RX_HPH_BIAS_LDO__POR,
+	[SITAR_A_RX_HPH_BIAS_CNP] = SITAR_A_RX_HPH_BIAS_CNP__POR,
+	[SITAR_A_RX_HPH_BIAS_WG] = SITAR_A_RX_HPH_BIAS_WG__POR,
+	[SITAR_A_RX_HPH_OCP_CTL] = SITAR_A_RX_HPH_OCP_CTL__POR,
+	[SITAR_A_RX_HPH_CNP_EN] = SITAR_A_RX_HPH_CNP_EN__POR,
+	[SITAR_A_RX_HPH_CNP_WG_CTL] = SITAR_A_RX_HPH_CNP_WG_CTL__POR,
+	[SITAR_A_RX_HPH_CNP_WG_TIME] = SITAR_A_RX_HPH_CNP_WG_TIME__POR,
+	[SITAR_A_RX_HPH_L_GAIN] = SITAR_A_RX_HPH_L_GAIN__POR,
+	[SITAR_A_RX_HPH_L_TEST] = SITAR_A_RX_HPH_L_TEST__POR,
+	[SITAR_A_RX_HPH_L_PA_CTL] = SITAR_A_RX_HPH_L_PA_CTL__POR,
+	[SITAR_A_RX_HPH_L_DAC_CTL] = SITAR_A_RX_HPH_L_DAC_CTL__POR,
+	[SITAR_A_RX_HPH_L_ATEST] = SITAR_A_RX_HPH_L_ATEST__POR,
+	[SITAR_A_RX_HPH_L_STATUS] = SITAR_A_RX_HPH_L_STATUS__POR,
+	[SITAR_A_RX_HPH_R_GAIN] = SITAR_A_RX_HPH_R_GAIN__POR,
+	[SITAR_A_RX_HPH_R_TEST] = SITAR_A_RX_HPH_R_TEST__POR,
+	[SITAR_A_RX_HPH_R_PA_CTL] = SITAR_A_RX_HPH_R_PA_CTL__POR,
+	[SITAR_A_RX_HPH_R_DAC_CTL] = SITAR_A_RX_HPH_R_DAC_CTL__POR,
+	[SITAR_A_RX_HPH_R_ATEST] = SITAR_A_RX_HPH_R_ATEST__POR,
+	[SITAR_A_RX_HPH_R_STATUS] = SITAR_A_RX_HPH_R_STATUS__POR,
+	[SITAR_A_RX_EAR_BIAS_PA] = SITAR_A_RX_EAR_BIAS_PA__POR,
+	[SITAR_A_RX_EAR_BIAS_CMBUFF] = SITAR_A_RX_EAR_BIAS_CMBUFF__POR,
+	[SITAR_A_RX_EAR_EN] = SITAR_A_RX_EAR_EN__POR,
+	[SITAR_A_RX_EAR_GAIN] = SITAR_A_RX_EAR_GAIN__POR,
+	[SITAR_A_RX_EAR_CMBUFF] = SITAR_A_RX_EAR_CMBUFF__POR,
+	[SITAR_A_RX_EAR_ICTL] = SITAR_A_RX_EAR_ICTL__POR,
+	[SITAR_A_RX_EAR_CCOMP] = SITAR_A_RX_EAR_CCOMP__POR,
+	[SITAR_A_RX_EAR_VCM] = SITAR_A_RX_EAR_VCM__POR,
+	[SITAR_A_RX_EAR_CNP] = SITAR_A_RX_EAR_CNP__POR,
+	[SITAR_A_RX_EAR_ATEST] = SITAR_A_RX_EAR_ATEST__POR,
+	[SITAR_A_RX_EAR_STATUS] = SITAR_A_RX_EAR_STATUS__POR,
+	[SITAR_A_RX_LINE_BIAS_PA] = SITAR_A_RX_LINE_BIAS_PA__POR,
+	[SITAR_A_RX_LINE_BIAS_LDO] = SITAR_A_RX_LINE_BIAS_LDO__POR,
+	[SITAR_A_RX_LINE_BIAS_CNP1] = SITAR_A_RX_LINE_BIAS_CNP1__POR,
+	[SITAR_A_RX_LINE_COM] = SITAR_A_RX_LINE_COM__POR,
+	[SITAR_A_RX_LINE_CNP_EN] = SITAR_A_RX_LINE_CNP_EN__POR,
+	[SITAR_A_RX_LINE_CNP_WG_CTL] = SITAR_A_RX_LINE_CNP_WG_CTL__POR,
+	[SITAR_A_RX_LINE_CNP_WG_TIME] = SITAR_A_RX_LINE_CNP_WG_TIME__POR,
+	[SITAR_A_RX_LINE_1_GAIN] = SITAR_A_RX_LINE_1_GAIN__POR,
+	[SITAR_A_RX_LINE_1_TEST] = SITAR_A_RX_LINE_1_TEST__POR,
+	[SITAR_A_RX_LINE_1_DAC_CTL] = SITAR_A_RX_LINE_1_DAC_CTL__POR,
+	[SITAR_A_RX_LINE_1_STATUS] = SITAR_A_RX_LINE_1_STATUS__POR,
+	[SITAR_A_RX_LINE_2_GAIN] = SITAR_A_RX_LINE_2_GAIN__POR,
+	[SITAR_A_RX_LINE_2_TEST] = SITAR_A_RX_LINE_2_TEST__POR,
+	[SITAR_A_RX_LINE_2_DAC_CTL] = SITAR_A_RX_LINE_2_DAC_CTL__POR,
+	[SITAR_A_RX_LINE_2_STATUS] = SITAR_A_RX_LINE_2_STATUS__POR,
+	[SITAR_A_RX_LINE_BIAS_CNP2] = SITAR_A_RX_LINE_BIAS_CNP2__POR,
+	[SITAR_A_RX_LINE_OCP_CTL] = SITAR_A_RX_LINE_OCP_CTL__POR,
+	[SITAR_A_RX_LINE_1_PA_CTL] = SITAR_A_RX_LINE_1_PA_CTL__POR,
+	[SITAR_A_RX_LINE_2_PA_CTL] = SITAR_A_RX_LINE_2_PA_CTL__POR,
+	[SITAR_A_RX_LINE_CNP_DBG] = SITAR_A_RX_LINE_CNP_DBG__POR,
+	[SITAR_A_MBHC_HPH] = SITAR_A_MBHC_HPH__POR,
+	[SITAR_A_RC_OSC_FREQ] = SITAR_A_RC_OSC_FREQ__POR,
+	[SITAR_A_RC_OSC_TEST] = SITAR_A_RC_OSC_TEST__POR,
+	[SITAR_A_RC_OSC_STATUS] = SITAR_A_RC_OSC_STATUS__POR,
+	[SITAR_A_RC_OSC_TUNER] = SITAR_A_RC_OSC_TUNER__POR,
+	[SITAR_A_CDC_ANC1_CTL] = SITAR_A_CDC_ANC1_CTL__POR,
+	[SITAR_A_CDC_ANC1_SHIFT] = SITAR_A_CDC_ANC1_SHIFT__POR,
+	[SITAR_A_CDC_ANC1_IIR_B1_CTL] = SITAR_A_CDC_ANC1_IIR_B1_CTL__POR,
+	[SITAR_A_CDC_ANC1_IIR_B2_CTL] = SITAR_A_CDC_ANC1_IIR_B2_CTL__POR,
+	[SITAR_A_CDC_ANC1_IIR_B3_CTL] = SITAR_A_CDC_ANC1_IIR_B3_CTL__POR,
+	[SITAR_A_CDC_ANC1_IIR_B4_CTL] = SITAR_A_CDC_ANC1_IIR_B4_CTL__POR,
+	[SITAR_A_CDC_ANC1_LPF_B1_CTL] = SITAR_A_CDC_ANC1_LPF_B1_CTL__POR,
+	[SITAR_A_CDC_ANC1_LPF_B2_CTL] = SITAR_A_CDC_ANC1_LPF_B2_CTL__POR,
+	[SITAR_A_CDC_ANC1_LPF_B3_CTL] = SITAR_A_CDC_ANC1_LPF_B3_CTL__POR,
+	[SITAR_A_CDC_ANC1_SPARE] = SITAR_A_CDC_ANC1_SPARE__POR,
+	[SITAR_A_CDC_ANC1_SMLPF_CTL] = SITAR_A_CDC_ANC1_SMLPF_CTL__POR,
+	[SITAR_A_CDC_ANC1_DCFLT_CTL] = SITAR_A_CDC_ANC1_DCFLT_CTL__POR,
+	[SITAR_A_CDC_TX1_VOL_CTL_TIMER] = SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR,
+	[SITAR_A_CDC_TX1_VOL_CTL_GAIN] = SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR,
+	[SITAR_A_CDC_TX1_VOL_CTL_CFG] = SITAR_A_CDC_TX1_VOL_CTL_CFG__POR,
+	[SITAR_A_CDC_TX1_MUX_CTL] = SITAR_A_CDC_TX1_MUX_CTL__POR,
+	[SITAR_A_CDC_TX1_CLK_FS_CTL] = SITAR_A_CDC_TX1_CLK_FS_CTL__POR,
+	[SITAR_A_CDC_TX1_DMIC_CTL] = SITAR_A_CDC_TX1_DMIC_CTL__POR,
+	[SITAR_A_CDC_SRC1_PDA_CFG] = SITAR_A_CDC_SRC1_PDA_CFG__POR,
+	[SITAR_A_CDC_SRC1_FS_CTL] = SITAR_A_CDC_SRC1_FS_CTL__POR,
+	[SITAR_A_CDC_RX1_B1_CTL] = SITAR_A_CDC_RX1_B1_CTL__POR,
+	[SITAR_A_CDC_RX1_B2_CTL] = SITAR_A_CDC_RX1_B2_CTL__POR,
+	[SITAR_A_CDC_RX1_B3_CTL] = SITAR_A_CDC_RX1_B3_CTL__POR,
+	[SITAR_A_CDC_RX1_B4_CTL] = SITAR_A_CDC_RX1_B4_CTL__POR,
+	[SITAR_A_CDC_RX1_B5_CTL] = SITAR_A_CDC_RX1_B5_CTL__POR,
+	[SITAR_A_CDC_RX1_B6_CTL] = SITAR_A_CDC_RX1_B6_CTL__POR,
+	[SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
+	[SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
+	[SITAR_A_CDC_CLK_ANC_RESET_CTL] = SITAR_A_CDC_CLK_ANC_RESET_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_RESET_CTL] = SITAR_A_CDC_CLK_RX_RESET_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_RESET_B1_CTL] =
+		SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_RESET_B2_CTL] =
+		SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR,
+	[SITAR_A_CDC_CLK_DMIC_CTL] = SITAR_A_CDC_CLK_DMIC_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_I2S_CTL] = SITAR_A_CDC_CLK_RX_I2S_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_I2S_CTL] = SITAR_A_CDC_CLK_TX_I2S_CTL__POR,
+	[SITAR_A_CDC_CLK_OTHR_RESET_CTL] = SITAR_A_CDC_CLK_OTHR_RESET_CTL__POR,
+	[SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
+		SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
+	[SITAR_A_CDC_CLK_OTHR_CTL] = SITAR_A_CDC_CLK_OTHR_CTL__POR,
+	[SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL] =
+		SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL__POR,
+	[SITAR_A_CDC_CLK_ANC_CLK_EN_CTL] = SITAR_A_CDC_CLK_ANC_CLK_EN_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_B1_CTL] = SITAR_A_CDC_CLK_RX_B1_CTL__POR,
+	[SITAR_A_CDC_CLK_RX_B2_CTL] = SITAR_A_CDC_CLK_RX_B2_CTL__POR,
+	[SITAR_A_CDC_CLK_MCLK_CTL] = SITAR_A_CDC_CLK_MCLK_CTL__POR,
+	[SITAR_A_CDC_CLK_PDM_CTL] = SITAR_A_CDC_CLK_PDM_CTL__POR,
+	[SITAR_A_CDC_CLK_SD_CTL] = SITAR_A_CDC_CLK_SD_CTL__POR,
+	[SITAR_A_CDC_CLK_LP_CTL] = SITAR_A_CDC_CLK_LP_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL] =
+		SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR,
+	[SITAR_A_CDC_CLSG_GAIN_THRESH_CTL] =
+		SITAR_A_CDC_CLSG_GAIN_THRESH_CTL__POR,
+	[SITAR_A_CDC_CLSG_TIMER_B1_CFG] = SITAR_A_CDC_CLSG_TIMER_B1_CFG__POR,
+	[SITAR_A_CDC_CLSG_TIMER_B2_CFG] = SITAR_A_CDC_CLSG_TIMER_B2_CFG__POR,
+	[SITAR_A_CDC_CLSG_CTL] = SITAR_A_CDC_CLSG_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B1_CTL] = SITAR_A_CDC_IIR1_GAIN_B1_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B2_CTL] = SITAR_A_CDC_IIR1_GAIN_B2_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B3_CTL] = SITAR_A_CDC_IIR1_GAIN_B3_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B4_CTL] = SITAR_A_CDC_IIR1_GAIN_B4_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B5_CTL] = SITAR_A_CDC_IIR1_GAIN_B5_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B6_CTL] = SITAR_A_CDC_IIR1_GAIN_B6_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B7_CTL] = SITAR_A_CDC_IIR1_GAIN_B7_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_B8_CTL] = SITAR_A_CDC_IIR1_GAIN_B8_CTL__POR,
+	[SITAR_A_CDC_IIR1_CTL] = SITAR_A_CDC_IIR1_CTL__POR,
+	[SITAR_A_CDC_IIR1_GAIN_TIMER_CTL] =
+		SITAR_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B1_CTL] = SITAR_A_CDC_IIR1_COEF_B1_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B2_CTL] = SITAR_A_CDC_IIR1_COEF_B2_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B3_CTL] = SITAR_A_CDC_IIR1_COEF_B3_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B4_CTL] = SITAR_A_CDC_IIR1_COEF_B4_CTL__POR,
+	[SITAR_A_CDC_IIR1_COEF_B5_CTL] = SITAR_A_CDC_IIR1_COEF_B5_CTL__POR,
+	[SITAR_A_CDC_TOP_GAIN_UPDATE] = SITAR_A_CDC_TOP_GAIN_UPDATE__POR,
+	[SITAR_A_CDC_TOP_RDAC_DOUT_CTL] = SITAR_A_CDC_TOP_RDAC_DOUT_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B1_CTL] = SITAR_A_CDC_DEBUG_B1_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B2_CTL] = SITAR_A_CDC_DEBUG_B2_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B3_CTL] = SITAR_A_CDC_DEBUG_B3_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B4_CTL] = SITAR_A_CDC_DEBUG_B4_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B5_CTL] = SITAR_A_CDC_DEBUG_B5_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B6_CTL] = SITAR_A_CDC_DEBUG_B6_CTL__POR,
+	[SITAR_A_CDC_DEBUG_B7_CTL] = SITAR_A_CDC_DEBUG_B7_CTL__POR,
+	[SITAR_A_CDC_COMP1_B1_CTL] = SITAR_A_CDC_COMP1_B1_CTL__POR,
+	[SITAR_A_CDC_COMP1_B2_CTL] = SITAR_A_CDC_COMP1_B2_CTL__POR,
+	[SITAR_A_CDC_COMP1_B3_CTL] = SITAR_A_CDC_COMP1_B3_CTL__POR,
+	[SITAR_A_CDC_COMP1_B4_CTL] = SITAR_A_CDC_COMP1_B4_CTL__POR,
+	[SITAR_A_CDC_COMP1_B5_CTL] = SITAR_A_CDC_COMP1_B5_CTL__POR,
+	[SITAR_A_CDC_COMP1_B6_CTL] = SITAR_A_CDC_COMP1_B6_CTL__POR,
+	[SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+		SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+	[SITAR_A_CDC_COMP1_FS_CFG] = SITAR_A_CDC_COMP1_FS_CFG__POR,
+	[SITAR_A_CDC_CONN_RX1_B1_CTL] = SITAR_A_CDC_CONN_RX1_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX1_B2_CTL] = SITAR_A_CDC_CONN_RX1_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_RX1_B3_CTL] = SITAR_A_CDC_CONN_RX1_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_RX2_B1_CTL] = SITAR_A_CDC_CONN_RX2_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX2_B2_CTL] = SITAR_A_CDC_CONN_RX2_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_RX2_B3_CTL] = SITAR_A_CDC_CONN_RX2_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_RX3_B1_CTL] = SITAR_A_CDC_CONN_RX3_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX3_B2_CTL] = SITAR_A_CDC_CONN_RX3_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_RX3_B3_CTL] = SITAR_A_CDC_CONN_RX3_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_ANC_B1_CTL] = SITAR_A_CDC_CONN_ANC_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_ANC_B2_CTL] = SITAR_A_CDC_CONN_ANC_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_B1_CTL] = SITAR_A_CDC_CONN_TX_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_B2_CTL] = SITAR_A_CDC_CONN_TX_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B1_CTL] = SITAR_A_CDC_CONN_EQ1_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B2_CTL] = SITAR_A_CDC_CONN_EQ1_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B3_CTL] = SITAR_A_CDC_CONN_EQ1_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ1_B4_CTL] = SITAR_A_CDC_CONN_EQ1_B4_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B1_CTL] = SITAR_A_CDC_CONN_EQ2_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B2_CTL] = SITAR_A_CDC_CONN_EQ2_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B3_CTL] = SITAR_A_CDC_CONN_EQ2_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_EQ2_B4_CTL] = SITAR_A_CDC_CONN_EQ2_B4_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC1_B1_CTL] = SITAR_A_CDC_CONN_SRC1_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC1_B2_CTL] = SITAR_A_CDC_CONN_SRC1_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC2_B1_CTL] = SITAR_A_CDC_CONN_SRC2_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_SRC2_B2_CTL] = SITAR_A_CDC_CONN_SRC2_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B1_CTL] = SITAR_A_CDC_CONN_TX_SB_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B2_CTL] = SITAR_A_CDC_CONN_TX_SB_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B3_CTL] = SITAR_A_CDC_CONN_TX_SB_B3_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B4_CTL] = SITAR_A_CDC_CONN_TX_SB_B4_CTL__POR,
+	[SITAR_A_CDC_CONN_TX_SB_B5_CTL] = SITAR_A_CDC_CONN_TX_SB_B5_CTL__POR,
+	[SITAR_A_CDC_CONN_RX_SB_B1_CTL] = SITAR_A_CDC_CONN_RX_SB_B1_CTL__POR,
+	[SITAR_A_CDC_CONN_RX_SB_B2_CTL] = SITAR_A_CDC_CONN_RX_SB_B2_CTL__POR,
+	[SITAR_A_CDC_CONN_CLSG_CTL] = SITAR_A_CDC_CONN_CLSG_CTL__POR,
+	[SITAR_A_CDC_CONN_SPARE] = SITAR_A_CDC_CONN_SPARE__POR,
+	[SITAR_A_CDC_MBHC_EN_CTL] = SITAR_A_CDC_MBHC_EN_CTL__POR,
+	[SITAR_A_CDC_MBHC_FIR_B1_CFG] = SITAR_A_CDC_MBHC_FIR_B1_CFG__POR,
+	[SITAR_A_CDC_MBHC_FIR_B2_CFG] = SITAR_A_CDC_MBHC_FIR_B2_CFG__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B1_CTL] = SITAR_A_CDC_MBHC_TIMER_B1_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B2_CTL] = SITAR_A_CDC_MBHC_TIMER_B2_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B3_CTL] = SITAR_A_CDC_MBHC_TIMER_B3_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B4_CTL] = SITAR_A_CDC_MBHC_TIMER_B4_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B5_CTL] = SITAR_A_CDC_MBHC_TIMER_B5_CTL__POR,
+	[SITAR_A_CDC_MBHC_TIMER_B6_CTL] = SITAR_A_CDC_MBHC_TIMER_B6_CTL__POR,
+	[SITAR_A_CDC_MBHC_B1_STATUS] = SITAR_A_CDC_MBHC_B1_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B2_STATUS] = SITAR_A_CDC_MBHC_B2_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B3_STATUS] = SITAR_A_CDC_MBHC_B3_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B4_STATUS] = SITAR_A_CDC_MBHC_B4_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B5_STATUS] = SITAR_A_CDC_MBHC_B5_STATUS__POR,
+	[SITAR_A_CDC_MBHC_B1_CTL] = SITAR_A_CDC_MBHC_B1_CTL__POR,
+	[SITAR_A_CDC_MBHC_B2_CTL] = SITAR_A_CDC_MBHC_B2_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B1_CTL] = SITAR_A_CDC_MBHC_VOLT_B1_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B2_CTL] = SITAR_A_CDC_MBHC_VOLT_B2_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B3_CTL] = SITAR_A_CDC_MBHC_VOLT_B3_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B4_CTL] = SITAR_A_CDC_MBHC_VOLT_B4_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B5_CTL] = SITAR_A_CDC_MBHC_VOLT_B5_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B6_CTL] = SITAR_A_CDC_MBHC_VOLT_B6_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B7_CTL] = SITAR_A_CDC_MBHC_VOLT_B7_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B8_CTL] = SITAR_A_CDC_MBHC_VOLT_B8_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B9_CTL] = SITAR_A_CDC_MBHC_VOLT_B9_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B10_CTL] = SITAR_A_CDC_MBHC_VOLT_B10_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B11_CTL] = SITAR_A_CDC_MBHC_VOLT_B11_CTL__POR,
+	[SITAR_A_CDC_MBHC_VOLT_B12_CTL] = SITAR_A_CDC_MBHC_VOLT_B12_CTL__POR,
+	[SITAR_A_CDC_MBHC_CLK_CTL] = SITAR_A_CDC_MBHC_CLK_CTL__POR,
+	[SITAR_A_CDC_MBHC_INT_CTL] = SITAR_A_CDC_MBHC_INT_CTL__POR,
+	[SITAR_A_CDC_MBHC_DEBUG_CTL] = SITAR_A_CDC_MBHC_DEBUG_CTL__POR,
+	[SITAR_A_CDC_MBHC_SPARE] = SITAR_A_CDC_MBHC_SPARE__POR,
+};
+
+const u8 sitar_reg_readable[SITAR_CACHE_SIZE] = {
+	[WCD9XXX_A_CHIP_CTL] = 1,
+	[WCD9XXX_A_CHIP_STATUS] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_0] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_1] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_2] = 1,
+	[WCD9XXX_A_CHIP_ID_BYTE_3] = 1,
+	[WCD9XXX_A_CHIP_VERSION] = 1,
+	[WCD9XXX_A_SB_VERSION] = 1,
+	[WCD9XXX_A_SLAVE_ID_1] = 1,
+	[WCD9XXX_A_SLAVE_ID_2] = 1,
+	[WCD9XXX_A_SLAVE_ID_3] = 1,
+	[SITAR_A_PIN_CTL_OE0] = 1,
+	[SITAR_A_PIN_CTL_OE1] = 1,
+	[SITAR_A_PIN_CTL_DATA0] = 1,
+	[SITAR_A_PIN_CTL_DATA1] = 1,
+	[SITAR_A_HDRIVE_GENERIC] = 1,
+	[SITAR_A_HDRIVE_OVERRIDE] = 1,
+	[SITAR_A_ANA_CSR_WAIT_STATE] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL0] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL1] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL2] = 1,
+	[SITAR_A_PROCESS_MONITOR_CTL3] = 1,
+	[SITAR_A_QFUSE_CTL] = 1,
+	[SITAR_A_QFUSE_STATUS] = 1,
+	[SITAR_A_QFUSE_DATA_OUT0] = 1,
+	[SITAR_A_QFUSE_DATA_OUT1] = 1,
+	[SITAR_A_QFUSE_DATA_OUT2] = 1,
+	[SITAR_A_QFUSE_DATA_OUT3] = 1,
+	[SITAR_A_CDC_CTL] = 1,
+	[SITAR_A_LEAKAGE_CTL] = 1,
+	[SITAR_A_INTR_MODE] = 1,
+	[SITAR_A_INTR_MASK0] = 1,
+	[SITAR_A_INTR_MASK1] = 1,
+	[SITAR_A_INTR_MASK2] = 1,
+	[SITAR_A_INTR_STATUS0] = 1,
+	[SITAR_A_INTR_STATUS1] = 1,
+	[SITAR_A_INTR_STATUS2] = 1,
+	[SITAR_A_INTR_LEVEL0] = 1,
+	[SITAR_A_INTR_LEVEL1] = 1,
+	[SITAR_A_INTR_LEVEL2] = 1,
+	[SITAR_A_INTR_TEST0] = 1,
+	[SITAR_A_INTR_TEST1] = 1,
+	[SITAR_A_INTR_TEST2] = 1,
+	[SITAR_A_INTR_SET0] = 1,
+	[SITAR_A_INTR_SET1] = 1,
+	[SITAR_A_INTR_SET2] = 1,
+	[SITAR_A_CDC_TX_I2S_SCK_MODE] = 1,
+	[SITAR_A_CDC_TX_I2S_WS_MODE] = 1,
+	[SITAR_A_CDC_DMIC_DATA0_MODE] = 1,
+	[SITAR_A_CDC_DMIC_CLK0_MODE] = 1,
+	[SITAR_A_CDC_DMIC_DATA1_MODE] = 1,
+	[SITAR_A_CDC_DMIC_CLK1_MODE] = 1,
+	[SITAR_A_CDC_TX_I2S_SD0_MODE] = 1,
+	[SITAR_A_CDC_INTR_MODE] = 1,
+	[SITAR_A_CDC_RX_I2S_SD0_MODE] = 1,
+	[SITAR_A_CDC_RX_I2S_SD1_MODE] = 1,
+	[SITAR_A_BIAS_REF_CTL] = 1,
+	[SITAR_A_BIAS_CENTRAL_BG_CTL] = 1,
+	[SITAR_A_BIAS_PRECHRG_CTL] = 1,
+	[SITAR_A_BIAS_CURR_CTL_1] = 1,
+	[SITAR_A_BIAS_CURR_CTL_2] = 1,
+	[SITAR_A_BIAS_OSC_BG_CTL] = 1,
+	[SITAR_A_CLK_BUFF_EN1] = 1,
+	[SITAR_A_CLK_BUFF_EN2] = 1,
+	[SITAR_A_LDO_H_MODE_1] = 1,
+	[SITAR_A_LDO_H_MODE_2] = 1,
+	[SITAR_A_LDO_H_LOOP_CTL] = 1,
+	[SITAR_A_LDO_H_COMP_1] = 1,
+	[SITAR_A_LDO_H_COMP_2] = 1,
+	[SITAR_A_LDO_H_BIAS_1] = 1,
+	[SITAR_A_LDO_H_BIAS_2] = 1,
+	[SITAR_A_LDO_H_BIAS_3] = 1,
+	[SITAR_A_MICB_CFILT_1_CTL] = 1,
+	[SITAR_A_MICB_CFILT_1_VAL] = 1,
+	[SITAR_A_MICB_CFILT_1_PRECHRG] = 1,
+	[SITAR_A_MICB_1_CTL] = 1,
+	[SITAR_A_MICB_1_INT_RBIAS] = 1,
+	[SITAR_A_MICB_1_MBHC] = 1,
+	[SITAR_A_MICB_CFILT_2_CTL] = 1,
+	[SITAR_A_MICB_CFILT_2_VAL] = 1,
+	[SITAR_A_MICB_CFILT_2_PRECHRG] = 1,
+	[SITAR_A_MICB_2_CTL] = 1,
+	[SITAR_A_MICB_2_INT_RBIAS] = 1,
+	[SITAR_A_MICB_2_MBHC] = 1,
+	[SITAR_A_TX_COM_BIAS] = 1,
+	[SITAR_A_MBHC_SCALING_MUX_1] = 1,
+	[SITAR_A_MBHC_SCALING_MUX_2] = 1,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_1] = 1,
+	[SITAR_A_TX_SUP_SWITCH_CTRL_2] = 1,
+	[SITAR_A_TX_1_2_EN] = 1,
+	[SITAR_A_TX_1_2_TEST_EN] = 1,
+	[SITAR_A_TX_1_2_ADC_CH1] = 1,
+	[SITAR_A_TX_1_2_ADC_CH2] = 1,
+	[SITAR_A_TX_1_2_ATEST_REFCTRL] = 1,
+	[SITAR_A_TX_1_2_TEST_CTL] = 1,
+	[SITAR_A_TX_1_2_TEST_BLOCK_EN] = 1,
+	[SITAR_A_TX_1_2_TXFE_CLKDIV] = 1,
+	[SITAR_A_TX_1_2_SAR_ERR_CH1] = 1,
+	[SITAR_A_TX_1_2_SAR_ERR_CH2] = 1,
+	[SITAR_A_TX_3_EN] = 1,
+	[SITAR_A_TX_3_TEST_EN] = 1,
+	[SITAR_A_TX_3_ADC] = 1,
+	[SITAR_A_TX_3_MBHC_ATEST_REFCTRL] = 1,
+	[SITAR_A_TX_3_TEST_CTL] = 1,
+	[SITAR_A_TX_3_TEST_BLOCK_EN] = 1,
+	[SITAR_A_TX_3_TXFE_CKDIV] = 1,
+	[SITAR_A_TX_3_SAR_ERR] = 1,
+	[SITAR_A_TX_4_MBHC_EN] = 1,
+	[SITAR_A_TX_4_MBHC_ADC] = 1,
+	[SITAR_A_TX_4_MBHC_TEST_CTL] = 1,
+	[SITAR_A_TX_4_MBHC_SAR_ERR] = 1,
+	[SITAR_A_TX_4_TXFE_CLKDIV] = 1,
+	[SITAR_A_AUX_COM_CTL] = 1,
+	[SITAR_A_AUX_COM_ATEST] = 1,
+	[SITAR_A_AUX_L_EN] = 1,
+	[SITAR_A_AUX_L_GAIN] = 1,
+	[SITAR_A_AUX_L_PA_CONN] = 1,
+	[SITAR_A_AUX_L_PA_CONN_INV] = 1,
+	[SITAR_A_AUX_R_EN] = 1,
+	[SITAR_A_AUX_R_GAIN] = 1,
+	[SITAR_A_AUX_R_PA_CONN] = 1,
+	[SITAR_A_AUX_R_PA_CONN_INV] = 1,
+	[SITAR_A_CP_EN] = 1,
+	[SITAR_A_CP_CLK] = 1,
+	[SITAR_A_CP_STATIC] = 1,
+	[SITAR_A_CP_DCC1] = 1,
+	[SITAR_A_CP_DCC3] = 1,
+	[SITAR_A_CP_ATEST] = 1,
+	[SITAR_A_CP_DTEST] = 1,
+	[SITAR_A_RX_COM_TIMER_DIV] = 1,
+	[SITAR_A_RX_COM_OCP_CTL] = 1,
+	[SITAR_A_RX_COM_OCP_COUNT] = 1,
+	[SITAR_A_RX_COM_DAC_CTL] = 1,
+	[SITAR_A_RX_COM_BIAS] = 1,
+	[SITAR_A_RX_HPH_BIAS_PA] = 1,
+	[SITAR_A_RX_HPH_BIAS_LDO] = 1,
+	[SITAR_A_RX_HPH_BIAS_CNP] = 1,
+	[SITAR_A_RX_HPH_BIAS_WG] = 1,
+	[SITAR_A_RX_HPH_OCP_CTL] = 1,
+	[SITAR_A_RX_HPH_CNP_EN] = 1,
+	[SITAR_A_RX_HPH_CNP_WG_CTL] = 1,
+	[SITAR_A_RX_HPH_CNP_WG_TIME] = 1,
+	[SITAR_A_RX_HPH_L_GAIN] = 1,
+	[SITAR_A_RX_HPH_L_TEST] = 1,
+	[SITAR_A_RX_HPH_L_PA_CTL] = 1,
+	[SITAR_A_RX_HPH_L_DAC_CTL] = 1,
+	[SITAR_A_RX_HPH_L_ATEST] = 1,
+	[SITAR_A_RX_HPH_L_STATUS] = 1,
+	[SITAR_A_RX_HPH_R_GAIN] = 1,
+	[SITAR_A_RX_HPH_R_TEST] = 1,
+	[SITAR_A_RX_HPH_R_PA_CTL] = 1,
+	[SITAR_A_RX_HPH_R_DAC_CTL] = 1,
+	[SITAR_A_RX_HPH_R_ATEST] = 1,
+	[SITAR_A_RX_HPH_R_STATUS] = 1,
+	[SITAR_A_RX_EAR_BIAS_PA] = 1,
+	[SITAR_A_RX_EAR_BIAS_CMBUFF] = 1,
+	[SITAR_A_RX_EAR_EN] = 1,
+	[SITAR_A_RX_EAR_GAIN] = 1,
+	[SITAR_A_RX_EAR_CMBUFF] = 1,
+	[SITAR_A_RX_EAR_ICTL] = 1,
+	[SITAR_A_RX_EAR_CCOMP] = 1,
+	[SITAR_A_RX_EAR_VCM] = 1,
+	[SITAR_A_RX_EAR_CNP] = 1,
+	[SITAR_A_RX_EAR_ATEST] = 1,
+	[SITAR_A_RX_EAR_STATUS] = 1,
+	[SITAR_A_RX_LINE_BIAS_PA] = 1,
+	[SITAR_A_RX_LINE_BIAS_LDO] = 1,
+	[SITAR_A_RX_LINE_BIAS_CNP1] = 1,
+	[SITAR_A_RX_LINE_COM] = 1,
+	[SITAR_A_RX_LINE_CNP_EN] = 1,
+	[SITAR_A_RX_LINE_CNP_WG_CTL] = 1,
+	[SITAR_A_RX_LINE_CNP_WG_TIME] = 1,
+	[SITAR_A_RX_LINE_1_GAIN] = 1,
+	[SITAR_A_RX_LINE_1_TEST] = 1,
+	[SITAR_A_RX_LINE_1_DAC_CTL] = 1,
+	[SITAR_A_RX_LINE_1_STATUS] = 1,
+	[SITAR_A_RX_LINE_2_GAIN] = 1,
+	[SITAR_A_RX_LINE_2_TEST] = 1,
+	[SITAR_A_RX_LINE_2_DAC_CTL] = 1,
+	[SITAR_A_RX_LINE_2_STATUS] = 1,
+	[SITAR_A_RX_LINE_BIAS_CNP2] = 1,
+	[SITAR_A_RX_LINE_OCP_CTL] = 1,
+	[SITAR_A_RX_LINE_1_PA_CTL] = 1,
+	[SITAR_A_RX_LINE_2_PA_CTL] = 1,
+	[SITAR_A_RX_LINE_CNP_DBG] = 1,
+	[SITAR_A_MBHC_HPH] = 1,
+	[SITAR_A_RC_OSC_FREQ] = 1,
+	[SITAR_A_RC_OSC_TEST] = 1,
+	[SITAR_A_RC_OSC_STATUS] = 1,
+	[SITAR_A_RC_OSC_TUNER] = 1,
+	[SITAR_A_CDC_ANC1_CTL] = 1,
+	[SITAR_A_CDC_ANC1_SHIFT] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B1_CTL] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B2_CTL] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B3_CTL] = 1,
+	[SITAR_A_CDC_ANC1_IIR_B4_CTL] = 1,
+	[SITAR_A_CDC_ANC1_LPF_B1_CTL] = 1,
+	[SITAR_A_CDC_ANC1_LPF_B2_CTL] = 1,
+	[SITAR_A_CDC_ANC1_LPF_B3_CTL] = 1,
+	[SITAR_A_CDC_ANC1_SPARE] = 1,
+	[SITAR_A_CDC_ANC1_SMLPF_CTL] = 1,
+	[SITAR_A_CDC_ANC1_DCFLT_CTL] = 1,
+	[SITAR_A_CDC_TX1_VOL_CTL_TIMER] = 1,
+	[SITAR_A_CDC_TX1_VOL_CTL_GAIN] = 1,
+	[SITAR_A_CDC_TX1_VOL_CTL_CFG] = 1,
+	[SITAR_A_CDC_TX1_MUX_CTL] = 1,
+	[SITAR_A_CDC_TX1_CLK_FS_CTL] = 1,
+	[SITAR_A_CDC_TX1_DMIC_CTL] = 1,
+	[SITAR_A_CDC_SRC1_PDA_CFG] = 1,
+	[SITAR_A_CDC_SRC1_FS_CTL] = 1,
+	[SITAR_A_CDC_RX1_B1_CTL] = 1,
+	[SITAR_A_CDC_RX1_B2_CTL] = 1,
+	[SITAR_A_CDC_RX1_B3_CTL] = 1,
+	[SITAR_A_CDC_RX1_B4_CTL] = 1,
+	[SITAR_A_CDC_RX1_B5_CTL] = 1,
+	[SITAR_A_CDC_RX1_B6_CTL] = 1,
+	[SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
+	[SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
+	[SITAR_A_CDC_CLK_ANC_RESET_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_RESET_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_RESET_B2_CTL] = 1,
+	[SITAR_A_CDC_CLK_DMIC_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_I2S_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_I2S_CTL] = 1,
+	[SITAR_A_CDC_CLK_OTHR_RESET_CTL] = 1,
+	[SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
+	[SITAR_A_CDC_CLK_OTHR_CTL] = 1,
+	[SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL] = 1,
+	[SITAR_A_CDC_CLK_ANC_CLK_EN_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_B1_CTL] = 1,
+	[SITAR_A_CDC_CLK_RX_B2_CTL] = 1,
+	[SITAR_A_CDC_CLK_MCLK_CTL] = 1,
+	[SITAR_A_CDC_CLK_PDM_CTL] = 1,
+	[SITAR_A_CDC_CLK_SD_CTL] = 1,
+	[SITAR_A_CDC_CLK_LP_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL] = 1,
+	[SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL] = 1,
+	[SITAR_A_CDC_CLSG_GAIN_THRESH_CTL] = 1,
+	[SITAR_A_CDC_CLSG_TIMER_B1_CFG] = 1,
+	[SITAR_A_CDC_CLSG_TIMER_B2_CFG] = 1,
+	[SITAR_A_CDC_CLSG_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B1_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B2_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B3_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B4_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B5_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B6_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B7_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_B8_CTL] = 1,
+	[SITAR_A_CDC_IIR1_CTL] = 1,
+	[SITAR_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B1_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B2_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B3_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B4_CTL] = 1,
+	[SITAR_A_CDC_IIR1_COEF_B5_CTL] = 1,
+	[SITAR_A_CDC_TOP_GAIN_UPDATE] = 1,
+	[SITAR_A_CDC_TOP_RDAC_DOUT_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B1_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B2_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B3_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B4_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B5_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B6_CTL] = 1,
+	[SITAR_A_CDC_DEBUG_B7_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B1_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B2_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B3_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B4_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B5_CTL] = 1,
+	[SITAR_A_CDC_COMP1_B6_CTL] = 1,
+	[SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
+	[SITAR_A_CDC_COMP1_FS_CFG] = 1,
+	[SITAR_A_CDC_CONN_RX1_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX1_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX1_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX2_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX2_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX2_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX3_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX3_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX3_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_ANC_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_ANC_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ1_B4_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_EQ2_B4_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC1_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC1_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC2_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_SRC2_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B3_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B4_CTL] = 1,
+	[SITAR_A_CDC_CONN_TX_SB_B5_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX_SB_B1_CTL] = 1,
+	[SITAR_A_CDC_CONN_RX_SB_B2_CTL] = 1,
+	[SITAR_A_CDC_CONN_CLSG_CTL] = 1,
+	[SITAR_A_CDC_CONN_SPARE] = 1,
+	[SITAR_A_CDC_MBHC_EN_CTL] = 1,
+	[SITAR_A_CDC_MBHC_FIR_B1_CFG] = 1,
+	[SITAR_A_CDC_MBHC_FIR_B2_CFG] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B1_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B2_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B3_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B4_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B5_CTL] = 1,
+	[SITAR_A_CDC_MBHC_TIMER_B6_CTL] = 1,
+	[SITAR_A_CDC_MBHC_B1_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B2_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B3_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B4_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B5_STATUS] = 1,
+	[SITAR_A_CDC_MBHC_B1_CTL] = 1,
+	[SITAR_A_CDC_MBHC_B2_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B1_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B2_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B3_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B4_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B5_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B6_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B7_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B8_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B9_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B10_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B11_CTL] = 1,
+	[SITAR_A_CDC_MBHC_VOLT_B12_CTL] = 1,
+	[SITAR_A_CDC_MBHC_CLK_CTL] = 1,
+	[SITAR_A_CDC_MBHC_INT_CTL] = 1,
+	[SITAR_A_CDC_MBHC_DEBUG_CTL] = 1,
+	[SITAR_A_CDC_MBHC_SPARE] = 1,
+};
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
new file mode 100644
index 0000000..1d93d7a
--- /dev/null
+++ b/sound/soc/codecs/wcd9304.c
@@ -0,0 +1,3593 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include "wcd9304.h"
+
+#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
+			SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
+
+#define NUM_DECIMATORS 4
+#define NUM_INTERPOLATORS 3
+#define BITS_PER_REG 8
+#define AIF1_PB 1
+#define AIF1_CAP 2
+#define NUM_CODEC_DAIS 2
+
+struct sitar_codec_dai_data {
+	u32 rate;
+	u32 *ch_num;
+	u32 ch_act;
+	u32 ch_tot;
+};
+#define SITAR_CFILT_FAST_MODE 0x00
+#define SITAR_CFILT_SLOW_MODE 0x40
+
+
+#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
+
+#define SITAR_I2S_MASTER_MODE_MASK 0x08
+
+#define SITAR_OCP_ATTEMPT 1
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver sitar_dai[];
+static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event);
+static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event);
+
+enum sitar_bandgap_type {
+	SITAR_BANDGAP_OFF = 0,
+	SITAR_BANDGAP_AUDIO_MODE,
+	SITAR_BANDGAP_MBHC_MODE,
+};
+
+struct mbhc_micbias_regs {
+	u16 cfilt_val;
+	u16 cfilt_ctl;
+	u16 mbhc_reg;
+	u16 int_rbias;
+	u16 ctl_reg;
+	u8 cfilt_sel;
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR1 = 0,
+	IIR2,
+	IIR_MAX,
+};
+/* Codec supports 5 bands */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_MAX,
+};
+
+/* Flags to track of PA and DAC state.
+ * PA and DAC should be tracked separately as AUXPGA loopback requires
+ * only PA to be turned on without DAC being on. */
+enum sitar_priv_ack_flags {
+	SITAR_HPHL_PA_OFF_ACK = 0,
+	SITAR_HPHR_PA_OFF_ACK,
+	SITAR_HPHL_DAC_OFF_ACK,
+	SITAR_HPHR_DAC_OFF_ACK
+};
+
+struct sitar_priv {
+	struct snd_soc_codec *codec;
+	u32 adc_count;
+	u32 cfilt1_cnt;
+	u32 cfilt2_cnt;
+	u32 cfilt3_cnt;
+	u32 rx_bias_count;
+	enum sitar_bandgap_type bandgap_type;
+	bool mclk_enabled;
+	bool clock_active;
+	bool config_mode_active;
+	bool mbhc_polling_active;
+	bool fake_insert_context;
+	int buttons_pressed;
+
+	struct sitar_mbhc_calibration *calibration;
+
+	struct snd_soc_jack *headset_jack;
+	struct snd_soc_jack *button_jack;
+
+	struct wcd9xxx_pdata *pdata;
+	u32 anc_slot;
+
+	bool no_mic_headset_override;
+	/* Delayed work to report long button press */
+	struct delayed_work btn0_dwork;
+
+	struct mbhc_micbias_regs mbhc_bias_regs;
+	u8 cfilt_k_value;
+	bool mbhc_micbias_switched;
+
+	/* track PA/DAC state */
+	unsigned long hph_pa_dac_state;
+
+	/*track sitar interface type*/
+	u8 intf_type;
+
+	u32 hph_status; /* track headhpone status */
+	/* define separate work for left and right headphone OCP to avoid
+	 * additional checking on which OCP event to report so no locking
+	 * to ensure synchronization is required
+	 */
+	struct work_struct hphlocp_work; /* reporting left hph ocp off */
+	struct work_struct hphrocp_work; /* reporting right hph ocp off */
+
+	/* pm_cnt holds number of sleep lock holders + 1
+	 * so if pm_cnt is 1 system is sleep-able. */
+	atomic_t pm_cnt;
+	wait_queue_head_t pm_wq;
+
+	u8 hphlocp_cnt; /* headphone left ocp retry */
+	u8 hphrocp_cnt; /* headphone right ocp retry */
+	/* num of slim ports required */
+	struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
+};
+
+#ifdef CONFIG_DEBUG_FS
+struct sitar_priv *debug_sitar_priv;
+#endif
+
+
+static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
+
+	ear_pa_gain = ear_pa_gain >> 5;
+
+	if (ear_pa_gain == 0x00) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (ear_pa_gain == 0x04) {
+		ucontrol->value.integer.value[0] = 1;
+	} else  {
+		pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+				__func__, ear_pa_gain);
+		return -EINVAL;
+	}
+
+	pr_err("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+
+	return 0;
+}
+
+static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s: ucontrol->value.integer.value[0]  = %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		ear_pa_gain = 0x00;
+		break;
+	case 1:
+		ear_pa_gain = 0x80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, SITAR_A_RX_EAR_GAIN, ear_pa_gain);
+	return 0;
+}
+
+static int sitar_get_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+		(1 << band_idx);
+
+	pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int sitar_put_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	/* Mask first 5 bits, 6-8 are reserved */
+	snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
+		(1 << band_idx), (value << band_idx));
+
+	pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx, value);
+	return 0;
+}
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				int coeff_idx)
+{
+	/* Address does not automatically update if reading */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		0x1F, band_idx * BAND_MAX + coeff_idx);
+
+	/* Mask bits top 2 bits since they are reserved */
+	return ((snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
+		(snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
+		(snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
+		(snd_soc_read(codec,
+		(SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
+		0x3FFFFFFF;
+}
+
+static int sitar_get_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+	ucontrol->value.integer.value[1] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+	ucontrol->value.integer.value[2] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+	ucontrol->value.integer.value[3] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+	ucontrol->value.integer.value[4] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+	pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[1],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[2],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[3],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[4]);
+	return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				int coeff_idx, uint32_t value)
+{
+	/* Mask top 3 bits, 6-8 are reserved */
+	/* Update address manually each time */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+		0x1F, band_idx * BAND_MAX + coeff_idx);
+
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+		0x3F, (value >> 24) & 0x3F);
+
+	/* Isolate 8bits at a time */
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
+		0xFF, (value >> 16) & 0xFF);
+
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
+		0xFF, (value >> 8) & 0xFF);
+
+	snd_soc_update_bits(codec,
+		(SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
+		0xFF, value & 0xFF);
+}
+
+static int sitar_put_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+				ucontrol->value.integer.value[0]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+				ucontrol->value.integer.value[1]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+				ucontrol->value.integer.value[2]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+				ucontrol->value.integer.value[3]);
+	set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+				ucontrol->value.integer.value[4]);
+
+	pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+	return 0;
+}
+
+static const char *sitar_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
+static const struct soc_enum sitar_ear_pa_gain_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, sitar_ear_pa_gain_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char *cf_text[] = {
+	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_dec1_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_rxmix1_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+
+static const struct snd_kcontrol_new sitar_snd_controls[] = {
+
+	SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
+		sitar_pa_gain_get, sitar_pa_gain_put),
+
+	SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
+		line_gain),
+	SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
+		line_gain),
+
+	SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
+		line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
+		line_gain),
+
+	SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
+		-84, 40, digital_gain),
+
+	SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
+		40, digital_gain),
+	SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+
+	SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
+	SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
+
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+
+	SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
+
+	SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
+
+	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+
+	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+	sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+	sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+};
+
+static const char *rx_mix1_text[] = {
+	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
+		"RX5"
+};
+
+static const char *rx_dac1_text[] = {
+	"ZERO", "RX1", "RX2"
+};
+
+static const char *rx_dac2_text[] = {
+	"ZERO", "RX1",
+};
+
+static const char *rx_dac3_text[] = {
+	"ZERO", "RX1", "RX1_INV", "RX2"
+};
+
+static const char *rx_dac4_text[] = {
+	"ZERO", "ON"
+};
+
+static const char *sb_tx1_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC1"
+};
+
+static const char *sb_tx2_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC2"
+};
+
+static const char *sb_tx3_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC3"
+};
+
+static const char *sb_tx5_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC5"
+};
+
+static const char *dec1_mux_text[] = {
+	"ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANCFB1",
+};
+
+static const char *dec2_mux_text[] = {
+	"ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANCFB2",
+};
+
+static const char *dec3_mux_text[] = {
+	"ZERO", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3", "MBADC",
+};
+
+static const char *dec4_mux_text[] = {
+	"ZERO", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3",
+};
+
+static const char *iir1_inp1_text[] = {
+	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
+	"ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
+};
+
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx_dac1_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
+
+static const struct soc_enum rx_dac2_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
+
+static const struct soc_enum rx_dac3_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
+
+static const struct soc_enum rx_dac4_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
+
+static const struct soc_enum sb_tx3_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
+
+static const struct soc_enum sb_tx2_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
+
+static const struct soc_enum sb_tx1_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
+
+static const struct soc_enum dec1_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 2, 8, dec2_mux_text);
+
+static const struct soc_enum dec3_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 4, 8, dec3_mux_text);
+
+static const struct soc_enum dec4_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 6, 8, dec4_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+	SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_dac1_mux =
+	SOC_DAPM_ENUM("RX1 DAC Mux", rx_dac1_enum);
+
+static const struct snd_kcontrol_new rx_dac2_mux =
+	SOC_DAPM_ENUM("RX2 DAC Mux", rx_dac2_enum);
+
+static const struct snd_kcontrol_new rx_dac3_mux =
+	SOC_DAPM_ENUM("RX3 DAC Mux", rx_dac3_enum);
+
+static const struct snd_kcontrol_new rx_dac4_mux =
+	SOC_DAPM_ENUM("RX4 DAC Mux", rx_dac4_enum);
+
+static const struct snd_kcontrol_new sb_tx5_mux =
+	SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx3_mux =
+	SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx2_mux =
+	SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx1_mux =
+	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+
+static const struct snd_kcontrol_new dec1_mux =
+	SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+	SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new dec3_mux =
+	SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+
+static const struct snd_kcontrol_new dec4_mux =
+	SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new dac1_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new hphl_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SITAR_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
+};
+
+static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
+	int enable)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	pr_err("%s %d\n", __func__, enable);
+
+	if (enable) {
+		sitar->adc_count++;
+		snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
+
+	} else {
+		sitar->adc_count--;
+		if (!sitar->adc_count) {
+			if (!sitar->mbhc_polling_active)
+				snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS,
+					0xE0, 0x0);
+		}
+	}
+}
+
+static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 adc_reg;
+
+	pr_err("%s %d\n", __func__, event);
+
+	if (w->reg == SITAR_A_TX_1_2_EN)
+		adc_reg = SITAR_A_TX_1_2_TEST_CTL;
+	else {
+		pr_err("%s: Error, invalid adc register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		sitar_codec_enable_adc_block(codec, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
+			1 << w->shift);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, adc_reg, 0x08, 0x08);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		sitar_codec_enable_adc_block(codec, 0);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 lineout_gain_reg;
+
+	pr_err("%s %d %s\n", __func__, event, w->name);
+
+	switch (w->shift) {
+	case 0:
+		lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
+		break;
+	case 1:
+		lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
+		break;
+	default:
+		pr_err("%s: Error, incorrect lineout register value\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		pr_err("%s: sleeping 16 ms after %s PA turn on\n",
+				__func__, w->name);
+		usleep_range(16000, 16000);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
+	u8 dmic_clk_sel, dmic_clk_en;
+	unsigned int dmic;
+	int ret;
+
+	ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
+	if (ret < 0) {
+		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 1:
+	case 2:
+		dmic_clk_sel = 0x02;
+		dmic_clk_en = 0x01;
+		break;
+	case 3:
+	case 4:
+		dmic_clk_sel = 0x08;
+		dmic_clk_en = 0x04;
+		break;
+
+		break;
+
+	default:
+		pr_err("%s: Invalid DMIC Selection\n", __func__);
+		return -EINVAL;
+	}
+
+	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
+	tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
+
+	pr_err("%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
+
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+				dmic_clk_sel, dmic_clk_sel);
+
+		snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
+
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+				dmic_clk_en, dmic_clk_en);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+				dmic_clk_en, 0);
+		break;
+	}
+	return 0;
+}
+
+
+static void sitar_codec_disable_button_presses(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
+}
+
+static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+	if (!sitar->no_mic_headset_override) {
+		wcd9xxx_enable_irq(codec->control_data,
+				SITAR_IRQ_MBHC_POTENTIAL);
+		wcd9xxx_enable_irq(codec->control_data,
+				SITAR_IRQ_MBHC_RELEASE);
+	} else {
+		sitar_codec_disable_button_presses(codec);
+	}
+}
+
+static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+	if (!sitar->no_mic_headset_override) {
+		wcd9xxx_disable_irq(codec->control_data,
+			SITAR_IRQ_MBHC_POTENTIAL);
+		wcd9xxx_disable_irq(codec->control_data,
+			SITAR_IRQ_MBHC_RELEASE);
+	}
+}
+
+static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
+		int mode)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u8 reg_mode_val, cur_mode_val;
+	bool mbhc_was_polling = false;
+
+	if (mode)
+		reg_mode_val = SITAR_CFILT_FAST_MODE;
+	else
+		reg_mode_val = SITAR_CFILT_SLOW_MODE;
+
+	cur_mode_val = snd_soc_read(codec,
+			sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
+
+	if (cur_mode_val != reg_mode_val) {
+		if (sitar->mbhc_polling_active) {
+			sitar_codec_pause_hs_polling(codec);
+			mbhc_was_polling = true;
+		}
+		snd_soc_update_bits(codec,
+			sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
+		if (mbhc_was_polling)
+			sitar_codec_start_hs_polling(codec);
+		pr_err("%s: CFILT mode change (%x to %x)\n", __func__,
+			cur_mode_val, reg_mode_val);
+	} else {
+		pr_err("%s: CFILT Value is already %x\n",
+			__func__, cur_mode_val);
+	}
+}
+
+static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
+					  u8 cfilt_sel, int inc)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u32 *cfilt_cnt_ptr = NULL;
+	u16 micb_cfilt_reg;
+
+	switch (cfilt_sel) {
+	case SITAR_CFILT1_SEL:
+		cfilt_cnt_ptr = &sitar->cfilt1_cnt;
+		micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
+		break;
+	case SITAR_CFILT2_SEL:
+		cfilt_cnt_ptr = &sitar->cfilt2_cnt;
+		micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
+		break;
+	default:
+		return; /* should not happen */
+	}
+
+	if (inc) {
+		if (!(*cfilt_cnt_ptr)++) {
+			/* Switch CFILT to slow mode if MBHC CFILT being used */
+			if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
+				sitar_codec_switch_cfilt_mode(codec, 0);
+
+			snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
+		}
+	} else {
+		/* check if count not zero, decrement
+		* then check if zero, go ahead disable cfilter
+		*/
+		if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
+			snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
+
+			/* Switch CFILT to fast mode if MBHC CFILT being used */
+			if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
+				sitar_codec_switch_cfilt_mode(codec, 1);
+		}
+	}
+}
+
+static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
+{
+	int rc = -EINVAL;
+	unsigned min_mv, max_mv;
+
+	switch (ldoh_v) {
+	case SITAR_LDOH_1P95_V:
+		min_mv = 160;
+		max_mv = 1800;
+		break;
+	case SITAR_LDOH_2P35_V:
+		min_mv = 200;
+		max_mv = 2200;
+		break;
+	case SITAR_LDOH_2P75_V:
+		min_mv = 240;
+		max_mv = 2600;
+		break;
+	case SITAR_LDOH_2P85_V:
+		min_mv = 250;
+		max_mv = 2700;
+		break;
+	default:
+		goto done;
+	}
+
+	if (cfilt_mv < min_mv || cfilt_mv > max_mv)
+		goto done;
+
+	for (rc = 4; rc <= 44; rc++) {
+		min_mv = max_mv * (rc) / 44;
+		if (min_mv >= cfilt_mv) {
+			rc -= 4;
+			break;
+		}
+	}
+done:
+	return rc;
+}
+
+static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
+{
+	u8 hph_reg_val = 0;
+	hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
+
+	return (hph_reg_val & 0x30) ? true : false;
+}
+
+static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
+{
+	u8 hph_reg_val = 0;
+	if (left)
+		hph_reg_val = snd_soc_read(codec,
+					  SITAR_A_RX_HPH_L_DAC_CTL);
+	else
+		hph_reg_val = snd_soc_read(codec,
+					  SITAR_A_RX_HPH_R_DAC_CTL);
+
+	return (hph_reg_val & 0xC0) ? true : false;
+}
+
+static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
+	int vddio_switch)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	int cfilt_k_val;
+	bool mbhc_was_polling =  false;
+
+	switch (vddio_switch) {
+	case 1:
+		if (sitar->mbhc_polling_active) {
+
+			sitar_codec_pause_hs_polling(codec);
+			/* Enable Mic Bias switch to VDDIO */
+			sitar->cfilt_k_value = snd_soc_read(codec,
+					sitar->mbhc_bias_regs.cfilt_val);
+			cfilt_k_val = sitar_find_k_value(
+					sitar->pdata->micbias.ldoh_v, 1800);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.cfilt_val,
+				0xFC, (cfilt_k_val << 2));
+
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x80, 0x80);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x10, 0x00);
+			sitar_codec_start_hs_polling(codec);
+
+			sitar->mbhc_micbias_switched = true;
+			pr_err("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
+				__func__);
+		}
+		break;
+
+	case 0:
+		if (sitar->mbhc_micbias_switched) {
+			if (sitar->mbhc_polling_active) {
+				sitar_codec_pause_hs_polling(codec);
+				mbhc_was_polling = true;
+			}
+			/* Disable Mic Bias switch to VDDIO */
+			if (sitar->cfilt_k_value != 0)
+				snd_soc_update_bits(codec,
+					sitar->mbhc_bias_regs.cfilt_val, 0XFC,
+					sitar->cfilt_k_value);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x80, 0x00);
+			snd_soc_update_bits(codec,
+				sitar->mbhc_bias_regs.mbhc_reg,	0x10, 0x00);
+
+			if (mbhc_was_polling)
+				sitar_codec_start_hs_polling(codec);
+
+			sitar->mbhc_micbias_switched = false;
+			pr_err("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
+				__func__);
+		}
+		break;
+	}
+}
+
+static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u16 micb_int_reg;
+	int micb_line;
+	u8 cfilt_sel_val = 0;
+	char *internal1_text = "Internal1";
+	char *internal2_text = "Internal2";
+
+	pr_err("%s %d\n", __func__, event);
+	switch (w->reg) {
+	case SITAR_A_MICB_1_CTL:
+		micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
+		cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
+		micb_line = SITAR_MICBIAS1;
+		break;
+	case SITAR_A_MICB_2_CTL:
+		micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
+		cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
+		micb_line = SITAR_MICBIAS2;
+		break;
+	default:
+		pr_err("%s: Error, invalid micbias register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Decide whether to switch the micbias for MBHC */
+		if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
+				&& sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+
+		snd_soc_update_bits(codec, w->reg, 0x1E, 0x0A);
+		sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
+
+		if (strnstr(w->name, internal1_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
+		else if (strnstr(w->name, internal2_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (sitar->mbhc_polling_active &&
+			(sitar->calibration->bias == micb_line)) {
+			sitar_codec_pause_hs_polling(codec);
+			sitar_codec_start_hs_polling(codec);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+
+		if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
+				&& sitar_is_hph_pa_on(codec))
+			sitar_codec_switch_micbias(codec, 1);
+
+		if (strnstr(w->name, internal1_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
+		else if (strnstr(w->name, internal2_text, 30))
+			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
+		sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 dec_reset_reg;
+
+	pr_err("%s %d\n", __func__, event);
+
+	if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
+		dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
+	else {
+		pr_err("%s: Error, incorrect dec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+			1 << w->shift);
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %d %s\n", __func__, event, w->name);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
+			1 << w->shift, 1 << w->shift);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
+			1 << w->shift, 0x0);
+		break;
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(1000, 1000);
+		pr_debug("LDO_H\n");
+		break;
+	}
+	return 0;
+}
+
+static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32  enable)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		sitar->rx_bias_count++;
+		if (sitar->rx_bias_count == 1)
+			snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
+				0x80, 0x80);
+	} else {
+		sitar->rx_bias_count--;
+		if (!sitar->rx_bias_count)
+			snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
+				0x80, 0x00);
+	}
+}
+
+static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		sitar_enable_rx_bias(codec, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		sitar_enable_rx_bias(codec, 0);
+		break;
+	}
+	return 0;
+}
+static int sitar_hphr_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
+				     struct snd_soc_jack *jack, int status,
+				     int mask)
+{
+	/* XXX: wake_lock_timeout()? */
+	snd_soc_jack_report(jack, status, mask);
+}
+
+static void hphocp_off_report(struct sitar_priv *sitar,
+	u32 jack_status, int irq)
+{
+	struct snd_soc_codec *codec;
+
+	if (sitar) {
+		pr_info("%s: clear ocp status %x\n", __func__, jack_status);
+		codec = sitar->codec;
+		sitar->hph_status &= ~jack_status;
+		if (sitar->headset_jack)
+			sitar_snd_soc_jack_report(sitar, sitar->headset_jack,
+						 sitar->hph_status,
+						 SITAR_JACK_MASK);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+		0x00);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+		0x10);
+		/* reset retry counter as PA is turned off signifying
+		* start of new OCP detection session
+		*/
+		if (SITAR_IRQ_HPH_PA_OCPL_FAULT)
+			sitar->hphlocp_cnt = 0;
+		else
+			sitar->hphrocp_cnt = 0;
+		wcd9xxx_enable_irq(codec->control_data, irq);
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+}
+
+static void hphlocp_off_report(struct work_struct *work)
+{
+	struct sitar_priv *sitar = container_of(work, struct sitar_priv,
+		hphlocp_work);
+	hphocp_off_report(sitar, SND_JACK_OC_HPHL, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+}
+
+static void hphrocp_off_report(struct work_struct *work)
+{
+	struct sitar_priv *sitar = container_of(work, struct sitar_priv,
+		hphrocp_work);
+	hphocp_off_report(sitar, SND_JACK_OC_HPHR, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+}
+
+static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u8 mbhc_micb_ctl_val;
+	pr_err("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mbhc_micb_ctl_val = snd_soc_read(codec,
+				sitar->mbhc_bias_regs.ctl_reg);
+
+		if (!(mbhc_micb_ctl_val & 0x80)
+				&& !sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 1);
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* schedule work is required because at the time HPH PA DAPM
+		* event callback is called by DAPM framework, CODEC dapm mutex
+		* would have been locked while snd_soc_jack_report also
+		* attempts to acquire same lock.
+		*/
+		if (w->shift == 5) {
+			clear_bit(SITAR_HPHL_PA_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			if (sitar->hph_status & SND_JACK_OC_HPHL)
+				schedule_work(&sitar->hphlocp_work);
+		} else if (w->shift == 4) {
+			clear_bit(SITAR_HPHR_PA_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+				 &sitar->hph_pa_dac_state);
+			if (sitar->hph_status & SND_JACK_OC_HPHR)
+				schedule_work(&sitar->hphrocp_work);
+		}
+
+		if (sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+
+		pr_err("%s: sleep 10 ms after %s PA disable.\n", __func__,
+				w->name);
+		usleep_range(10000, 10000);
+
+		break;
+	}
+	return 0;
+}
+
+static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
+		struct mbhc_micbias_regs *micbias_regs)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+	unsigned int cfilt;
+
+	switch (calibration->bias) {
+	case SITAR_MICBIAS1:
+		cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
+		micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
+		micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
+		micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
+		break;
+	case SITAR_MICBIAS2:
+		cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
+		micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
+		micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
+		micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
+		break;
+	default:
+		/* Should never reach here */
+		pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
+		return;
+	}
+
+	micbias_regs->cfilt_sel = cfilt;
+
+	switch (cfilt) {
+	case SITAR_CFILT1_SEL:
+		micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
+		micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
+		break;
+	case SITAR_CFILT2_SEL:
+		micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
+		micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
+		break;
+	}
+}
+
+static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_err("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
+			0x01);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
+		usleep_range(200, 200);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
+			0x10);
+		usleep_range(20, 20);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
+			0x00);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
+	4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
+	0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
+	/*RX stuff */
+	SND_SOC_DAPM_OUTPUT("EAR"),
+
+	SND_SOC_DAPM_PGA("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
+		ARRAY_SIZE(dac1_switch)),
+	SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
+	SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM RX5", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Headphone */
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+		sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("HPHL DAC", SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
+		hphl_switch, ARRAY_SIZE(hphl_switch)),
+
+	SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+		sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
+		sitar_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Speaker */
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
+			0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
+			0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+		0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+		0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+		0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac1_mux),
+	SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac2_mux),
+	SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac3_mux),
+	SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac4_mux),
+
+	SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp2_mux),
+
+	SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
+		sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
+		sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+	/* TX */
+	SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+		0),
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
+		sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
+		sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
+		sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC1 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+		&dec1_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
+	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
+	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
+
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimtx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimtx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+				0, sitar_codec_enable_slimtx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+		&dec2_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+		&dec3_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+		&dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* Sidetone */
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR PA"},
+	{"EAR PA", "NULL", "DAC1"},
+	{"DAC1", "Switch", "DAC1 MUX"},
+	{"DAC1", NULL, "CP"},
+	{"DAC1", NULL, "EAR DRIVER"},
+
+	{"LINEOUT1", NULL, "CP"},
+	{"LINEOUT2", NULL, "CP"},
+
+	{"LINEOUT2", NULL, "LINEOUT2 PA"},
+	{"LINEOUT2 PA", "NULL", "DAC3 MUX"},
+
+	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+	{"LINEOUT1 PA", "NULL", "DAC2 MUX"},
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL"},
+	{"HEADPHONE", NULL, "HPHR"},
+
+	{"HPHL", NULL, "HPHL DAC"},
+	{"HPHL DAC", NULL, "DAC4 MUX"},
+	{"HPHR", NULL, "HPHR DAC"},
+	{"HPHL DAC", NULL, "RX3 MIX1"},
+
+	{"DAC1 MUX", "RX1", "RX1 CHAIN"},
+	{"DAC2 MUX", "RX1", "RX1 CHAIN"},
+	{"DAC3 MUX", "RX1", "RX1 CHAIN"},
+	{"DAC3 MUX", "RX1_INV", "RX1 CHAIN"},
+	{"DAC3 MUX", "RX2", "RX2 MIX1"},
+	{"DAC4 MUX", "ON", "RX2 MIX1"},
+
+	{"RX1 CHAIN", NULL, "RX1 MIX1"},
+
+	{"CP", NULL, "RX_BIAS"},
+
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+
+	/* SLIMBUS Connections */
+
+	/* Slimbus port 5 is non functional in Sitar 1.0 */
+	{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
+
+
+	/* TX */
+	{"SLIM TX1", NULL, "SLIM TX1 MUX"},
+	{"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
+
+	{"SLIM TX2", NULL, "SLIM TX2 MUX"},
+	{"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
+
+	{"SLIM TX1", NULL, "SLIM TX1 MUX"},
+	{"SLIM TX2", NULL, "SLIM TX2 MUX"},
+	{"SLIM TX3", NULL, "SLIM TX3 MUX"},
+
+	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
+
+	/* Decimator Inputs */
+	{"DEC1 MUX", "DMIC1", "DMIC1"},
+	{"DEC1 MUX", "DMIC4", "DMIC4"},
+	{"DEC1 MUX", "ADC1", "ADC1"},
+	{"DEC1 MUX", "ADC2", "ADC2"},
+
+	{"DEC2 MUX", "DMIC2", "DMIC2"},
+	{"DEC2 MUX", "DMIC3", "DMIC3"},
+	{"DEC2 MUX", "ADC1", "ADC1"},
+	{"DEC2 MUX", "ADC2", "ADC2"},
+
+	{"DEC3 MUX", "DMIC3", "DMIC3"},
+	{"DEC3 MUX", "ADC1", "ADC1"},
+	{"DEC3 MUX", "ADC2", "ADC2"},
+	{"DEC3 MUX", "DMIC2", "DMIC2"},
+	{"DEC3 MUX", "DMIC3", "DMIC4"},
+
+	{"DEC4 MUX", "DMIC4", "DMIC4"},
+	{"DEC4 MUX", "ADC1", "ADC1"},
+	{"DEC4 MUX", "ADC2", "ADC2"},
+	{"DEC4 MUX", "DMIC3", "DMIC3"},
+	{"DEC4 MUX", "DMIC2", "DMIC2"},
+	{"DEC4 MUX", "DMIC1", "DMIC1"},
+
+	/* ADC Connections */
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2", NULL, "AMIC2"},
+
+	/* IIR */
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
+	{"MIC BIAS1 External", NULL, "LDO_H"},
+	{"MIC BIAS2 Internal1", NULL, "LDO_H"},
+	{"MIC BIAS2 External", NULL, "LDO_H"},
+};
+
+static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	return sitar_reg_readable[reg];
+}
+
+static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	/* Registers lower than 0x100 are top level registers which can be
+	* written by the Sitar core driver.
+	*/
+
+	if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
+		return 1;
+
+	/* IIR Coeff registers are not cacheable */
+	if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
+		(reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
+		return 1;
+
+	return 0;
+}
+
+#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	int ret;
+
+	BUG_ON(reg > SITAR_MAX_REGISTER);
+
+	if (!sitar_volatile(codec, reg)) {
+		ret = snd_soc_cache_write(codec, reg, value);
+		if (ret != 0)
+			dev_err(codec->dev, "Cache write to %x failed: %d\n",
+				reg, ret);
+	}
+
+	return wcd9xxx_reg_write(codec->control_data, reg, value);
+}
+static unsigned int sitar_read(struct snd_soc_codec *codec,
+				unsigned int reg)
+{
+	unsigned int val;
+	int ret;
+
+	BUG_ON(reg > SITAR_MAX_REGISTER);
+
+	if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
+		reg < codec->driver->reg_cache_size) {
+		ret = snd_soc_cache_read(codec, reg, &val);
+		if (ret >= 0) {
+			return val;
+		} else
+			dev_err(codec->dev, "Cache read from %x failed: %d\n",
+				reg, ret);
+	}
+
+	val = wcd9xxx_reg_read(codec->control_data, reg);
+	return val;
+}
+
+static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
+{
+
+	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x61);
+	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+	usleep_range(1000, 1000);
+	snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x80);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
+		0x04);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
+		0x01);
+	usleep_range(1000, 1000);
+	snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x00);
+}
+
+static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
+	enum sitar_bandgap_type choice)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	/* TODO lock resources accessed by audio streams and threaded
+	* interrupt handlers
+	*/
+
+	pr_err("%s, choice is %d, current is %d\n", __func__, choice,
+		sitar->bandgap_type);
+
+	if (sitar->bandgap_type == choice)
+		return;
+
+	if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
+		(choice == SITAR_BANDGAP_AUDIO_MODE)) {
+		sitar_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == SITAR_BANDGAP_MBHC_MODE) {
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
+			0x2);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
+			0x4);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
+			0x1);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x00);
+	} else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
+		(choice == SITAR_BANDGAP_AUDIO_MODE)) {
+		snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
+		usleep_range(100, 100);
+		sitar_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == SITAR_BANDGAP_OFF) {
+		snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
+	} else {
+		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
+	}
+	sitar->bandgap_type = choice;
+}
+
+
+static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
+	int config_mode)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	pr_err("%s\n", __func__);
+
+	if (config_mode) {
+		snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
+		snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
+		snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
+		usleep_range(1000, 1000);
+	} else
+		snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
+
+
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
+	snd_soc_update_bits(codec, SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+	snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
+	usleep_range(50, 50);
+	sitar->clock_active = true;
+	return 0;
+}
+static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	pr_err("%s\n", __func__);
+	snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
+	ndelay(160);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
+	sitar->clock_active = false;
+}
+
+static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+{
+	/* TODO store register values in calibration */
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
+
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
+
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
+
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 3);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL, 9);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL, 30);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 120);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
+	snd_soc_write(codec, SITAR_A_CDC_MBHC_B2_CTL, 11);
+}
+
+static int sitar_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	pr_err("%s(): substream = %s  stream = %d\n" , __func__,
+		substream->name, substream->stream);
+
+	return 0;
+}
+
+static void sitar_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	pr_err("%s(): substream = %s  stream = %d\n" , __func__,
+		substream->name, substream->stream);
+}
+
+int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	pr_err("%s() mclk_enable = %u\n", __func__, mclk_enable);
+
+	if (mclk_enable) {
+		sitar->mclk_enabled = true;
+
+		if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
+			sitar_codec_pause_hs_polling(codec);
+			sitar_codec_enable_bandgap(codec,
+					SITAR_BANDGAP_AUDIO_MODE);
+			sitar_codec_enable_clock_block(codec, 0);
+			sitar_codec_calibrate_hs_polling(codec);
+			sitar_codec_start_hs_polling(codec);
+		} else {
+			sitar_codec_enable_bandgap(codec,
+					SITAR_BANDGAP_AUDIO_MODE);
+			sitar_codec_enable_clock_block(codec, 0);
+		}
+	} else {
+
+		if (!sitar->mclk_enabled) {
+			pr_err("Error, MCLK already diabled\n");
+			return -EINVAL;
+		}
+		sitar->mclk_enabled = false;
+
+		if (sitar->mbhc_polling_active) {
+			if (!sitar->mclk_enabled) {
+				sitar_codec_pause_hs_polling(codec);
+				sitar_codec_enable_bandgap(codec,
+					SITAR_BANDGAP_MBHC_MODE);
+				sitar_enable_rx_bias(codec, 1);
+				sitar_codec_enable_clock_block(codec, 1);
+				sitar_codec_calibrate_hs_polling(codec);
+				sitar_codec_start_hs_polling(codec);
+			}
+			snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
+					0x05, 0x01);
+		} else {
+			sitar_codec_disable_clock_block(codec);
+			sitar_codec_enable_bandgap(codec,
+				SITAR_BANDGAP_OFF);
+		}
+	}
+	return 0;
+}
+
+static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	pr_err("%s\n", __func__);
+	return 0;
+}
+
+static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	u8 val = 0;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+
+	pr_err("%s\n", __func__);
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* CPU is master */
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL,
+					SITAR_I2S_MASTER_MODE_MASK, 0);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL,
+					SITAR_I2S_MASTER_MODE_MASK, 0);
+		}
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+	/* CPU is slave */
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			val = SITAR_I2S_MASTER_MODE_MASK;
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(dai->codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+static int sitar_set_channel_map(struct snd_soc_dai *dai,
+			unsigned int tx_num, unsigned int *tx_slot,
+			unsigned int rx_num, unsigned int *rx_slot)
+
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+	u32 i = 0;
+	if (!tx_slot && !rx_slot) {
+		pr_err("%s: Invalid\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
+
+	if (dai->id == AIF1_PB) {
+		for (i = 0; i < rx_num; i++) {
+			sitar->dai[dai->id - 1].ch_num[i]  = rx_slot[i];
+			sitar->dai[dai->id - 1].ch_act = 0;
+			sitar->dai[dai->id - 1].ch_tot = rx_num;
+		}
+	} else if (dai->id == AIF1_CAP) {
+		for (i = 0; i < tx_num; i++) {
+			sitar->dai[dai->id - 1].ch_num[i]  = tx_slot[i];
+			sitar->dai[dai->id - 1].ch_act = 0;
+			sitar->dai[dai->id - 1].ch_tot = tx_num;
+		}
+	}
+	return 0;
+}
+
+static int sitar_get_channel_map(struct snd_soc_dai *dai,
+			unsigned int *tx_num, unsigned int *tx_slot,
+			unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+	struct wcd9xxx *sitar = dev_get_drvdata(dai->codec->control_data);
+
+	u32 cnt = 0;
+	u32 tx_ch[SLIM_MAX_TX_PORTS];
+	u32 rx_ch[SLIM_MAX_RX_PORTS];
+
+	if (!rx_slot && !tx_slot) {
+		pr_err("%s: Invalid\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
+	/* for virtual port, codec driver needs to do
+	* housekeeping, for now should be ok
+	*/
+	wcd9xxx_get_channel(sitar, rx_ch, tx_ch);
+	if (dai->id == AIF1_PB) {
+		*rx_num = sitar_dai[dai->id - 1].playback.channels_max;
+		while (cnt < *rx_num) {
+			rx_slot[cnt] = rx_ch[cnt];
+			cnt++;
+		}
+	} else if (dai->id == AIF1_CAP) {
+		*tx_num = sitar_dai[dai->id - 1].capture.channels_max;
+		while (cnt < *tx_num) {
+			tx_slot[cnt] = tx_ch[6 + cnt];
+			cnt++;
+		}
+	}
+	return 0;
+}
+
+static int sitar_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+	u8 path, shift;
+	u16 tx_fs_reg, rx_fs_reg;
+	u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+
+	pr_err("%s: DAI-ID %x\n", __func__, dai->id);
+
+	switch (params_rate(params)) {
+	case 8000:
+		tx_fs_rate = 0x00;
+		rx_fs_rate = 0x00;
+		break;
+	case 16000:
+		tx_fs_rate = 0x01;
+		rx_fs_rate = 0x20;
+		break;
+	case 32000:
+		tx_fs_rate = 0x02;
+		rx_fs_rate = 0x40;
+		break;
+	case 48000:
+		tx_fs_rate = 0x03;
+		rx_fs_rate = 0x60;
+		break;
+	default:
+		pr_err("%s: Invalid sampling rate %d\n", __func__,
+				params_rate(params));
+		return -EINVAL;
+	}
+
+
+	/**
+	* If current dai is a tx dai, set sample rate to
+	* all the txfe paths that are currently not active
+	*/
+	if (dai->id == AIF1_CAP) {
+
+		tx_state = snd_soc_read(codec,
+				SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
+
+		for (path = 1, shift = 0;
+				path <= NUM_DECIMATORS; path++, shift++) {
+
+			if (!(tx_state & (1 << shift))) {
+				tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
+						+ (BITS_PER_REG*(path-1));
+				snd_soc_update_bits(codec, tx_fs_reg,
+							0x03, tx_fs_rate);
+			}
+		}
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_TX_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				pr_err("invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
+						0x03, tx_fs_rate);
+		}
+	} else {
+		sitar->dai[dai->id - 1].rate   = params_rate(params);
+	}
+
+	/**
+	* TODO: Need to handle case where same RX chain takes 2 or more inputs
+	* with varying sample rates
+	*/
+
+	/**
+	* If current dai is a rx dai, set sample rate to
+	* all the rx paths that are currently not active
+	*/
+	if (dai->id == AIF1_PB) {
+
+		rx_state = snd_soc_read(codec,
+			SITAR_A_CDC_CLK_RX_B1_CTL);
+
+		for (path = 1, shift = 0;
+				path <= NUM_INTERPOLATORS; path++, shift++) {
+
+			if (!(rx_state & (1 << shift))) {
+				rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
+						+ (BITS_PER_REG*(path-1));
+				snd_soc_update_bits(codec, rx_fs_reg,
+						0xE0, rx_fs_rate);
+			}
+		}
+		if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					SITAR_A_CDC_CLK_RX_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				pr_err("invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
+						0x03, (rx_fs_rate >> 0x05));
+		}
+	} else {
+		sitar->dai[dai->id - 1].rate   = params_rate(params);
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops sitar_dai_ops = {
+	.startup = sitar_startup,
+	.shutdown = sitar_shutdown,
+	.hw_params = sitar_hw_params,
+	.set_sysclk = sitar_set_dai_sysclk,
+	.set_fmt = sitar_set_dai_fmt,
+	.set_channel_map = sitar_set_channel_map,
+	.get_channel_map = sitar_get_channel_map,
+};
+
+static struct snd_soc_dai_driver sitar_dai[] = {
+	{
+		.name = "sitar_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9304_RATES,
+			.formats = SITAR_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &sitar_dai_ops,
+	},
+	{
+		.name = "sitar_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9304_RATES,
+			.formats = SITAR_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &sitar_dai_ops,
+	},
+};
+
+static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct wcd9xxx *sitar;
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+	u32  j = 0;
+	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	sitar = codec->control_data;
+	/* Execute the callback only if interface type is slimbus */
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return 0;
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_CAP)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].playback.stream_name, 13)) {
+				++sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
+			wcd9xxx_cfg_slim_sch_rx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot,
+					sitar_p->dai[j].rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_CAP)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].playback.stream_name, 13)) {
+				--sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (!sitar_p->dai[j].ch_act) {
+			wcd9xxx_close_slim_sch_rx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot);
+			sitar_p->dai[j].rate = 0;
+			memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
+					sitar_p->dai[j].ch_tot));
+			sitar_p->dai[j].ch_tot = 0;
+		}
+	}
+	return 0;
+}
+
+static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct wcd9xxx *sitar;
+	struct snd_soc_codec *codec = w->codec;
+	struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+	/* index to the DAI ID, for now hardcoding */
+	u32  j = 0;
+
+	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	sitar = codec->control_data;
+
+	/* Execute the callback only if interface type is slimbus */
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return 0;
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_PB)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].capture.stream_name, 13)) {
+				++sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
+			wcd9xxx_cfg_slim_sch_tx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot,
+					sitar_p->dai[j].rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+			if (sitar_dai[j].id == AIF1_PB)
+				continue;
+			if (!strncmp(w->sname,
+				sitar_dai[j].capture.stream_name, 13)) {
+				--sitar_p->dai[j].ch_act;
+				break;
+			}
+		}
+		if (!sitar_p->dai[j].ch_act) {
+			wcd9xxx_close_slim_sch_tx(sitar,
+					sitar_p->dai[j].ch_num,
+					sitar_p->dai[j].ch_tot);
+			sitar_p->dai[j].rate = 0;
+			memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
+					sitar_p->dai[j].ch_tot));
+			sitar_p->dai[j].ch_tot = 0;
+		}
+	}
+	return 0;
+}
+
+
+static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
+{
+	u8 bias_msb, bias_lsb;
+	short bias_value;
+
+	bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
+	bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
+	bias_value = (bias_msb << 8) | bias_lsb;
+	return bias_value;
+}
+
+static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
+{
+	u8 bias_msb, bias_lsb;
+	short bias_value;
+
+	bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
+	bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
+	bias_value = (bias_msb << 8) | bias_lsb;
+	return bias_value;
+}
+
+static short sitar_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
+	int dce)
+{
+	short bias_value;
+
+	if (dce) {
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
+		usleep_range(60000, 60000);
+		bias_value = sitar_codec_read_dce_result(codec);
+	} else {
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+		usleep_range(5000, 5000);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
+		usleep_range(50, 50);
+		bias_value = sitar_codec_read_sta_result(codec);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
+	}
+
+	pr_err("read microphone bias value %x\n", bias_value);
+	return bias_value;
+}
+
+static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+	short bias_value;
+	u8 cfilt_mode;
+
+	if (!calibration) {
+		pr_err("Error, no sitar calibration\n");
+		return -ENODEV;
+	}
+
+	sitar->mbhc_polling_active = true;
+
+	if (!sitar->mclk_enabled) {
+		sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
+		sitar_enable_rx_bias(codec, 1);
+		sitar_codec_enable_clock_block(codec, 1);
+	}
+
+	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
+
+	snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
+
+	/* Make sure CFILT is in fast mode, save current mode */
+	cfilt_mode = snd_soc_read(codec,
+		sitar->mbhc_bias_regs.cfilt_ctl);
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
+		0x70, 0x00);
+
+	snd_soc_update_bits(codec,
+		sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+
+	sitar_codec_calibrate_hs_polling(codec);
+
+	bias_value = sitar_codec_measure_micbias_voltage(codec, 0);
+	snd_soc_update_bits(codec,
+		sitar->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
+	snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
+
+	return bias_value;
+}
+
+static int sitar_codec_enable_hs_detect(struct snd_soc_codec *codec,
+		int insertion)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+	int central_bias_enabled = 0;
+	u8 wg_time;
+
+	if (!calibration) {
+		pr_err("Error, no sitar calibration\n");
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0);
+
+	if (insertion) {
+		/* Make sure mic bias and Mic line schmitt trigger
+		* are turned OFF
+		*/
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
+			0x81, 0x01);
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+			0x90, 0x00);
+		wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
+		wg_time += 1;
+
+		/* Enable HPH Schmitt Trigger */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x11, 0x11);
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x0C,
+			calibration->hph_current << 2);
+
+		/* Turn off HPH PAs and DAC's during insertion detection to
+		* avoid false insertion interrupts
+		*/
+		if (sitar->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
+			0xC0, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
+			0xC0, 0x00);
+		usleep_range(wg_time * 1000, wg_time * 1000);
+
+		/* setup for insetion detection */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x02, 0x02);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
+	} else {
+		/* Make sure the HPH schmitt trigger is OFF */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
+
+		/* enable the mic line schmitt trigger */
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x60,
+			calibration->mic_current << 5);
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+			0x80, 0x80);
+		usleep_range(calibration->mic_pid, calibration->mic_pid);
+		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+			0x10, 0x10);
+
+		/* Setup for low power removal detection */
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
+	}
+
+	if (snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_CTL) & 0x4) {
+		if (!(sitar->clock_active)) {
+			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
+				0x06, 0);
+			usleep_range(calibration->shutdown_plug_removal,
+				calibration->shutdown_plug_removal);
+		} else
+			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
+				0x06, 0);
+	}
+
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.int_rbias, 0x80, 0);
+
+	/* If central bandgap disabled */
+	if (!(snd_soc_read(codec, SITAR_A_PIN_CTL_OE1) & 1)) {
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x3, 0x3);
+		usleep_range(calibration->bg_fast_settle,
+			calibration->bg_fast_settle);
+		central_bias_enabled = 1;
+	}
+
+	/* If LDO_H disabled */
+	if (snd_soc_read(codec, SITAR_A_PIN_CTL_OE0) & 0x80) {
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x10, 0);
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0x80);
+		usleep_range(calibration->tldoh, calibration->tldoh);
+		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0);
+
+		if (central_bias_enabled)
+			snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x1, 0);
+	}
+
+	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+	return 0;
+}
+
+
+static void sitar_lock_sleep(struct sitar_priv *sitar)
+{
+	int ret;
+	while (!(ret = wait_event_timeout(sitar->pm_wq,
+					 atomic_inc_not_zero(&sitar->pm_cnt),
+					 2 * HZ))) {
+		pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
+			__func__, ret, atomic_read(&sitar->pm_cnt));
+		WARN_ON_ONCE(1);
+	}
+}
+
+static void sitar_unlock_sleep(struct sitar_priv *sitar)
+{
+	atomic_dec(&sitar->pm_cnt);
+	wake_up(&sitar->pm_wq);
+}
+
+
+static void btn0_lpress_fn(struct work_struct *work)
+{
+	struct delayed_work *delayed_work;
+	struct sitar_priv *sitar;
+
+	pr_err("%s:\n", __func__);
+
+	delayed_work = to_delayed_work(work);
+	sitar = container_of(delayed_work, struct sitar_priv, btn0_dwork);
+
+	if (sitar) {
+		if (sitar->button_jack) {
+			pr_err("%s: Reporting long button press event\n",
+					__func__);
+			sitar_snd_soc_jack_report(sitar, sitar->button_jack,
+						 SND_JACK_BTN_0,
+						 SND_JACK_BTN_0);
+		}
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+
+	sitar_unlock_sleep(sitar);
+}
+
+int sitar_hs_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
+	struct sitar_mbhc_calibration *calibration)
+{
+	struct sitar_priv *sitar;
+	int rc;
+
+	if (!codec || !calibration) {
+		pr_err("Error: no codec or calibration\n");
+		return -EINVAL;
+	}
+	sitar = snd_soc_codec_get_drvdata(codec);
+	sitar->headset_jack = headset_jack;
+	sitar->button_jack = button_jack;
+	sitar->calibration = calibration;
+	sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
+
+	/* Put CFILT in fast mode by default */
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
+		0x40, SITAR_CFILT_FAST_MODE);
+
+	INIT_DELAYED_WORK(&sitar->btn0_dwork, btn0_lpress_fn);
+	INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
+	INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
+	rc =  sitar_codec_enable_hs_detect(codec, 1);
+
+	if (!IS_ERR_VALUE(rc)) {
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+			0x10);
+		wcd9xxx_enable_irq(codec->control_data,
+			SITAR_IRQ_HPH_PA_OCPL_FAULT);
+		wcd9xxx_enable_irq(codec->control_data,
+			SITAR_IRQ_HPH_PA_OCPR_FAULT);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(sitar_hs_detect);
+
+static irqreturn_t sitar_dce_handler(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	short bias_value;
+
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+	sitar_lock_sleep(priv);
+
+	bias_value = sitar_codec_read_dce_result(codec);
+	pr_err("%s: button press interrupt, bias value(DCE Read)=%d\n",
+			__func__, bias_value);
+
+	bias_value = sitar_codec_read_sta_result(codec);
+	pr_err("%s: button press interrupt, bias value(STA Read)=%d\n",
+			__func__, bias_value);
+	/*
+	* TODO: If button pressed is not button 0,
+	* report the button press event immediately.
+	*/
+	priv->buttons_pressed |= SND_JACK_BTN_0;
+
+	msleep(100);
+
+	if (schedule_delayed_work(&priv->btn0_dwork,
+				 msecs_to_jiffies(400)) == 0) {
+		WARN(1, "Button pressed twice without release event\n");
+		sitar_unlock_sleep(priv);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_release_handler(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	int ret, mic_voltage;
+
+	pr_err("%s\n", __func__);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
+	sitar_lock_sleep(priv);
+
+	mic_voltage = sitar_codec_read_dce_result(codec);
+	pr_err("%s: Microphone Voltage on release(DCE Read) = %d\n",
+		__func__, mic_voltage);
+
+	if (priv->buttons_pressed & SND_JACK_BTN_0) {
+		ret = cancel_delayed_work(&priv->btn0_dwork);
+
+		if (ret == 0) {
+
+			pr_err("%s: Reporting long button release event\n",
+					__func__);
+			if (priv->button_jack) {
+				sitar_snd_soc_jack_report(priv,
+							 priv->button_jack, 0,
+							 SND_JACK_BTN_0);
+			}
+
+		} else {
+			/* if scheduled btn0_dwork is canceled from here,
+			* we have to unlock from here instead btn0_work */
+			sitar_unlock_sleep(priv);
+			mic_voltage =
+				sitar_codec_measure_micbias_voltage(codec, 0);
+			pr_err("%s: Mic Voltage on release(new STA) = %d\n",
+						__func__, mic_voltage);
+
+			if (mic_voltage < -2000 || mic_voltage > -670) {
+				pr_err("%s: Fake buttton press interrupt\n",
+						__func__);
+			} else {
+
+				if (priv->button_jack) {
+					pr_err("%s:reporting short button press and release\n",
+							__func__);
+
+					sitar_snd_soc_jack_report(priv,
+							     priv->button_jack,
+						SND_JACK_BTN_0, SND_JACK_BTN_0);
+					sitar_snd_soc_jack_report(priv,
+							    priv->button_jack,
+							    0, SND_JACK_BTN_0);
+				}
+			}
+		}
+
+		priv->buttons_pressed &= ~SND_JACK_BTN_0;
+	}
+
+	sitar_codec_start_hs_polling(codec);
+	sitar_unlock_sleep(priv);
+	return IRQ_HANDLED;
+}
+
+static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_calibration *calibration = sitar->calibration;
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
+
+	snd_soc_update_bits(codec,
+		sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+	usleep_range(calibration->shutdown_plug_removal,
+		calibration->shutdown_plug_removal);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
+
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
+}
+
+static void sitar_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	sitar_codec_shutdown_hs_removal_detect(codec);
+
+	if (!sitar->mclk_enabled) {
+		snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0x00);
+		sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_AUDIO_MODE);
+		sitar_codec_enable_clock_block(codec, 0);
+	}
+
+	sitar->mbhc_polling_active = false;
+}
+
+static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
+{
+	struct sitar_priv *sitar = data;
+	struct snd_soc_codec *codec;
+
+	pr_info("%s: received HPHL OCP irq\n", __func__);
+
+	if (sitar) {
+		codec = sitar->codec;
+		if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
+			pr_info("%s: retry\n", __func__);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x00);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x10);
+		} else {
+			wcd9xxx_disable_irq(codec->control_data,
+					 SITAR_IRQ_HPH_PA_OCPL_FAULT);
+			sitar->hphlocp_cnt = 0;
+			sitar->hph_status |= SND_JACK_OC_HPHL;
+			if (sitar->headset_jack)
+				sitar_snd_soc_jack_report(sitar,
+							 sitar->headset_jack,
+							 sitar->hph_status,
+							 SITAR_JACK_MASK);
+		}
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
+{
+	struct sitar_priv *sitar = data;
+	struct snd_soc_codec *codec;
+
+	pr_info("%s: received HPHR OCP irq\n", __func__);
+
+	if (sitar) {
+		codec = sitar->codec;
+		if (sitar->hphrocp_cnt++ < SITAR_OCP_ATTEMPT) {
+			pr_info("%s: retry\n", __func__);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x00);
+			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+					   0x10);
+		} else {
+			wcd9xxx_disable_irq(codec->control_data,
+					 SITAR_IRQ_HPH_PA_OCPR_FAULT);
+			sitar->hphrocp_cnt = 0;
+			sitar->hph_status |= SND_JACK_OC_HPHR;
+			if (sitar->headset_jack)
+				sitar_snd_soc_jack_report(sitar,
+							 sitar->headset_jack,
+							 sitar->hph_status,
+							 SITAR_JACK_MASK);
+		}
+	} else {
+		pr_err("%s: Bad sitar private data\n", __func__);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void sitar_sync_hph_state(struct sitar_priv *sitar)
+{
+	if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHR clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
+				   1 << 4);
+	}
+	if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHL clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
+				   1 << 5);
+	}
+
+	if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHR clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
+				   0xC0, 0xC0);
+	}
+	if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+				&sitar->hph_pa_dac_state)) {
+		pr_err("%s: HPHL clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
+				   0xC0, 0xC0);
+	}
+}
+
+static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	int ldo_h_on, micb_cfilt_on;
+	short mic_voltage;
+	short threshold_no_mic = 0xF7F6;
+	short threshold_fake_insert = 0xFD30;
+	u8 is_removal;
+
+	pr_err("%s\n", __func__);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+	sitar_lock_sleep(priv);
+
+	is_removal = snd_soc_read(codec, SITAR_A_CDC_MBHC_INT_CTL) & 0x02;
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
+
+	/* Turn off both HPH and MIC line schmitt triggers */
+	snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+			0x90, 0x00);
+	snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
+
+	if (priv->fake_insert_context) {
+		pr_err("%s: fake context interrupt, reset insertion\n",
+			__func__);
+		priv->fake_insert_context = false;
+		sitar_codec_shutdown_hs_polling(codec);
+		sitar_codec_enable_hs_detect(codec, 1);
+		return IRQ_HANDLED;
+	}
+
+
+	ldo_h_on = snd_soc_read(codec, SITAR_A_LDO_H_MODE_1) & 0x80;
+	micb_cfilt_on = snd_soc_read(codec,
+					priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
+
+	if (!ldo_h_on)
+		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+	if (!micb_cfilt_on)
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
+							0x80, 0x80);
+
+	usleep_range(priv->calibration->setup_plug_removal_delay,
+		priv->calibration->setup_plug_removal_delay);
+
+	if (!ldo_h_on)
+		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x0);
+	if (!micb_cfilt_on)
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
+							0x80, 0x0);
+
+	if (is_removal) {
+		/*
+		* If headphone is removed while playback is in progress,
+		* it is possible that micbias will be switched to VDDIO.
+		*/
+		if (priv->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+		priv->hph_status &= ~SND_JACK_HEADPHONE;
+
+		/* If headphone PA is on, check if userspace receives
+		* removal event to sync-up PA's state */
+		if (sitar_is_hph_pa_on(codec)) {
+			set_bit(SITAR_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
+			set_bit(SITAR_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
+		}
+
+		if (sitar_is_hph_dac_on(codec, 1))
+			set_bit(SITAR_HPHL_DAC_OFF_ACK,
+				&priv->hph_pa_dac_state);
+		if (sitar_is_hph_dac_on(codec, 0))
+			set_bit(SITAR_HPHR_DAC_OFF_ACK,
+				&priv->hph_pa_dac_state);
+
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting removal\n", __func__);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack,
+						 priv->hph_status,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_shutdown_hs_removal_detect(codec);
+		sitar_codec_enable_hs_detect(codec, 1);
+		sitar_unlock_sleep(priv);
+		return IRQ_HANDLED;
+	}
+
+	mic_voltage = sitar_codec_setup_hs_polling(codec);
+
+	if (mic_voltage > threshold_fake_insert) {
+		pr_err("%s: Fake insertion interrupt, mic_voltage = %x\n",
+			__func__, mic_voltage);
+
+		/* Disable HPH trigger and enable MIC line trigger */
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
+
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
+			priv->calibration->mic_current << 5);
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+			0x80, 0x80);
+		usleep_range(priv->calibration->mic_pid,
+			priv->calibration->mic_pid);
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+			0x10, 0x10);
+
+		/* Setup for insertion detection */
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
+		priv->fake_insert_context = true;
+		wcd9xxx_enable_irq(codec->control_data,
+				SITAR_IRQ_MBHC_INSERTION);
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+
+	} else if (mic_voltage < threshold_no_mic) {
+		pr_err("%s: Headphone Detected, mic_voltage = %x\n",
+			__func__, mic_voltage);
+		priv->hph_status |= SND_JACK_HEADPHONE;
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting insertion %d\n", __func__,
+				SND_JACK_HEADPHONE);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack,
+						 priv->hph_status,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_shutdown_hs_polling(codec);
+		sitar_codec_enable_hs_detect(codec, 0);
+		sitar_sync_hph_state(priv);
+	} else {
+		pr_err("%s: Headset detected, mic_voltage = %x\n",
+			__func__, mic_voltage);
+		priv->hph_status |= SND_JACK_HEADSET;
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting insertion %d\n", __func__,
+				SND_JACK_HEADSET);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack,
+						 priv->hph_status,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_start_hs_polling(codec);
+		sitar_sync_hph_state(priv);
+	}
+
+	sitar_unlock_sleep(priv);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	short bias_value;
+
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
+	sitar_lock_sleep(priv);
+
+	usleep_range(priv->calibration->shutdown_plug_removal,
+		priv->calibration->shutdown_plug_removal);
+
+	bias_value = sitar_codec_measure_micbias_voltage(codec, 1);
+	pr_err("removal interrupt, bias value is %d\n", bias_value);
+
+	if (bias_value < -90) {
+		pr_err("False alarm, headset not actually removed\n");
+		sitar_codec_start_hs_polling(codec);
+	} else {
+		/*
+		* If this removal is not false, first check the micbias
+		* switch status and switch it to LDOH if it is already
+		* switched to VDDIO.
+		*/
+		if (priv->mbhc_micbias_switched)
+			sitar_codec_switch_micbias(codec, 0);
+		priv->hph_status &= ~SND_JACK_HEADSET;
+		if (priv->headset_jack) {
+			pr_err("%s: Reporting removal\n", __func__);
+			sitar_snd_soc_jack_report(priv, priv->headset_jack, 0,
+						 SITAR_JACK_MASK);
+		}
+		sitar_codec_shutdown_hs_polling(codec);
+
+		sitar_codec_enable_hs_detect(codec, 1);
+	}
+
+	sitar_unlock_sleep(priv);
+	return IRQ_HANDLED;
+}
+
+
+static unsigned long slimbus_value;
+
+static irqreturn_t sitar_slimbus_irq(int irq, void *data)
+{
+	struct sitar_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	int i, j;
+	u8 val;
+
+	sitar_lock_sleep(priv);
+
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
+		slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
+			SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
+		for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
+			val = wcd9xxx_interface_reg_read(codec->control_data,
+				SITAR_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
+			if (val & 0x1)
+				pr_err_ratelimited("overflow error on port %x,"
+					" value %x\n", i*8 + j, val);
+			if (val & 0x2)
+				pr_err_ratelimited("underflow error on port %x,"
+					" value %x\n", i*8 + j, val);
+		}
+		wcd9xxx_interface_reg_write(codec->control_data,
+			SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
+	}
+
+	sitar_unlock_sleep(priv);
+	return IRQ_HANDLED;
+}
+
+
+static int sitar_handle_pdata(struct sitar_priv *sitar)
+{
+	struct snd_soc_codec *codec = sitar->codec;
+	struct wcd9xxx_pdata *pdata = sitar->pdata;
+	int k1, k2, rc = 0;
+	u8 leg_mode = pdata->amic_settings.legacy_mode;
+	u8 txfe_bypass = pdata->amic_settings.txfe_enable;
+	u8 txfe_buff = pdata->amic_settings.txfe_buff;
+	u8 flag = pdata->amic_settings.use_pdata;
+	u8 i = 0, j = 0;
+	u8 val_txfe = 0, value = 0;
+
+	if (!pdata) {
+		rc = -ENODEV;
+		goto done;
+	}
+
+	/* Make sure settings are correct */
+	if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
+	   (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
+	   (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* figure out k value */
+	k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
+		pdata->micbias.cfilt1_mv);
+	k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
+		pdata->micbias.cfilt2_mv);
+
+	if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Set voltage level and always use LDO */
+
+	snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
+		(k1 << 2));
+	snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
+		(k2 << 2));
+
+	snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
+		(pdata->micbias.bias1_cfilt_sel << 5));
+	snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
+		(pdata->micbias.bias2_cfilt_sel << 5));
+
+	for (i = 0; i < 6; j++, i += 2) {
+		if (flag & (0x01 << i)) {
+			value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
+			val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
+			val_txfe = val_txfe |
+				((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
+			snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
+				0x10, value);
+			snd_soc_update_bits(codec,
+				SITAR_A_TX_1_2_TEST_EN + j * 10,
+				0x30, val_txfe);
+		}
+		if (flag & (0x01 << (i + 1))) {
+			value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
+			val_txfe = (txfe_bypass &
+					(0x01 << (i + 1))) ? 0x02 : 0x00;
+			val_txfe |= (txfe_buff &
+					(0x01 << (i + 1))) ? 0x01 : 0x00;
+			snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
+				0x01, value);
+			snd_soc_update_bits(codec,
+				SITAR_A_TX_1_2_TEST_EN + j * 10,
+				0x03, val_txfe);
+		}
+	}
+
+	if (pdata->ocp.use_pdata) {
+		/* not defined in CODEC specification */
+		if (pdata->ocp.hph_ocp_limit == 1 ||
+			pdata->ocp.hph_ocp_limit == 5) {
+			rc = -EINVAL;
+			goto done;
+		}
+		snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
+			0x0F, pdata->ocp.num_attempts);
+		snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
+			((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
+			0xE0, (pdata->ocp.hph_ocp_limit << 5));
+	}
+done:
+	return rc;
+}
+
+static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
+
+	/* Sitar 1.1 MICBIAS changes */
+	SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
+	SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
+
+	/* Sitar 1.1 HPH changes */
+	SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
+	SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
+
+	/* Sitar 1.1 EAR PA changes */
+	SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
+	SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
+	SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
+
+	/* Sitar 1.1 RX Changes */
+	SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
+
+	/* Sitar 1.1 RX1 and RX2 Changes */
+	SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
+
+	SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
+
+};
+
+static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
+{
+	u32 i;
+	for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
+		snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
+				sitar_1_1_reg_defaults[i].val);
+
+}
+static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
+	/* Initialize current threshold to 350MA
+	* number of wait and run cycles to 4096
+	*/
+	{SITAR_A_RX_HPH_OCP_CTL, 0xF8, 0x60},
+	{SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+
+	{SITAR_A_QFUSE_CTL, 0xFF, 0x03},
+
+	/* Initialize gain registers to use register gain */
+	{SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
+	{SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
+	{SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
+	{SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
+
+	/* Initialize mic biases to differential mode */
+	{SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
+	{SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
+
+	{SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
+
+	/* Use 16 bit sample size for TX1 to TX6 */
+	{SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x28},
+	{SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
+	{SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
+	{SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
+	{SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
+
+	/* Use 16 bit sample size for RX */
+	{SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
+	{SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
+
+	/*enable HPF filter for TX paths */
+	{SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
+};
+
+static void sitar_codec_init_reg(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
+		snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
+			sitar_codec_reg_init_val[i].mask,
+			sitar_codec_reg_init_val[i].val);
+}
+
+static int sitar_codec_probe(struct snd_soc_codec *codec)
+{
+	struct sitar *control;
+	struct sitar_priv *sitar;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret = 0;
+	int i;
+	u8 sitar_version;
+	int ch_cnt;
+
+	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	control = codec->control_data;
+
+	sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
+	if (!sitar) {
+		dev_err(codec->dev, "Failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	/* Make sure mbhc micbias register addresses are zeroed out */
+	memset(&sitar->mbhc_bias_regs, 0,
+		sizeof(struct mbhc_micbias_regs));
+	sitar->cfilt_k_value = 0;
+	sitar->mbhc_micbias_switched = false;
+
+	snd_soc_codec_set_drvdata(codec, sitar);
+
+	sitar->mclk_enabled = false;
+	sitar->bandgap_type = SITAR_BANDGAP_OFF;
+	sitar->clock_active = false;
+	sitar->config_mode_active = false;
+	sitar->mbhc_polling_active = false;
+	sitar->fake_insert_context = false;
+	sitar->no_mic_headset_override = false;
+	sitar->codec = codec;
+	sitar->pdata = dev_get_platdata(codec->dev->parent);
+	atomic_set(&sitar->pm_cnt, 1);
+	init_waitqueue_head(&sitar->pm_wq);
+
+	sitar_update_reg_defaults(codec);
+	sitar_codec_init_reg(codec);
+
+	ret = sitar_handle_pdata(sitar);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s: bad pdata\n", __func__);
+		goto err_pdata;
+	}
+
+	snd_soc_add_controls(codec, sitar_snd_controls,
+		ARRAY_SIZE(sitar_snd_controls));
+	snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
+		ARRAY_SIZE(sitar_dapm_widgets));
+	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+	sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
+	pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
+
+	sitar_version &=  0x1F;
+	pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
+
+	snd_soc_dapm_sync(dapm);
+
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION,
+		sitar_hs_insert_irq, "Headset insert detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_INSERTION);
+		goto err_insert_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL,
+		sitar_hs_remove_irq, "Headset remove detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_REMOVAL);
+		goto err_remove_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
+		sitar_dce_handler, "DC Estimation detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_POTENTIAL);
+		goto err_potential_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
+		sitar_release_handler, "Button Release detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_MBHC_RELEASE);
+		goto err_release_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
+
+	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
+		sitar_slimbus_irq, "SLIMBUS Slave", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_SLIMBUS);
+		goto err_slimbus_irq;
+	}
+
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+		wcd9xxx_interface_reg_write(codec->control_data,
+			SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+
+
+	ret = wcd9xxx_request_irq(codec->control_data,
+		SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar_hphl_ocp_irq,
+		"HPH_L OCP detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_HPH_PA_OCPL_FAULT);
+		goto err_hphl_ocp_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+
+	ret = wcd9xxx_request_irq(codec->control_data,
+		SITAR_IRQ_HPH_PA_OCPR_FAULT, sitar_hphr_ocp_irq,
+		"HPH_R OCP detect", sitar);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			SITAR_IRQ_HPH_PA_OCPR_FAULT);
+		goto err_hphr_ocp_irq;
+	}
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+
+	for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
+		switch (sitar_dai[i].id) {
+		case AIF1_PB:
+			ch_cnt = sitar_dai[i].playback.channels_max;
+			break;
+		case AIF1_CAP:
+			ch_cnt = sitar_dai[i].capture.channels_max;
+			break;
+		default:
+			continue;
+		}
+		sitar->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
+					ch_cnt), GFP_KERNEL);
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	debug_sitar_priv = sitar;
+#endif
+
+	return ret;
+
+err_hphr_ocp_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar);
+err_hphl_ocp_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_SLIMBUS, sitar);
+err_slimbus_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_RELEASE, sitar);
+err_release_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_POTENTIAL, sitar);
+err_potential_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_REMOVAL, sitar);
+err_remove_irq:
+	wcd9xxx_free_irq(codec->control_data,
+			SITAR_IRQ_MBHC_INSERTION, sitar);
+err_insert_irq:
+err_pdata:
+	kfree(sitar);
+	return ret;
+}
+static int sitar_codec_remove(struct snd_soc_codec *codec)
+{
+	int i;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_SLIMBUS, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
+	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
+	sitar_codec_disable_clock_block(codec);
+	sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
+	for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
+		kfree(sitar->dai[i].ch_num);
+	kfree(sitar);
+	return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_sitar = {
+	.probe	= sitar_codec_probe,
+	.remove	= sitar_codec_remove,
+	.read = sitar_read,
+	.write = sitar_write,
+
+	.readable_register = sitar_readable,
+	.volatile_register = sitar_volatile,
+
+	.reg_cache_size = SITAR_CACHE_SIZE,
+	.reg_cache_default = sitar_reg_defaults,
+	.reg_word_size = 1,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_poke;
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t codec_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[32];
+	char *buf;
+	int rc;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	buf = (char *)lbuf;
+	debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
+		? false : true;
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+};
+#endif
+
+#ifdef CONFIG_PM
+static int sitar_suspend(struct device *dev)
+{
+	int ret = 0, cnt;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sitar_priv *sitar = platform_get_drvdata(pdev);
+
+	cnt = atomic_read(&sitar->pm_cnt);
+	if (cnt > 0) {
+		if (wait_event_timeout(sitar->pm_wq,
+					(atomic_cmpxchg(&sitar->pm_cnt, 1, 0)
+						== 1), 5 * HZ)) {
+			dev_dbg(dev, "system suspend pm_cnt %d\n",
+				atomic_read(&sitar->pm_cnt));
+		} else {
+			dev_err(dev, "%s timed out pm_cnt = %d\n",
+				__func__, atomic_read(&sitar->pm_cnt));
+			WARN_ON_ONCE(1);
+			ret = -EBUSY;
+		}
+	} else if (cnt == 0)
+		dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
+			atomic_read(&sitar->pm_cnt));
+	else {
+		WARN(1, "unexpected pm_cnt %d\n", cnt);
+		ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+static int sitar_resume(struct device *dev)
+{
+	int ret = 0, cnt;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sitar_priv *sitar = platform_get_drvdata(pdev);
+
+	cnt = atomic_cmpxchg(&sitar->pm_cnt, 0, 1);
+	if (cnt == 0) {
+		dev_dbg(dev, "system resume, pm_cnt %d\n",
+			atomic_read(&sitar->pm_cnt));
+		wake_up_all(&sitar->pm_wq);
+	} else if (cnt > 0)
+		dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
+	else {
+		WARN(1, "unexpected pm_cnt %d\n", cnt);
+		ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+static const struct dev_pm_ops sitar_pm_ops = {
+	.suspend	= sitar_suspend,
+	.resume		= sitar_resume,
+};
+#endif
+
+static int __devinit sitar_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	pr_err("%s\n", __func__);
+#ifdef CONFIG_DEBUG_FS
+	debugfs_poke = debugfs_create_file("TRRS",
+		S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
+
+#endif
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+			sitar_dai, ARRAY_SIZE(sitar_dai));
+	return ret;
+}
+static int __devexit sitar_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(debugfs_poke);
+#endif
+	return 0;
+}
+static struct platform_driver sitar_codec_driver = {
+	.probe = sitar_probe,
+	.remove = sitar_remove,
+	.driver = {
+		.name = "sitar_codec",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &sitar_pm_ops,
+#endif
+	},
+};
+
+static int __init sitar_codec_init(void)
+{
+	return platform_driver_register(&sitar_codec_driver);
+}
+
+static void __exit sitar_codec_exit(void)
+{
+	platform_driver_unregister(&sitar_codec_driver);
+}
+
+module_init(sitar_codec_init);
+module_exit(sitar_codec_exit);
+
+MODULE_DESCRIPTION("Sitar codec driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9304.h b/sound/soc/codecs/wcd9304.h
new file mode 100644
index 0000000..07a1ca0
--- /dev/null
+++ b/sound/soc/codecs/wcd9304.h
@@ -0,0 +1,72 @@
+/* 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 <sound/soc.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+
+#define SITAR_VERSION_1_0	0x00
+
+#define SITAR_NUM_REGISTERS 0x3E0
+#define SITAR_MAX_REGISTER (SITAR_NUM_REGISTERS-1)
+#define SITAR_CACHE_SIZE SITAR_NUM_REGISTERS
+
+#define SITAR_REG_VAL(reg, val)		{reg, 0, val}
+
+/* Local to the core only */
+#define SITAR_SLIM_MAX_RX_PORTS 5
+#define SITAR_SLIM_MAX_TX_PORTS 5
+
+extern const u8 sitar_reg_readable[SITAR_CACHE_SIZE];
+extern const u8 sitar_reg_defaults[SITAR_CACHE_SIZE];
+
+enum sitar_micbias_num {
+	SITAR_MICBIAS1,
+	SITAR_MICBIAS2,
+};
+
+enum sitar_pid_current {
+	SITAR_PID_MIC_2P5_UA,
+	SITAR_PID_MIC_5_UA,
+	SITAR_PID_MIC_10_UA,
+	SITAR_PID_MIC_20_UA,
+};
+
+struct sitar_mbhc_calibration {
+	enum sitar_micbias_num bias;
+	int tldoh;
+	int bg_fast_settle;
+	enum sitar_pid_current mic_current;
+	int mic_pid;
+	enum sitar_pid_current hph_current;
+	int setup_plug_removal_delay;
+	int shutdown_plug_removal;
+};
+
+struct sitar_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+extern int sitar_hs_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
+	struct sitar_mbhc_calibration *calibration);
+
+#ifndef anc_header_dec
+struct anc_header {
+	u32 reserved[3];
+	u32 num_anc_slots;
+};
+#define anc_header_dec
+#endif
+
+extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
index c681771..e0ad541 100644
--- a/sound/soc/codecs/wcd9310-tables.c
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mfd/wcd9310/registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
 #include "wcd9310.h"
 
 const u8 tabla_reg_readable[TABLA_CACHE_SIZE] = {
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 46f6461..a5427ed 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -18,9 +18,10 @@
 #include <linux/printk.h>
 #include <linux/ratelimit.h>
 #include <linux/debugfs.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -171,7 +172,7 @@
 	struct snd_soc_jack *headset_jack;
 	struct snd_soc_jack *button_jack;
 
-	struct tabla_pdata *pdata;
+	struct wcd9xxx_pdata *pdata;
 	u32 anc_slot;
 
 	bool no_mic_headset_override;
@@ -1319,10 +1320,12 @@
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
-	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+	wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 	if (!tabla->no_mic_headset_override) {
-		tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
-		tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+		wcd9xxx_enable_irq(codec->control_data,
+				TABLA_IRQ_MBHC_POTENTIAL);
+		wcd9xxx_enable_irq(codec->control_data,
+				TABLA_IRQ_MBHC_RELEASE);
 	} else {
 		tabla_codec_disable_button_presses(codec);
 	}
@@ -1336,11 +1339,12 @@
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 	if (!tabla->no_mic_headset_override) {
-		tabla_disable_irq(codec->control_data,
+		wcd9xxx_disable_irq(codec->control_data,
 			TABLA_IRQ_MBHC_POTENTIAL);
-		tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+		wcd9xxx_disable_irq(codec->control_data,
+			TABLA_IRQ_MBHC_RELEASE);
 	}
 }
 
@@ -1767,7 +1771,7 @@
 			tabla->hphlocp_cnt = 0;
 		else
 			tabla->hphrocp_cnt = 0;
-		tabla_enable_irq(codec->control_data, irq);
+		wcd9xxx_enable_irq(codec->control_data, irq);
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
 	}
@@ -1925,16 +1929,16 @@
 
 static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
-			       0, tabla_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
+				0, tabla_codec_enable_micbias,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
-			       0, tabla_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
+				0, tabla_codec_enable_micbias,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route audio_i2s_map[] = {
@@ -2284,7 +2288,7 @@
 static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
 {
 	int i;
-	struct tabla *tabla_core = dev_get_drvdata(ssc->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
 
 	if (TABLA_IS_1_X(tabla_core->version)) {
 		for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
@@ -2333,7 +2337,7 @@
 				reg, ret);
 	}
 
-	return tabla_reg_write(codec->control_data, reg, value);
+	return wcd9xxx_reg_write(codec->control_data, reg, value);
 }
 static unsigned int tabla_read(struct snd_soc_codec *codec,
 				unsigned int reg)
@@ -2353,7 +2357,7 @@
 				reg, ret);
 	}
 
-	val = tabla_reg_read(codec->control_data, reg);
+	val = wcd9xxx_reg_read(codec->control_data, reg);
 	return val;
 }
 
@@ -2622,7 +2626,7 @@
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* CPU is master */
-		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			if (dai->id == AIF1_CAP)
 				snd_soc_update_bits(dai->codec,
 					TABLA_A_CDC_CLK_TX_I2S_CTL,
@@ -2635,7 +2639,7 @@
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 	/* CPU is slave */
-		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			val = TABLA_I2S_MASTER_MODE_MASK;
 			if (dai->id == AIF1_CAP)
 				snd_soc_update_bits(dai->codec,
@@ -2685,7 +2689,7 @@
 				unsigned int *rx_num, unsigned int *rx_slot)
 
 {
-	struct tabla *tabla = dev_get_drvdata(dai->codec->control_data);
+	struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
 
 	u32 cnt = 0;
 	u32 tx_ch[SLIM_MAX_TX_PORTS];
@@ -2699,7 +2703,7 @@
 	/* for virtual port, codec driver needs to do
 	 * housekeeping, for now should be ok
 	 */
-	tabla_get_channel(tabla, rx_ch, tx_ch);
+	wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
 	if (dai->id == AIF1_PB) {
 		*rx_num = tabla_dai[dai->id - 1].playback.channels_max;
 		while (cnt < *rx_num) {
@@ -2784,7 +2788,7 @@
 							0x03, tx_fs_rate);
 			}
 		}
-		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			switch (params_format(params)) {
 			case SNDRV_PCM_FORMAT_S16_LE:
 				snd_soc_update_bits(codec,
@@ -2830,7 +2834,7 @@
 						0xE0, rx_fs_rate);
 			}
 		}
-		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 			switch (params_format(params)) {
 			case SNDRV_PCM_FORMAT_S16_LE:
 				snd_soc_update_bits(codec,
@@ -2945,7 +2949,7 @@
 static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct tabla *tabla;
+	struct wcd9xxx *tabla;
 	struct snd_soc_codec *codec = w->codec;
 	struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
 	u32  j = 0;
@@ -2953,7 +2957,7 @@
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	tabla = codec->control_data;
 	/* Execute the callback only if interface type is slimbus */
-	if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+	if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		return 0;
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -2967,10 +2971,10 @@
 			}
 		}
 		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
-			ret = tabla_cfg_slim_sch_rx(tabla,
-						tabla_p->dai[j].ch_num,
-						tabla_p->dai[j].ch_tot,
-						tabla_p->dai[j].rate);
+			ret = wcd9xxx_cfg_slim_sch_rx(tabla,
+					tabla_p->dai[j].ch_num,
+					tabla_p->dai[j].ch_tot,
+					tabla_p->dai[j].rate);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
@@ -2983,12 +2987,12 @@
 			}
 		}
 		if (!tabla_p->dai[j].ch_act) {
-			ret = tabla_close_slim_sch_rx(tabla,
+			ret = wcd9xxx_close_slim_sch_rx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot);
 			tabla_p->dai[j].rate = 0;
 			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
-						tabla_p->dai[j].ch_tot));
+					tabla_p->dai[j].ch_tot));
 			tabla_p->dai[j].ch_tot = 0;
 		}
 	}
@@ -2998,7 +3002,7 @@
 static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct tabla *tabla;
+	struct wcd9xxx *tabla;
 	struct snd_soc_codec *codec = w->codec;
 	struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
 	/* index to the DAI ID, for now hardcoding */
@@ -3009,7 +3013,7 @@
 	tabla = codec->control_data;
 
 	/* Execute the callback only if interface type is slimbus */
-	if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+	if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		return 0;
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -3024,7 +3028,7 @@
 			}
 		}
 		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
-			ret = tabla_cfg_slim_sch_tx(tabla,
+			ret = wcd9xxx_cfg_slim_sch_tx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot,
 						tabla_p->dai[j].rate);
@@ -3041,12 +3045,12 @@
 			}
 		}
 		if (!tabla_p->dai[j].ch_act) {
-			ret = tabla_close_slim_sch_tx(tabla,
+			ret = wcd9xxx_close_slim_sch_tx(tabla,
 						tabla_p->dai[j].ch_num,
 						tabla_p->dai[j].ch_tot);
 			tabla_p->dai[j].rate = 0;
 			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
-						tabla_p->dai[j].ch_tot));
+					tabla_p->dai[j].ch_tot));
 			tabla_p->dai[j].ch_tot = 0;
 		}
 	}
@@ -3584,7 +3588,7 @@
 	snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
 			    tabla->micbias);
 
-	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
 	return 0;
 }
@@ -3655,10 +3659,10 @@
 		if (tabla->button_jack) {
 			bias_value = tabla_codec_read_sta_result(tabla->codec);
 			sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
-						       bias_value);
+						bias_value);
 			bias_value = tabla_codec_read_dce_result(tabla->codec);
 			dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
-						       bias_value);
+						bias_value);
 			pr_debug("%s: Reporting long button press event"
 				 " STA: %d, DCE: %d\n", __func__,
 				 sta_mv, dce_mv);
@@ -3670,7 +3674,6 @@
 		pr_err("%s: Bad tabla private data\n", __func__);
 	}
 
-	tabla_unlock_sleep(core);
 }
 
 void tabla_mbhc_cal(struct snd_soc_codec *codec)
@@ -3850,7 +3853,7 @@
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	int n;
 	u8 *n_cic, *gain;
-	struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
 
 	tabla = snd_soc_codec_get_drvdata(codec);
 	generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
@@ -3998,7 +4001,7 @@
 	if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
 		if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
 			pr_err("Error: clock rate %dHz is not yet supported\n",
-			       mclk_rate);
+				mclk_rate);
 		else
 			pr_err("Error: unsupported clock rate %d\n", mclk_rate);
 		return -EINVAL;
@@ -4037,9 +4040,9 @@
 	if (!IS_ERR_VALUE(rc)) {
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 			0x10);
-		tabla_enable_irq(codec->control_data,
+		wcd9xxx_enable_irq(codec->control_data,
 			TABLA_IRQ_HPH_PA_OCPL_FAULT);
-		tabla_enable_irq(codec->control_data,
+		wcd9xxx_enable_irq(codec->control_data,
 			TABLA_IRQ_HPH_PA_OCPR_FAULT);
 	}
 
@@ -4057,7 +4060,7 @@
 	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
 	v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
 	v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
-					       TABLA_BTN_DET_V_BTN_HIGH);
+				TABLA_BTN_DET_V_BTN_HIGH);
 	for (i = 0; i < btn_det->num_btn; i++) {
 		if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
 			btn = i;
@@ -4115,10 +4118,10 @@
 	    TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
 	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
-	struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
 
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
 
 	bias_value_dce = tabla_codec_read_dce_result(codec);
 	bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
@@ -4164,12 +4167,12 @@
 
 		/* XXX: assuming button 0 has the lowest micbias voltage */
 		if (btn == 0) {
-			tabla_lock_sleep(core);
+			wcd9xxx_lock_sleep(core);
 			if (schedule_delayed_work(&priv->btn0_dwork,
 						  msecs_to_jiffies(400)) == 0) {
 				WARN(1, "Button pressed twice without release"
 				     "event\n");
-				tabla_unlock_sleep(core);
+				wcd9xxx_unlock_sleep(core);
 			}
 		} else {
 			pr_debug("%s: Reporting short button %d(0x%x) press\n",
@@ -4191,10 +4194,10 @@
 	short mb_v;
 	struct tabla_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
 
 	pr_debug("%s: enter\n", __func__);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 
 	if (priv->buttons_pressed & SND_JACK_BTN_0) {
 		ret = cancel_delayed_work(&priv->btn0_dwork);
@@ -4208,7 +4211,7 @@
 		} else {
 			/* if scheduled btn0_dwork is canceled from here,
 			 * we have to unlock from here instead btn0_work */
-			tabla_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core);
 			mb_v = tabla_codec_sta_dce(codec, 0);
 			pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
 				 __func__, mb_v,
@@ -4304,7 +4307,7 @@
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 					    0x10);
 		} else {
-			tabla_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(codec->control_data,
 					  TABLA_IRQ_HPH_PA_OCPL_FAULT);
 			tabla->hphlocp_cnt = 0;
 			tabla->hph_status |= SND_JACK_OC_HPHL;
@@ -4337,7 +4340,7 @@
 			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 					    0x10);
 		} else {
-			tabla_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(codec->control_data,
 					  TABLA_IRQ_HPH_PA_OCPR_FAULT);
 			tabla->hphrocp_cnt = 0;
 			tabla->hph_status |= SND_JACK_OC_HPHR;
@@ -4357,26 +4360,26 @@
 static void tabla_sync_hph_state(struct tabla_priv *tabla)
 {
 	if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
+				&tabla->hph_pa_dac_state)) {
 		pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
 		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
 				    1 << 4);
 	}
 	if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
+				&tabla->hph_pa_dac_state)) {
 		pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
 		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
 				    1 << 5);
 	}
 
 	if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
+				&tabla->hph_pa_dac_state)) {
 		pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
 		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
 				    0xC0, 0xC0);
 	}
 	if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
-			       &tabla->hph_pa_dac_state)) {
+				&tabla->hph_pa_dac_state)) {
 		pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
 		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
 				    0xC0, 0xC0);
@@ -4395,7 +4398,7 @@
 	int mic_mv;
 
 	pr_debug("%s: enter\n", __func__);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 
 	is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
@@ -4406,7 +4409,7 @@
 
 	if (priv->mbhc_fake_ins_start &&
 	    time_after(jiffies, priv->mbhc_fake_ins_start +
-		       msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
+			msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
 		pr_debug("%s: fake context interrupt, reset insertion\n",
 			 __func__);
 		priv->mbhc_fake_ins_start = 0;
@@ -4482,8 +4485,8 @@
 			     0),
 			 mb_v, mic_mv);
 		if (time_after(jiffies,
-			       priv->mbhc_fake_ins_start +
-			       msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
+			priv->mbhc_fake_ins_start +
+			msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
 			/* Disable HPH trigger and enable MIC line trigger */
 			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
 					    0x00);
@@ -4509,7 +4512,8 @@
 		}
 		/* Setup for insertion detection */
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
-		tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+		wcd9xxx_enable_irq(codec->control_data,
+					TABLA_IRQ_MBHC_INSERTION);
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
 
 	} else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
@@ -4559,9 +4563,9 @@
 	int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
 
 	pr_debug("%s: enter, removal interrupt\n", __func__);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 
 	usleep_range(generic->t_shutdown_plug_rem,
 		     generic->t_shutdown_plug_rem);
@@ -4611,11 +4615,11 @@
 	int i, j;
 	u8 val;
 
-	for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
-		slimbus_value = tabla_interface_reg_read(codec->control_data,
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
+		slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
 			TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
 		for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
-			val = tabla_interface_reg_read(codec->control_data,
+			val = wcd9xxx_interface_reg_read(codec->control_data,
 				TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
 			if (val & 0x1)
 				pr_err_ratelimited("overflow error on port %x,"
@@ -4624,7 +4628,7 @@
 				pr_err_ratelimited("underflow error on port %x,"
 					" value %x\n", i*8 + j, val);
 		}
-		tabla_interface_reg_write(codec->control_data,
+		wcd9xxx_interface_reg_write(codec->control_data,
 			TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
 	}
 
@@ -4635,7 +4639,7 @@
 static int tabla_handle_pdata(struct tabla_priv *tabla)
 {
 	struct snd_soc_codec *codec = tabla->codec;
-	struct tabla_pdata *pdata = tabla->pdata;
+	struct wcd9xxx_pdata *pdata = tabla->pdata;
 	int k1, k2, k3, rc = 0;
 	u8 leg_mode = pdata->amic_settings.legacy_mode;
 	u8 txfe_bypass = pdata->amic_settings.txfe_enable;
@@ -4802,7 +4806,7 @@
 static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
 {
 	u32 i;
-	struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
 
 	for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
 		snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
@@ -4894,7 +4898,7 @@
 static void tabla_codec_init_reg(struct snd_soc_codec *codec)
 {
 	u32 i;
-	struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
 
 	for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
 		snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
@@ -4918,7 +4922,7 @@
 
 static void tabla_update_reg_address(struct tabla_priv *priv)
 {
-	struct tabla *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
 	struct tabla_reg_address *reg_addr = &priv->reg_addr;
 
 	if (TABLA_IS_1_X(tabla_core->version)) {
@@ -4934,7 +4938,7 @@
 
 static int tabla_codec_probe(struct snd_soc_codec *codec)
 {
-	struct tabla *control;
+	struct wcd9xxx *control;
 	struct tabla_priv *tabla;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret = 0;
@@ -4973,7 +4977,7 @@
 	tabla->no_mic_headset_override = false;
 	tabla->codec = codec;
 	tabla->pdata = dev_get_platdata(codec->dev->parent);
-	tabla->intf_type = tabla_get_intf_type();
+	tabla->intf_type = wcd9xxx_get_intf_type();
 
 	tabla_update_reg_address(tabla);
 	tabla_update_reg_defaults(codec);
@@ -5002,7 +5006,7 @@
 		snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
 				    ARRAY_SIZE(tabla_2_higher_dapm_widgets));
 
-	if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+	if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 		snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
 			ARRAY_SIZE(tabla_dapm_i2s_widgets));
 		snd_soc_dapm_add_routes(dapm, audio_i2s_map,
@@ -5018,49 +5022,49 @@
 				      ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
 	} else  {
 		pr_err("%s : ERROR.  Unsupported Tabla version 0x%2x\n",
-		       __func__, control->version);
+			__func__, control->version);
 		goto err_pdata;
 	}
 
 	snd_soc_dapm_sync(dapm);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
 		tabla_hs_insert_irq, "Headset insert detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_INSERTION);
 		goto err_insert_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
 		tabla_hs_remove_irq, "Headset remove detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_REMOVAL);
 		goto err_remove_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
 		tabla_dce_handler, "DC Estimation detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_POTENTIAL);
 		goto err_potential_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
 		tabla_release_handler, "Button Release detect", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
 			TABLA_IRQ_MBHC_RELEASE);
 		goto err_release_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 
-	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
 		tabla_slimbus_irq, "SLIMBUS Slave", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -5068,11 +5072,11 @@
 		goto err_slimbus_irq;
 	}
 
-	for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
-		tabla_interface_reg_write(codec->control_data,
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+		wcd9xxx_interface_reg_write(codec->control_data,
 			TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
 
-	ret = tabla_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(codec->control_data,
 		TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
 		"HPH_L OCP detect", tabla);
 	if (ret) {
@@ -5080,9 +5084,9 @@
 			TABLA_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = tabla_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(codec->control_data,
 		TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
 		"HPH_R OCP detect", tabla);
 	if (ret) {
@@ -5090,7 +5094,7 @@
 			TABLA_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
 	for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
 		switch (tabla_dai[i].id) {
 		case AIF1_PB:
@@ -5116,17 +5120,18 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
+	wcd9xxx_free_irq(codec->control_data,
+			TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
 err_hphl_ocp_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
 err_slimbus_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
 err_release_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
 err_potential_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
 err_remove_irq:
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
 err_insert_irq:
 err_pdata:
 	kfree(tabla);
@@ -5136,11 +5141,11 @@
 {
 	int i;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
-	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
 	tabla_codec_disable_clock_block(codec);
 	tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
 	if (tabla->mbhc_fw)
@@ -5227,10 +5232,10 @@
 		S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
 
 #endif
-	if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
 			tabla_dai, ARRAY_SIZE(tabla_dai));
-	else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
+	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
 		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
 			tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
 	return ret;
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 9c430b9..d1d0c17 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -11,7 +11,7 @@
  */
 #include <sound/soc.h>
 #include <sound/jack.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 
 #define TABLA_NUM_REGISTERS 0x400
 #define TABLA_MAX_REGISTER (TABLA_NUM_REGISTERS-1)
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 1ed5f74..3a2687e 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -126,6 +126,7 @@
 	select SND_SOC_QDSP6
 	select SND_SOC_MSM_STUB
 	select SND_SOC_WCD9310
+	select SND_SOC_WCD9304
 	select SND_SOC_MSM_HOSTLESS_PCM
 	select SND_SOC_MSM_QDSP6_HDMI_AUDIO
 	default n
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 6f2d651..2aef4bd 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -62,7 +62,7 @@
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
 obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
 
-snd-soc-msm8960-objs := msm8960.o apq8064.o
+snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o
 obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
 
 # Generic MSM drivers
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index 6907ded..3333344 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -14,10 +14,8 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/wcd9310/core.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <linux/clk.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
@@ -25,7 +23,6 @@
 #include <sound/q6afe.h>
 #include <sound/q6adm.h>
 #include <sound/msm-dai-q6.h>
-#include <mach/clk.h>
 #include <mach/msm_hdmi_audio.h>
 
 
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 070dc7b..0430f7b 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -14,7 +14,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index 01b8463..a176118 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -149,6 +149,8 @@
 			}
 			case AFE_EVENT_RTPORT_STOP:
 				pr_debug("%s: event!=0\n", __func__);
+				prtd->start = 0;
+				snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
 				break;
 			case AFE_EVENT_RTPORT_LOW_WM:
 				pr_debug("%s: Underrun\n", __func__);
@@ -213,6 +215,8 @@
 		}
 		case AFE_EVENT_RTPORT_STOP:
 			pr_debug("%s: event!=0\n", __func__);
+			prtd->start = 0;
+			snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
 			break;
 		case AFE_EVENT_RTPORT_LOW_WM:
 			pr_debug("%s: Underrun\n", __func__);
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 09f1010..0b7cc78 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -27,6 +27,9 @@
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
 
 #include "msm-pcm-q6.h"
 #include "msm-pcm-routing.h"
@@ -483,8 +486,37 @@
 	int rc = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
+	uint64_t timestamp;
+	uint64_t temp;
 
 	switch (cmd) {
+	case SNDRV_COMPRESS_TSTAMP: {
+		struct snd_compr_tstamp tstamp;
+		pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+
+		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
+		timestamp = q6asm_get_session_time(prtd->audio_client);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * runtime->channels);
+		temp = temp * (runtime->rate/1000);
+		temp = div_u64(temp, 1000);
+		tstamp.sampling_rate = runtime->rate;
+		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
+		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
+		tstamp.timestamp = timestamp;
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld,\n",
+			__func__, tstamp.rendered, tstamp.decoded,
+			tstamp.timestamp);
+		if (copy_to_user((void *) arg, &tstamp,
+			sizeof(struct snd_compr_tstamp)))
+			return -EFAULT;
+		return 0;
+	}
 	case SNDRV_PCM_IOCTL1_RESET:
 		prtd->cmd_ack = 0;
 		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
diff --git a/sound/soc/msm/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index 56b4cf5..2301472 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -108,6 +108,7 @@
 	uint32_t mode;
 	uint32_t rate_type;
 	uint32_t rate;
+	uint32_t dtx_mode;
 
 	uint8_t capture_start;
 	uint8_t playback_start;
@@ -200,6 +201,31 @@
 	return 0;
 }
 
+static int msm_voip_dtx_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	voip_info.dtx_mode  = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: dtx: %d\n", __func__, voip_info.dtx_mode);
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+static int msm_voip_dtx_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	ucontrol->value.integer.value[0] = voip_info.dtx_mode;
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
 static struct snd_kcontrol_new msm_voip_controls[] = {
 	SOC_SINGLE_EXT("Voip Tx Mute", SND_SOC_NOPM, 0, 1, 0,
 				msm_voip_mute_get, msm_voip_mute_put),
@@ -208,6 +234,8 @@
 	SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
 				0, 2, msm_voip_mode_rate_config_get,
 				msm_voip_mode_rate_config_put),
+	SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
+				msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
 };
 
 static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
@@ -713,11 +741,13 @@
 		if ((prtd->play_samp_rate == 8000) &&
 					(prtd->cap_samp_rate == 8000))
 			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_NB);
+					VSS_NETWORK_ID_VOIP_NB,
+					voip_info.dtx_mode);
 		else if ((prtd->play_samp_rate == 16000) &&
 					(prtd->cap_samp_rate == 16000))
 			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_WB);
+					VSS_NETWORK_ID_VOIP_WB,
+					voip_info.dtx_mode);
 		else {
 			pr_debug("%s: Invalid rate playback %d, capture %d\n",
 				 __func__, prtd->play_samp_rate,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
new file mode 100644
index 0000000..a081253
--- /dev/null
+++ b/sound/soc/msm/msm8930.c
@@ -0,0 +1,1083 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dsp.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9304.h"
+
+/* 8930 machine driver */
+
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8930_SPK_ON 1
+#define MSM8930_SPK_OFF 0
+
+#define msm8930_SLIM_0_RX_MAX_CHANNELS		2
+#define msm8930_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS	0x1
+#define BOTTOM_SPK_AMP_NEG	0x2
+#define TOP_SPK_AMP_POS		0x4
+#define TOP_SPK_AMP_NEG		0x8
+
+#define GPIO_AUX_PCM_DOUT 63
+#define GPIO_AUX_PCM_DIN 64
+#define GPIO_AUX_PCM_SYNC 65
+#define GPIO_AUX_PCM_CLK 66
+
+#define SITAR_EXT_CLK_RATE 12288000
+
+#define SITAR_MBHC_DEF_BUTTONS 3
+#define SITAR_MBHC_DEF_RLOADS 5
+
+static int msm8930_spk_control;
+static int msm8930_slim_0_rx_ch = 1;
+static int msm8930_slim_0_tx_ch = 1;
+
+static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm8930_btsco_ch = 1;
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static int msm8930_headset_gpios_configured;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+struct sitar_mbhc_calibration sitar_calib = {
+	.bias = SITAR_MICBIAS2,
+	.tldoh = 100,
+	.bg_fast_settle = 100,
+	.mic_current = SITAR_PID_MIC_5_UA,
+	.mic_pid = 100,
+	.hph_current = SITAR_PID_MIC_5_UA,
+	.setup_plug_removal_delay = 1000000,
+	.shutdown_plug_removal = 100000,
+};
+
+static void msm8930_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
+	if (msm8930_spk_control == MSM8930_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk Right Pos");
+	}
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int msm8930_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
+	ucontrol->value.integer.value[0] = msm8930_spk_control;
+	return 0;
+}
+static int msm8930_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 (msm8930_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm8930_spk_control = ucontrol->value.integer.value[0];
+	msm8930_ext_control(codec);
+	return 1;
+}
+
+static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+	/* TODO: add external speaker power amps support */
+	return 0;
+}
+int msm8930_enable_codec_ext_clk(
+		struct snd_soc_codec *codec, int enable)
+{
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	if (enable) {
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users != 1)
+			return 0;
+
+		if (codec_clk) {
+			clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
+			clk_enable(codec_clk);
+			sitar_mclk_enable(codec, 1);
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+	} else {
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users == 0)
+			return 0;
+		clk_users--;
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					 __func__, clk_users);
+			clk_disable(codec_clk);
+			sitar_mclk_enable(codec, 0);
+		}
+	}
+	return 0;
+}
+
+static int msm8930_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return msm8930_enable_codec_ext_clk(w->codec, 1);
+	case SND_SOC_DAPM_POST_PMD:
+		return msm8930_enable_codec_ext_clk(w->codec, 0);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8930_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Right Pos", msm8930_spkramp_event),
+
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+
+};
+
+static const struct snd_soc_dapm_route common_audio_map[] = {
+
+	{"RX_BIAS", NULL, "MCLK"},
+	{"LDO_H", NULL, "MCLK"},
+
+	{"MIC BIAS1 Internal1", NULL, "MCLK"},
+	{"MIC BIAS2 Internal1", NULL, "MCLK"},
+
+	/* Speaker path */
+	{"Ext Spk Left Pos", NULL, "LINEOUT1"},
+	{"Ext Spk Right Pos", NULL, "LINEOUT2"},
+
+
+	{"AMIC2", NULL, "MIC BIAS2 Internal1"},
+	{"MIC BIAS2 Internal1", NULL, "Headset Mic"},
+
+	/* Microphone path */
+	{"AMIC1", NULL, "MIC BIAS1 Internal1"},
+	{"MIC BIAS1 Internal1", NULL, "Handset Mic"},
+
+	{"HEADPHONE", NULL, "LDO_H"},
+
+	/**
+	 * The digital Mic routes are setup considering
+	 * fluid as default device.
+	 */
+
+	/**
+	 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
+	 * Digital Mic GM5 on CDP mainboard.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
+	 * Digital Mic GM6 on CDP mainboard.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+	/**
+	 * Digital Mic3. Back Bottom Digital Mic on Fluid.
+	 * Digital Mic GM1 on CDP mainboard.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4. Back top Digital Mic on Fluid.
+	 * Digital Mic GM2 on CDP mainboard.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS2 External", NULL, "Digital Mic4"},
+
+
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *slim0_rx_ch_text[] = {"One", "Two"};
+static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm8930_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+};
+
+static const char *btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm8930_btsco_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm8930_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_slim_0_rx_ch  = %d\n", __func__,
+		 msm8930_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int msm8930_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
+		 msm8930_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm8930_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_slim_0_tx_ch  = %d\n", __func__,
+		 msm8930_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm8930_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int msm8930_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm8930_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
+		 msm8930_slim_0_tx_ch);
+	return 1;
+}
+
+static int msm8930_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8930_btsco_rate  = %d", __func__, msm8930_btsco_rate);
+	ucontrol->value.integer.value[0] = msm8930_btsco_rate;
+	return 0;
+}
+
+static int msm8930_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 1:
+		msm8930_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm8930_btsco_rate = %d\n", __func__, msm8930_btsco_rate);
+	return 0;
+}
+
+static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
+		msm8930_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm8930_enum[1],
+		msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
+		msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
+};
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
+		msm8930_btsco_rate_get, msm8930_btsco_rate_put),
+};
+
+static int msm8930_btsco_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err = 0;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	err = snd_soc_add_platform_controls(platform,
+			int_btsco_rate_mixer_controls,
+		ARRAY_SIZE(int_btsco_rate_mixer_controls));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int msm8930_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+	pr_debug("%s: ch=%d\n", __func__,
+					msm8930_slim_0_rx_ch);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				msm8930_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+				msm8930_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+							       __func__);
+			goto end;
+		}
+	} else {
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				msm8930_slim_0_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+		ret = snd_soc_dai_set_channel_map(codec_dai,
+				msm8930_slim_0_tx_ch, tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set codec channel map\n",
+							       __func__);
+			goto end;
+		}
+
+	}
+end:
+	return ret;
+}
+
+static int msm8930_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;
+
+	pr_debug("%s()\n", __func__);
+
+
+	rtd->pmdown_time = 0;
+
+	err = snd_soc_add_controls(codec, sitar_msm8930_controls,
+				ARRAY_SIZE(sitar_msm8930_controls));
+	if (err < 0)
+		return err;
+
+	snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
+				ARRAY_SIZE(msm8930_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, common_audio_map,
+		ARRAY_SIZE(common_audio_map));
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+
+	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",
+				SND_JACK_BTN_0, &button_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+	sitar_hs_detect(codec, &hs_jack, &button_jack, &sitar_calib);
+	return 0;
+}
+
+static struct snd_soc_dsp_link lpa_fe_media = {
+	.playback = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link fe_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link slimbus0_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link int_fm_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+/* bi-directional media definition for hostless PCM device */
+static struct snd_soc_dsp_link bidir_hl_media = {
+	.playback = true,
+	.capture = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static struct snd_soc_dsp_link hdmi_rx_hl = {
+	.playback = true,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static int msm8930_slim_0_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);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm8930_slim_0_rx_ch;
+
+	return 0;
+}
+
+static int msm8930_slim_0_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);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm8930_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int msm8930_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);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm8930_hdmi_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 = 2;
+
+	return 0;
+}
+
+static int msm8930_btsco_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 = msm8930_btsco_rate;
+	channels->min = channels->max = msm8930_btsco_ch;
+
+	return 0;
+}
+static int msm8930_auxpcm_be_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);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+static int msm8930_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int msm8930_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+static int msm8930_startup(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	return 0;
+}
+
+static int msm8930_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = msm8930_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	msm8930_aux_pcm_free_gpios();
+}
+
+static void msm8930_shutdown(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+}
+
+static struct snd_soc_ops msm8930_be_ops = {
+	.startup = msm8930_startup,
+	.hw_params = msm8930_hw_params,
+	.shutdown = msm8930_shutdown,
+};
+
+static struct snd_soc_ops msm8930_auxpcm_be_ops = {
+	.startup = msm8930_auxpcm_startup,
+	.shutdown = msm8930_auxpcm_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm8930_dai[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8930 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8930 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name	= "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{
+		.name = "MSM8930 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+	/* Hostless PMC purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &slimbus0_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &int_fm_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM8930 Compr",
+		.stream_name = "COMPR",
+		.cpu_dai_name	= "MultiMedia4",
+		.platform_name  = "msm-compr-dsp",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+	},
+	 {
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name   = "AUXPCM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &bidir_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	/* HDMI Hostless */
+	{
+		.name = "HDMI_RX_HOSTLESS",
+		.stream_name = "HDMI_RX_HOSTLESS",
+		.cpu_dai_name = "HDMI_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &hdmi_rx_hl,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.no_codec = 1,
+		.ignore_suspend = 1,
+	},
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "sitar_codec",
+		.codec_dai_name	= "sitar_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm8930_audrx_init,
+		.be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8930_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "sitar_codec",
+		.codec_dai_name	= "sitar_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8930_be_ops,
+	},
+	/* Backend BT/FM DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6.12288",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-rx",
+		.init = &msm8930_btsco_init,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+		.be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6.12292",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6.12293",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_TX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	/* HDMI BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI,
+		.stream_name = "HDMI Playback",
+		.cpu_dai_name = "msm-dai-q6-hdmi.8",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_HDMI_RX,
+		.be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
+	},
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6.224",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_codec = 1,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+		.ops = &msm8930_auxpcm_be_ops,
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6.32773",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm8930_be_hw_params_fixup,
+	},
+};
+
+struct snd_soc_card snd_soc_card_msm8930 = {
+	.name		= "msm8930-sitar-snd-card",
+	.dai_link	= msm8930_dai,
+	.num_links	= ARRAY_SIZE(msm8930_dai),
+};
+
+static struct platform_device *msm8930_snd_device;
+
+static int msm8930_configure_headset_mic_gpios(void)
+{
+	int ret;
+	ret = gpio_request(80, "US_EURO_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio 80\n", __func__);
+		return ret;
+	}
+	ret = gpio_direction_output(80, 0);
+	if (ret) {
+		pr_err("%s: Unable to set direction\n", __func__);
+		gpio_free(80);
+	}
+	msm8930_headset_gpios_configured = 0;
+	return 0;
+}
+static void msm8930_free_headset_mic_gpios(void)
+{
+	if (msm8930_headset_gpios_configured)
+		gpio_free(80);
+}
+
+static int __init msm8930_audio_init(void)
+{
+	int ret;
+
+	if (!cpu_is_msm8930()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return -ENODEV ;
+	}
+
+	msm8930_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm8930_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
+	ret = platform_device_add(msm8930_snd_device);
+	if (ret) {
+		platform_device_put(msm8930_snd_device);
+		return ret;
+	}
+
+	if (msm8930_configure_headset_mic_gpios()) {
+		pr_err("%s Fail to configure headset mic gpios\n", __func__);
+		msm8930_headset_gpios_configured = 0;
+	} else
+		msm8930_headset_gpios_configured = 1;
+
+	return ret;
+
+}
+module_init(msm8930_audio_init);
+
+static void __exit msm8930_audio_exit(void)
+{
+	if (!cpu_is_msm8930()) {
+		pr_err("%s: Not the right machine type\n", __func__);
+		return ;
+	}
+	msm8930_free_headset_mic_gpios();
+	platform_device_unregister(msm8930_snd_device);
+}
+module_exit(msm8930_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MSM8930");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index eb363e7..0854dff 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1391,7 +1391,7 @@
 {
 	int ret;
 
-	if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
+	if (!cpu_is_msm8960()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return -ENODEV ;
 	}
@@ -1455,7 +1455,7 @@
 
 static void __exit msm8960_audio_exit(void)
 {
-	if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
+	if (!cpu_is_msm8960()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return ;
 	}
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 532d92b..f0f833c 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -662,6 +662,59 @@
 	return -EINVAL;
 }
 
+static int voice_set_dtx(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+	struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	/* Set DTX */
+	cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+	cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+	cvs_set_dtx.hdr.src_port = v->session_id;
+	cvs_set_dtx.hdr.dest_port = cvs_handle;
+	cvs_set_dtx.hdr.token = 0;
+	cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+	cvs_set_dtx.dtx_mode.enable = common.mvs_info.dtx_mode;
+
+	pr_debug("%s: Setting DTX %d\n", __func__, common.mvs_info.dtx_mode);
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_DTX\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int voice_config_cvs_vocoder(struct voice_data *v)
 {
 	int ret = 0;
@@ -753,7 +806,6 @@
 	}
 	case VSS_MEDIA_ID_AMR_NB_MODEM: {
 		struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
-		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
 
 		pr_debug("Setting AMR rate\n");
 
@@ -785,40 +837,15 @@
 			pr_err("%s: wait_event timeout\n", __func__);
 			goto fail;
 		}
-		/* Disable DTX */
-		pr_debug("Disabling DTX\n");
 
-		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						      APR_HDR_LEN(APR_HDR_SIZE),
-						      APR_PKT_VER);
-		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-					sizeof(cvs_set_dtx) - APR_HDR_SIZE);
-		cvs_set_dtx.hdr.src_port = v->session_id;
-		cvs_set_dtx.hdr.dest_port = cvs_handle;
-		cvs_set_dtx.hdr.token = 0;
-		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
-		cvs_set_dtx.dtx_mode.enable = 0;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_DTX\n",
-			       __func__, ret);
+		ret = voice_set_dtx(v);
+		if (ret < 0)
 			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
+
 		break;
 	}
 	case VSS_MEDIA_ID_AMR_WB_MODEM: {
 		struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
-		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
 
 		pr_debug("Setting AMR WB rate\n");
 
@@ -851,70 +878,18 @@
 			pr_err("%s: wait_event timeout\n", __func__);
 			goto fail;
 		}
-		/* Disable DTX */
-		pr_debug("Disabling DTX\n");
 
-		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						      APR_HDR_LEN(APR_HDR_SIZE),
-						      APR_PKT_VER);
-		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				       sizeof(cvs_set_dtx) - APR_HDR_SIZE);
-		cvs_set_dtx.hdr.src_port = v->session_id;
-		cvs_set_dtx.hdr.dest_port = cvs_handle;
-		cvs_set_dtx.hdr.token = 0;
-		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
-		cvs_set_dtx.dtx_mode.enable = 0;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_DTX\n",
-			       __func__, ret);
+		ret = voice_set_dtx(v);
+		if (ret < 0)
 			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
+
 		break;
 	}
 	case VSS_MEDIA_ID_G729:
 	case VSS_MEDIA_ID_G711_ALAW:
 	case VSS_MEDIA_ID_G711_MULAW: {
-		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
-		/* Disable DTX */
-		pr_debug("Disabling DTX\n");
+		ret = voice_set_dtx(v);
 
-		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						      APR_HDR_LEN(APR_HDR_SIZE),
-						      APR_PKT_VER);
-		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-					    sizeof(cvs_set_dtx) - APR_HDR_SIZE);
-		cvs_set_dtx.hdr.src_port = v->session_id;
-		cvs_set_dtx.hdr.dest_port = cvs_handle;
-		cvs_set_dtx.hdr.token = 0;
-		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
-		cvs_set_dtx.dtx_mode.enable = 0;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_DTX\n",
-			       __func__, ret);
-			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
 		break;
 	}
 	default:
@@ -3236,11 +3211,13 @@
 
 void voc_config_vocoder(uint32_t media_type,
 			  uint32_t rate,
-			  uint32_t network_type)
+			  uint32_t network_type,
+			  uint32_t dtx_mode)
 {
 	common.mvs_info.media_type = media_type;
 	common.mvs_info.rate = rate;
 	common.mvs_info.network_type = network_type;
+	common.mvs_info.dtx_mode = dtx_mode;
 }
 
 static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 2dc08d6..1a24b9c 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -785,6 +785,7 @@
 	uint32_t media_type;
 	uint32_t rate;
 	uint32_t network_type;
+	uint32_t dtx_mode;
 	ul_cb_fn ul_cb;
 	dl_cb_fn dl_cb;
 	void *private_data;
@@ -876,7 +877,8 @@
 
 void voc_config_vocoder(uint32_t media_type,
 			uint32_t rate,
-			uint32_t network_type);
+			uint32_t network_type,
+			uint32_t dtx_mode);
 
 enum {
 	DEV_RX = 0,