Merge "radio-tavarua: Add private IOCTLs to poke threshold values." into msm-3.0
diff --git a/Documentation/genlock.txt b/Documentation/genlock.txt
new file mode 100644
index 0000000..d3a44e2
--- /dev/null
+++ b/Documentation/genlock.txt
@@ -0,0 +1,161 @@
+Introduction
+
+'genlock' is an in-kernel API and optional userspace interface for a generic
+cross-process locking mechanism. The API is designed for situations where
+multiple user space processes and/or kernel drivers need to coordinate access
+to a shared resource, such as a graphics buffer. The API was designed with
+graphics buffers in mind, but is sufficiently generic to allow it to be
+independently used with different types of resources. The chief advantage
+of genlock over other cross-process locking mechanisms is that the resources
+can be accessed by both userspace and kernel drivers which allows resources
+to be locked or unlocked by asynchronous events in the kernel without the
+intervention of user space.
+
+As an example, consider a graphics buffer that is shared between a rendering
+application and a compositing window manager. The application renders into a
+buffer. That buffer is reused by the compositing window manager as a texture.
+To avoid corruption, access to the buffer needs to be restricted so that one
+is not drawing on the surface while the other is reading. Locks can be
+explicitly added between the rendering stages in the processes, but explicit
+locks require that the application wait for rendering and purposely release the
+lock. An implicit release triggered by an asynchronous event from the GPU
+kernel driver, however, will let execution continue without requiring the
+intercession of user space.
+
+SW Goals
+
+The genlock API implements exclusive write locks and shared read locks meaning
+that there can only be one writer at a time, but multiple readers. Processes
+that are unable to acquire a lock can be optionally blocked until the resource
+becomes available.
+
+Locks are shared between processes. Each process will have its own private
+instance for a lock known as a handle. Handles can be shared between user
+space and kernel space to allow a kernel driver to unlock or lock a buffer
+on behalf of a user process.
+
+Kernel API
+
+Access to the genlock API can either be via the in-kernel API or via an
+optional character device (/dev/genlock). The character device is primarily
+to be used for legacy resource sharing APIs that cannot be easily changed.
+New resource sharing APIs from this point should implement a scheme specific
+wrapper for locking.
+
+To create or attach to an existing lock, a process or kernel driver must first
+create a handle. Each handle is linked to a single lock at any time. An entityi
+may have multiple handles, each associated with a different lock. Once a handle
+has been created, the owner may create a new lock or attach an existing lock
+that has been exported from a different handle.
+
+Once the handle has a lock attached, the owning process may attempt to lock the
+buffer for read or write. Write locks are exclusive, meaning that only one
+process may acquire it at any given time. Read locks are shared, meaning that
+multiple readers can hold the lock at the same time. Attempts to acquire a read
+lock with a writer active or a write lock with one or more readers or writers
+active will typically cause the process to block until the lock is acquired.
+When the lock is released, all waiting processes will be woken up. Ownership
+of the lock is reference counted, meaning that any one owner can "lock"
+multiple times. The lock will only be released from the owner when all the
+references to the lock are released via unlock.
+
+The owner of a write lock may atomically convert the lock into a read lock
+(which will wake up other processes waiting for a read lock) without first
+releasing the lock. The owner would simply issue a new request for a read lock.
+However, the owner of a read lock cannot convert it into a write lock in the
+same manner. To switch from a read lock to a write lock, the owner must
+release the lock and then try to reacquire it.
+
+These are the in-kernel API calls that drivers can use to create and
+manipulate handles and locks. Handles can either be created and managed
+completely inside of kernel space, or shared from user space via a file
+descriptor.
+
+* struct genlock_handle *genlock_get_handle(void)
+Create a new handle.
+
+* struct genlock_handle * genlock_get_handle_fd(int fd)
+Given a valid file descriptor, return the handle associated with that
+descriptor.
+
+* void genlock_put_handle(struct genlock_handle *)
+Release a handle.
+
+* struct genlock * genlock_create_lock(struct genlock_handle *)
+Create a new lock and attach it to the handle.
+
+* struct genlock * genlock_attach_lock(struct genlock_handle *handle, int fd)
+Given a valid file descriptor, get the lock associated with it and attach it to
+the handle.
+
+* void genlock_release_lock(struct genlock_handle *)
+Release a lock attached to a handle.
+
+* int genlock_lock(struct genlock_handle *, int op, int flags, u32 timeout)
+Lock or unlock the lock attached to the handle. A zero timeout value will
+be treated just like if the GENOCK_NOBLOCK flag is passed; if the lock
+can be acquired without blocking then do so otherwise return -EAGAIN.
+Function returns -ETIMEDOUT if the timeout expired or 0 if the lock was
+acquired.
+
+* int genlock_wait(struct genloc_handle *, u32 timeout)
+Wait for a lock held by the handle to go to the unlocked state. A non-zero
+timeout value must be passed. Returns -ETIMEDOUT if the timeout expired or
+0 if the lock is in an unlocked state.
+
+Character Device
+
+Opening an instance to the /dev/genlock character device will automatically
+create a new handle. All ioctl functions with the exception of NEW and
+RELEASE use the following parameter structure:
+
+struct genlock_lock {
+	int fd; /* Returned by EXPORT, used by ATTACH */
+	int op;	/* Used by LOCK */
+	int flags;	/* used by LOCK */
+	u32 timeout;	/* Used by LOCK and WAIT */
+}
+
+*GENLOCK_IOC_NEW
+Create a new lock and attaches it to the handle. Returns -EINVAL if the handle
+already has a lock attached (use GENLOCK_IOC_RELEASE to remove it). Returns
+-ENOMEM if the memory for the lock can not be allocated. No data is passed
+from the user for this ioctl.
+
+*GENLOCK_IOC_EXPORT
+Export the currently attached lock to a file descriptor. The file descriptor
+is returned in genlock_lock.fd.
+
+*GENLOCK_IOC_ATTACH
+Attach an exported lock file descriptor to the current handle. Return -EINVAL
+if the handle already has a lock attached (use GENLOCK_IOC_RELEASE to remove
+it). Pass the file descriptor in genlock_lock.fd.
+
+*GENLOCK_IOC_LOCK
+Lock or unlock the attached lock. Pass the desired operation in
+genlock_lock.op:
+ * GENLOCK_WRLOCK - write lock
+ * GENLOCK_RDLOCK - read lock
+ * GENLOCK_UNLOCK - unlock an existing lock
+
+Pass flags in genlock_lock.flags:
+ * GENLOCK_NOBLOCK - Do not block if the lock is already taken
+
+Pass a timeout value in milliseconds in genlock_lock.timeout.
+genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
+Returns -EINVAL if no lock is attached, -EAGAIN if the lock is taken and
+NOBLOCK is specified or if the timeout value is zero, -ETIMEDOUT if the timeout
+expires or 0 if the lock was successful.
+
+* GENLOCK_IOC_WAIT
+Wait for the lock attached to the handle to be released (i.e. goes to unlock).
+This is mainly used for a thread that needs to wait for a peer to release a
+lock on the same shared handle. A non-zero timeout value in milliseconds is
+passed in genlock_lock.timeout. Returns 0 when the lock has been released,
+-EINVAL if a zero timeout is passed, or -ETIMEDOUT if the timeout expires.
+
+* GENLOCK_IOC_RELEASE
+Use this to release an existing lock. This is useful if you wish to attach a
+different lock to the same handle. You do not need to call this under normal
+circumstances; when the handle is closed the reference to the lock is released.
+No data is passed from the user for this ioctl.
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 6c50ae9..3e754fc 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -32,6 +32,7 @@
 CONFIG_ARCH_MSMCOPPER=y
 CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
 # CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_DEBUG_MSMCOPPER_UART=y
 CONFIG_CPU_HAS_L2_PMU=y
 # CONFIG_MSM_JTAG_V7 is not set
 # CONFIG_MSM_FIQ_SUPPORT is not set
@@ -98,6 +99,14 @@
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_CI13XXX_MSM=y
 CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 # CONFIG_LEDS_MSM_PMIC is not set
@@ -133,6 +142,8 @@
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_AUTHENC=y
 CONFIG_CRYPTO_CBC=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 5e0cd9f..dccefd8 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -25,6 +25,7 @@
 # CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -421,12 +422,10 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_STACKTRACE is not set
 CONFIG_DEBUG_INFO=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index d63a018..8689712 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -93,7 +93,7 @@
 CONFIG_MISC_DEVICES=y
 # CONFIG_ANDROID_PMEM is not set
 CONFIG_NETDEVICES=y
-CONFIG_HOSTAP=m
+CONFIG_HOSTAP=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 # CONFIG_INPUT_MOUSEDEV is not set
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 7ef3a30..7dac1d4 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -211,7 +211,8 @@
 	for (iter = 0; iter < (mi)->nr_banks; iter++)
 
 #define bank_pfn_start(bank)	__phys_to_pfn((bank)->start)
-#define bank_pfn_end(bank)	__phys_to_pfn((bank)->start + (bank)->size)
+#define bank_pfn_end(bank)	(__phys_to_pfn((bank)->start) + \
+						__phys_to_pfn((bank)->size))
 #define bank_pfn_size(bank)	((bank)->size >> PAGE_SHIFT)
 #define bank_phys_start(bank)	(bank)->start
 #define bank_phys_end(bank)	((bank)->start + (bank)->size)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 604989d..e4f88ec 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -149,7 +149,7 @@
 	obj-$(CONFIG_ARCH_MSM7X01A) += pm.o
 	obj-y += pm-boot.o
 else
-	obj-y += no-pm.o
+	obj-y += no-pm.o hotplug.o
 endif
 
 obj-$(CONFIG_MSM_SPM_V1) += spm.o
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index e6206dd..1f112f6 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -56,7 +56,6 @@
 };
 
 static struct src_clock clocks[NUM_SRC] = {
-	[SRC_CXO].name  = "cxo",
 	[SRC_PLL0].name = "pll0",
 	[SRC_PLL8].name = "pll8",
 	[SRC_PLL9].name = "pll9",
@@ -320,7 +319,7 @@
 
 	for (i = 0; i < NUM_SRC; i++) {
 		if (clocks[i].name) {
-			clocks[i].clk = clk_get_sys(NULL, clocks[i].name);
+			clocks[i].clk = clk_get_sys("acpu", clocks[i].name);
 			BUG_ON(IS_ERR(clocks[i].clk));
 		}
 	}
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 5e2d311..c70e1b5 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -292,6 +292,17 @@
 		queue_rx();
 		return;
 	}
+
+	if (rx_hdr->ch_id >= BAM_DMUX_NUM_CHANNELS) {
+		pr_err("%s: dropping invalid LCID %d reserved %d cmd %d"
+			" pad %d ch %d len %d\n", __func__,
+			rx_hdr->ch_id, rx_hdr->reserved, rx_hdr->cmd,
+			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		return;
+	}
+
 	switch (rx_hdr->cmd) {
 	case BAM_MUX_HDR_CMD_DATA:
 		DBG_INC_READ_CNT(rx_hdr->pkt_len);
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index eddd4ed..44b78d1 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -623,11 +623,63 @@
 	.src_clk_rate = 24000000,
 };
 
+#define USB_5V_EN		3
+#define PM_USB_5V_EN	PM8018_GPIO_PM_TO_SYS(USB_5V_EN)
+
+static void msm_hsusb_vbus_power(bool on)
+{
+	int rc;
+	static bool vbus_is_on;
+	struct pm_gpio usb_vbus = {
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+			.output_value   = 0,
+			.vin_sel        = 2,
+			.out_strength   = PM_GPIO_STRENGTH_HIGH,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+	};
+
+	if (vbus_is_on == on)
+		return;
+
+	if (on) {
+		rc = pm8xxx_gpio_config(PM_USB_5V_EN, &usb_vbus);
+		if (rc) {
+			pr_err("failed to config usb_5v_en gpio\n");
+			return;
+		}
+
+		rc = gpio_request(PM_USB_5V_EN,
+						"usb_5v_en");
+		if (rc < 0) {
+			pr_err("failed to request usb_5v_en gpio\n");
+			return;
+		}
+
+		rc = gpio_direction_output(PM_USB_5V_EN, 1);
+		if (rc) {
+			pr_err("%s: unable to set_direction for gpio [%d]\n",
+				__func__, PM_USB_5V_EN);
+			goto free_usb_5v_en;
+		}
+
+		vbus_is_on = true;
+		return;
+	}
+	gpio_set_value(PM_USB_5V_EN, 0);
+free_usb_5v_en:
+	gpio_free(PM_USB_5V_EN);
+	vbus_is_on = false;
+}
+
 static struct msm_otg_platform_data msm_otg_pdata = {
-	.mode			= USB_PERIPHERAL,
-	.otg_control		= OTG_NO_CONTROL,
+	.mode			= USB_OTG,
+	.otg_control	= OTG_PHY_CONTROL,
 	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
-	.pclk_src_name		= "dfab_usb_hs_clk",
+	.pclk_src_name	= "dfab_usb_hs_clk",
+	.vbus_power		= msm_hsusb_vbus_power,
 };
 
 static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
@@ -662,6 +714,7 @@
 	&msm_device_smd,
 	&msm_device_otg,
 	&msm_device_gadget_peripheral,
+	&msm_device_hsusb_host,
 	&android_usb_device,
 	&msm9615_device_uart_gsbi4,
 	&msm9615_device_ext_2p95v_vreg,
diff --git a/arch/arm/mach-msm/board-apq8064.c b/arch/arm/mach-msm/board-apq8064.c
index b131989..00886c6 100644
--- a/arch/arm/mach-msm/board-apq8064.c
+++ b/arch/arm/mach-msm/board-apq8064.c
@@ -18,6 +18,8 @@
 #include <linux/slimbus/slimbus.h>
 #include <linux/msm_ssbi.h>
 #include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -37,6 +39,7 @@
 #include <mach/msm_memtypes.h>
 #include <linux/bootmem.h>
 #include <asm/setup.h>
+#include <mach/dma.h>
 
 #include "msm_watchdog.h"
 #include "board-apq8064.h"
@@ -429,12 +432,14 @@
 {
 	if ((machine_is_apq8064_rumi3()) || machine_is_apq8064_sim()) {
 		if (apq8064_sdc1_pdata) {
-			apq8064_sdc1_pdata->disable_bam = true;
+			if (machine_is_apq8064_sim())
+				apq8064_sdc1_pdata->disable_bam = true;
 			apq8064_sdc1_pdata->disable_runtime_pm = true;
 			apq8064_sdc1_pdata->disable_cmd23 = true;
 		}
 		if (apq8064_sdc3_pdata) {
-			apq8064_sdc3_pdata->disable_bam = true;
+			if (machine_is_apq8064_sim())
+				apq8064_sdc3_pdata->disable_bam = true;
 			apq8064_sdc3_pdata->disable_runtime_pm = true;
 			apq8064_sdc3_pdata->disable_cmd23 = true;
 		}
@@ -443,6 +448,118 @@
 	apq8064_add_sdcc(3, apq8064_sdc3_pdata);
 }
 
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0x11000000
+
+#define QCE_HW_KEY_SUPPORT	0
+#define QCE_SHA_HMAC_SUPPORT	1
+#define QCE_SHARE_CE_RESOURCE	3
+#define QCE_CE_SHARED		0
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV8064_CE_IN_CHAN,
+		.end = DMOV8064_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV8064_CE_IN_CRCI,
+		.end = DMOV8064_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV8064_CE_OUT_CRCI,
+		.end = DMOV8064_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV8064_CE_IN_CHAN,
+		.end = DMOV8064_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV8064_CE_IN_CRCI,
+		.end = DMOV8064_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV8064_CE_OUT_CRCI,
+		.end = DMOV8064_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
+
 #define MSM_SHARED_RAM_PHYS 0x80000000
 static void __init apq8064_map_io(void)
 {
@@ -526,6 +643,15 @@
 	&msm8064_device_saw_regulator_core1,
 	&msm8064_device_saw_regulator_core2,
 	&msm8064_device_saw_regulator_core3,
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
 };
 
 static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 9813715..fece76d 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -744,6 +744,7 @@
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
 };
 
 static struct gpiomux_setting hsic_hub_act_cfg = {
@@ -4288,7 +4289,7 @@
 	.update_time		= 60000,
 	.max_voltage		= 4200,
 	.min_voltage		= 3200,
-	.resume_voltage		= 4100,
+	.resume_voltage_delta	= 100,
 	.term_current		= 100,
 	.cool_temp		= 10,
 	.warm_temp		= 40,
@@ -4378,6 +4379,10 @@
 		.num_configs = ARRAY_SIZE(pm8921_led_configs),
 };
 
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+	.r_sense		= 10,
+};
+
 static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
 	.irq_pdata		= &pm8xxx_irq_pdata,
 	.gpio_pdata		= &pm8xxx_gpio_pdata,
@@ -4391,6 +4396,7 @@
 	.bms_pdata		= &pm8921_bms_pdata,
 	.adc_pdata		= &pm8921_adc_pdata,
 	.leds_pdata		= &pm8xxx_leds_pdata,
+	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
 };
 
 static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 95b69e6..85de532 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -26,6 +26,7 @@
 #include <linux/power_supply.h>
 #include <linux/input/rmi_platformdata.h>
 #include <linux/input/rmi_i2c.h>
+#include <linux/regulator/consumer.h>
 #include <asm/mach/mmc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -52,6 +53,7 @@
 #include "pm.h"
 #include "timer.h"
 #include "pm-boot.h"
+#include "board-msm7x27a-regulator.h"
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
@@ -2505,10 +2507,27 @@
 	},
 };
 
+static struct platform_device msm_proccomm_regulator_dev = {
+	.name   = PROCCOMM_REGULATOR_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data = &msm7x27a_proccomm_regulator_data
+	}
+};
+
+static void __init msm7627a_init_regulators(void)
+{
+	int rc = platform_device_register(&msm_proccomm_regulator_dev);
+	if (rc)
+		pr_err("%s: could not register regulator device: %d\n",
+				__func__, rc);
+}
+
 #define UART1DM_RX_GPIO		45
 static void __init msm_qrd1_init(void)
 {
 	msm7x2x_misc_init();
+	msm7627a_init_regulators();
 	msm_device_i2c_init();
 	msm7627a_init_mmc();
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index aaf6c83..c16c2ee 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5158,8 +5158,14 @@
 	CLK_LOOKUP("usb_fs_sys_clk",	usb_fs1_sys_clk.c,	NULL),
 	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		NULL),
-	CLK_LOOKUP("ref_clk",		sata_phy_ref_clk.c,     NULL),
+	CLK_LOOKUP("ref_clk",		sata_phy_ref_clk.c,	NULL),
 	CLK_LOOKUP("cfg_clk",		sata_phy_cfg_clk.c,	NULL),
+	CLK_LOOKUP("iface_clk",		ce3_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("iface_clk",		ce3_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("core_clk",		ce3_core_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce3_core_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("ce3_core_src_clk",	ce3_src_clk.c,		"qce.0"),
+	CLK_LOOKUP("ce3_core_src_clk",	ce3_src_clk.c,		"qcrypto.0"),
 	CLK_LOOKUP("dma_bam_pclk",	dma_bam_p_clk.c,	NULL),
 	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		NULL),
@@ -5178,9 +5184,6 @@
 	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
 	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
 	CLK_LOOKUP("iface_clk",		pcie_p_clk.c,		NULL),
-	CLK_LOOKUP("core_src_clk",	ce3_src_clk.c,		NULL),
-	CLK_LOOKUP("core_clk",          ce3_core_clk.c,         NULL),
-	CLK_LOOKUP("iface_clk",         ce3_p_clk.c,            NULL),
 	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	NULL),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 7e163df..78da29c 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -249,19 +249,83 @@
 	},
 };
 
+static DEFINE_SPINLOCK(soft_vote_lock);
+
+static int pll_acpu_vote_clk_enable(struct clk *clk)
+{
+	int ret = 0;
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&soft_vote_lock, flags);
+
+	if (!*pll->soft_vote)
+		ret = pll_vote_clk_enable(clk);
+	if (ret == 0)
+		*pll->soft_vote |= (pll->soft_vote_mask);
+
+	spin_unlock_irqrestore(&soft_vote_lock, flags);
+	return ret;
+}
+
+static void pll_acpu_vote_clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&soft_vote_lock, flags);
+
+	*pll->soft_vote &= ~(pll->soft_vote_mask);
+	if (!*pll->soft_vote)
+		pll_vote_clk_disable(clk);
+
+	spin_unlock_irqrestore(&soft_vote_lock, flags);
+}
+
+static struct clk_ops clk_ops_pll_acpu_vote = {
+	.enable = pll_acpu_vote_clk_enable,
+	.disable = pll_acpu_vote_clk_disable,
+	.auto_off = pll_acpu_vote_clk_disable,
+	.is_enabled = pll_vote_clk_is_enabled,
+	.get_rate = pll_vote_clk_get_rate,
+	.get_parent = pll_vote_clk_get_parent,
+	.is_local = local_clk_is_local,
+};
+
+#define PLL_SOFT_VOTE_PRIMARY	BIT(0)
+#define PLL_SOFT_VOTE_ACPU	BIT(1)
+
+static unsigned int soft_vote_pll0;
+
 static struct pll_vote_clk pll0_clk = {
 	.rate = 276000000,
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(0),
 	.status_reg = BB_PLL0_STATUS_REG,
 	.parent = &cxo_clk.c,
+	.soft_vote = &soft_vote_pll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
 	.c = {
 		.dbg_name = "pll0_clk",
-		.ops = &clk_ops_pll_vote,
+		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_clk.c),
 	},
 };
 
+static struct pll_vote_clk pll0_acpu_clk = {
+	.rate = 276000000,
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(0),
+	.status_reg = BB_PLL0_STATUS_REG,
+	.soft_vote = &soft_vote_pll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.c = {
+		.dbg_name = "pll0_acpu_clk",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(pll0_acpu_clk.c),
+	},
+};
+
 static struct pll_vote_clk pll4_clk = {
 	.rate = 393216000,
 	.en_reg = BB_PLL_ENA_SC0_REG,
@@ -275,32 +339,68 @@
 	},
 };
 
+static unsigned int soft_vote_pll8;
+
 static struct pll_vote_clk pll8_clk = {
 	.rate = 384000000,
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(8),
 	.status_reg = BB_PLL8_STATUS_REG,
 	.parent = &cxo_clk.c,
+	.soft_vote = &soft_vote_pll8,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
 	.c = {
 		.dbg_name = "pll8_clk",
-		.ops = &clk_ops_pll_vote,
+		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_clk.c),
 	},
 };
 
+static struct pll_vote_clk pll8_acpu_clk = {
+	.rate = 384000000,
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(8),
+	.status_reg = BB_PLL8_STATUS_REG,
+	.soft_vote = &soft_vote_pll8,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.c = {
+		.dbg_name = "pll8_acpu_clk",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(pll8_acpu_clk.c),
+	},
+};
+
+static unsigned int soft_vote_pll9;
+
 static struct pll_vote_clk pll9_clk = {
 	.rate = 440000000,
 	.en_reg = BB_PLL_ENA_SC0_REG,
 	.en_mask = BIT(9),
 	.status_reg = SC_PLL0_STATUS_REG,
 	.parent = &cxo_clk.c,
+	.soft_vote = &soft_vote_pll9,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
 	.c = {
 		.dbg_name = "pll9_clk",
-		.ops = &clk_ops_pll_vote,
+		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll9_clk.c),
 	},
 };
 
+static struct pll_vote_clk pll9_acpu_clk = {
+	.rate = 440000000,
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(9),
+	.soft_vote = &soft_vote_pll9,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.status_reg = SC_PLL0_STATUS_REG,
+	.c = {
+		.dbg_name = "pll9_acpu_clk",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(pll9_acpu_clk.c),
+	},
+};
+
 static struct pll_vote_clk pll14_clk = {
 	.rate = 480000000,
 	.en_reg = BB_PLL_ENA_SC0_REG,
@@ -1557,6 +1657,11 @@
 	CLK_LOOKUP("pll8",	pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll9",	pll9_clk.c,	NULL),
 	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
+
+	CLK_LOOKUP("pll0", pll0_acpu_clk.c, "acpu"),
+	CLK_LOOKUP("pll8", pll8_acpu_clk.c, "acpu"),
+	CLK_LOOKUP("pll9", pll9_acpu_clk.c, "acpu"),
+
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
 	CLK_LOOKUP("cfpb_clk",		cfpb_clk.c,	NULL),
@@ -1772,6 +1877,19 @@
 	/* Enable PLL4 source on the LPASS Primary PLL Mux */
 	regval = readl_relaxed(LCC_PRI_PLL_CLK_CTL_REG);
 	writel_relaxed(regval | BIT(0), LCC_PRI_PLL_CLK_CTL_REG);
+
+	/* Disable hardware clock gating on certain clocks */
+	regval = readl_relaxed(USB_HSIC_HCLK_CTL_REG);
+	regval &= ~BIT(6);
+	writel_relaxed(regval, USB_HSIC_HCLK_CTL_REG);
+
+	regval = readl_relaxed(CE1_CORE_CLK_CTL_REG);
+	regval &= ~BIT(6);
+	writel_relaxed(regval, CE1_CORE_CLK_CTL_REG);
+
+	regval = readl_relaxed(USB_HS1_HCLK_CTL_REG);
+	regval &= ~BIT(6);
+	writel_relaxed(regval, USB_HS1_HCLK_CTL_REG);
 }
 
 /* Local clock driver initialization. */
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index c1cfb55..2391f84 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -641,7 +641,7 @@
 	return 1;
 }
 
-static int pll_vote_clk_enable(struct clk *clk)
+int pll_vote_clk_enable(struct clk *clk)
 {
 	u32 ena;
 	unsigned long flags;
@@ -660,7 +660,7 @@
 	return 0;
 }
 
-static void pll_vote_clk_disable(struct clk *clk)
+void pll_vote_clk_disable(struct clk *clk)
 {
 	u32 ena;
 	unsigned long flags;
@@ -673,19 +673,19 @@
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 }
 
-static unsigned long pll_vote_clk_get_rate(struct clk *clk)
+unsigned long pll_vote_clk_get_rate(struct clk *clk)
 {
 	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
 	return pll->rate;
 }
 
-static struct clk *pll_vote_clk_get_parent(struct clk *clk)
+struct clk *pll_vote_clk_get_parent(struct clk *clk)
 {
 	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
 	return pll->parent;
 }
 
-static int pll_vote_clk_is_enabled(struct clk *clk)
+int pll_vote_clk_is_enabled(struct clk *clk)
 {
 	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
 	return !!(readl_relaxed(pll->status_reg) & BIT(16));
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 16a9955..2107567 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -177,6 +177,8 @@
 /**
  * struct pll_vote_clk - phase locked loop (HW voteable)
  * @rate: output rate
+ * @soft_vote: soft voting variable for multiple PLL software instances
+ * @soft_vote_mask: soft voting mask for multiple PLL software instances
  * @en_reg: enable register
  * @en_mask: ORed with @en_reg to enable the clock
  * @status_reg: status register
@@ -186,6 +188,8 @@
 struct pll_vote_clk {
 	unsigned long rate;
 
+	u32 *soft_vote;
+	const u32 soft_vote_mask;
 	void __iomem *const en_reg;
 	const u32 en_mask;
 
@@ -288,6 +292,15 @@
 bool local_clk_is_local(struct clk *clk);
 
 /*
+ * PLL vote clock APIs
+ */
+int pll_vote_clk_enable(struct clk *clk);
+void pll_vote_clk_disable(struct clk *clk);
+unsigned long pll_vote_clk_get_rate(struct clk *clk);
+struct clk *pll_vote_clk_get_parent(struct clk *clk);
+int pll_vote_clk_is_enabled(struct clk *clk);
+
+/*
  * Generic set-rate implementations
  */
 void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 9b8d5ac..afc2649 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -761,6 +761,12 @@
 	CLK_DUMMY("dfab_clk",		DFAB_CLK,		NULL, 0),
 	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,		NULL, 0),
 	CLK_DUMMY("mem_clk",		EBI1_ADM_CLK,	  "msm_dmov", 0),
+	CLK_DUMMY("ce3_core_src_clk",	CE3_SRC_CLK,     "qce.0", OFF),
+	CLK_DUMMY("ce3_core_src_clk",	CE3_SRC_CLK, "qcrypto.0", OFF),
+	CLK_DUMMY("core_clk",		CE3_CORE_CLK,	      "qce.0", OFF),
+	CLK_DUMMY("core_clk",		CE3_CORE_CLK,	  "qcrypto.0", OFF),
+	CLK_DUMMY("iface_clk",		CE3_P_CLK,	     "qce0.0", OFF),
+	CLK_DUMMY("iface_clk",		CE3_P_CLK,	  "qcrypto.0", OFF),
 };
 
 struct clock_init_data apq8064_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 47e33d0..012eb85 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -145,6 +145,31 @@
 	},
 };
 
+static struct resource resources_hsusb_host[] = {
+	{
+		.start  = MSM9615_HSUSB_PHYS,
+		.end    = MSM9615_HSUSB_PHYS + MSM9615_HSUSB_PHYS - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB1_HS_IRQ,
+		.end    = USB1_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_hsusb_host = {
+	.name           = "msm_hsusb_host",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_hsusb_host),
+	.resource       = resources_hsusb_host,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
 static struct resource resources_uart_gsbi4[] = {
 	{
 		.start	= GSBI4_UARTDM_IRQ,
@@ -668,53 +693,47 @@
 };
 
 static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] = {
-	[1] = MSM_GPIO_TO_INT(46),
-	[2] = MSM_GPIO_TO_INT(150),
-	[4] = MSM_GPIO_TO_INT(103),
-	[5] = MSM_GPIO_TO_INT(104),
-	[6] = MSM_GPIO_TO_INT(105),
-	[7] = MSM_GPIO_TO_INT(106),
-	[8] = MSM_GPIO_TO_INT(107),
-	[9] = MSM_GPIO_TO_INT(7),
-	[10] = MSM_GPIO_TO_INT(11),
-	[11] = MSM_GPIO_TO_INT(15),
-	[12] = MSM_GPIO_TO_INT(19),
-	[13] = MSM_GPIO_TO_INT(23),
-	[14] = MSM_GPIO_TO_INT(27),
-	[15] = MSM_GPIO_TO_INT(31),
-	[16] = MSM_GPIO_TO_INT(35),
-	[19] = MSM_GPIO_TO_INT(90),
-	[20] = MSM_GPIO_TO_INT(92),
-	[23] = MSM_GPIO_TO_INT(85),
-	[24] = MSM_GPIO_TO_INT(83),
+	[4] = MSM_GPIO_TO_INT(30),
+	[5] = MSM_GPIO_TO_INT(59),
+	[6] = MSM_GPIO_TO_INT(81),
+	[7] = MSM_GPIO_TO_INT(87),
+	[8] = MSM_GPIO_TO_INT(86),
+	[9] = MSM_GPIO_TO_INT(2),
+	[10] = MSM_GPIO_TO_INT(6),
+	[11] = MSM_GPIO_TO_INT(10),
+	[12] = MSM_GPIO_TO_INT(14),
+	[13] = MSM_GPIO_TO_INT(18),
+	[14] = MSM_GPIO_TO_INT(7),
+	[15] = MSM_GPIO_TO_INT(11),
+	[16] = MSM_GPIO_TO_INT(15),
+	[19] = MSM_GPIO_TO_INT(26),
+	[20] = MSM_GPIO_TO_INT(28),
+	[23] = MSM_GPIO_TO_INT(19),
+	[24] = MSM_GPIO_TO_INT(23),
 	[25] = USB1_HS_IRQ,
-	/*[27] = HDMI_IRQ,*/
-	[29] = MSM_GPIO_TO_INT(10),
-	[30] = MSM_GPIO_TO_INT(102),
-	[31] = MSM_GPIO_TO_INT(81),
-	[32] = MSM_GPIO_TO_INT(78),
-	[33] = MSM_GPIO_TO_INT(94),
-	[34] = MSM_GPIO_TO_INT(72),
-	[35] = MSM_GPIO_TO_INT(39),
-	[36] = MSM_GPIO_TO_INT(43),
-	[37] = MSM_GPIO_TO_INT(61),
-	[38] = MSM_GPIO_TO_INT(50),
-	[39] = MSM_GPIO_TO_INT(42),
-	[41] = MSM_GPIO_TO_INT(62),
-	[42] = MSM_GPIO_TO_INT(76),
-	[43] = MSM_GPIO_TO_INT(75),
-	[44] = MSM_GPIO_TO_INT(70),
-	[45] = MSM_GPIO_TO_INT(69),
-	[46] = MSM_GPIO_TO_INT(67),
-	[47] = MSM_GPIO_TO_INT(65),
-	[48] = MSM_GPIO_TO_INT(58),
-	[49] = MSM_GPIO_TO_INT(54),
-	[50] = MSM_GPIO_TO_INT(52),
-	[51] = MSM_GPIO_TO_INT(49),
-	[52] = MSM_GPIO_TO_INT(40),
-	[53] = MSM_GPIO_TO_INT(37),
-	[54] = MSM_GPIO_TO_INT(24),
-	[55] = MSM_GPIO_TO_INT(14),
+	[26] = MSM_GPIO_TO_INT(3),
+	[27] = MSM_GPIO_TO_INT(68),
+	[29] = MSM_GPIO_TO_INT(78),
+	[31] = MSM_GPIO_TO_INT(0),
+	[32] = MSM_GPIO_TO_INT(4),
+	[33] = MSM_GPIO_TO_INT(22),
+	[34] = MSM_GPIO_TO_INT(17),
+	[37] = MSM_GPIO_TO_INT(20),
+	[39] = MSM_GPIO_TO_INT(84),
+	[42] = MSM_GPIO_TO_INT(24),
+	[43] = MSM_GPIO_TO_INT(79),
+	[44] = MSM_GPIO_TO_INT(80),
+	[45] = MSM_GPIO_TO_INT(82),
+	[46] = MSM_GPIO_TO_INT(85),
+	[47] = MSM_GPIO_TO_INT(45),
+	[48] = MSM_GPIO_TO_INT(50),
+	[49] = MSM_GPIO_TO_INT(51),
+	[50] = MSM_GPIO_TO_INT(69),
+	[51] = MSM_GPIO_TO_INT(77),
+	[52] = MSM_GPIO_TO_INT(1),
+	[53] = MSM_GPIO_TO_INT(5),
+	[54] = MSM_GPIO_TO_INT(40),
+	[55] = MSM_GPIO_TO_INT(27),
 };
 
 static uint16_t msm_mpm_bypassed_apps_irqs[] = {
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 5a31f70..e8aa38e 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -12,6 +12,7 @@
 
 #include <asm/cacheflush.h>
 
+#ifdef CONFIG_SMP
 extern volatile int pen_release;
 
 static inline void cpu_enter_lowpower(void)
@@ -55,6 +56,7 @@
 		pr_debug("CPU%u: spurious wakeup call\n", cpu);
 	}
 }
+#endif
 
 int platform_cpu_kill(unsigned int cpu)
 {
@@ -68,6 +70,7 @@
  */
 void platform_cpu_die(unsigned int cpu)
 {
+#ifdef CONFIG_SMP
 	/*
 	 * we're ready for shutdown now, so do it
 	 */
@@ -79,6 +82,7 @@
 	 * coherency, and then restore interrupts
 	 */
 	cpu_leave_lowpower();
+#endif
 }
 
 int platform_cpu_disable(unsigned int cpu)
diff --git a/arch/arm/mach-msm/include/mach/barriers.h b/arch/arm/mach-msm/include/mach/barriers.h
index 919186b..2d4792c 100644
--- a/arch/arm/mach-msm/include/mach/barriers.h
+++ b/arch/arm/mach-msm/include/mach/barriers.h
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  *
  */
+#include <mach/memory.h>
+
 #define mb() do \
 	{ \
 		dsb();\
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 1474fcb..3cb79b7 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -245,6 +245,13 @@
 #define DMOV_HSUART2_RX_CRCI   15
 #endif
 
+/* channels for APQ8064 */
+#define DMOV8064_CE_IN_CHAN        2
+#define DMOV8064_CE_IN_CRCI       14
+
+#define DMOV8064_CE_OUT_CHAN       3
+#define DMOV8064_CE_OUT_CRCI       15
+
 
 /* no client rate control ifc (eg, ram) */
 #define DMOV_NONE_CRCI        0
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index e34abb1..d6cdbe7 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -25,16 +25,3 @@
 
 void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
 EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-
-int platform_cpu_disable(unsigned int cpu)
-{
-	return -ENOSYS;
-}
-
-int platform_cpu_kill(unsigned int cpu)
-{
-	return -ENOSYS;
-}
-
-void platform_cpu_die(unsigned int cpu)
-{ }
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 65a2c54..f9445d8 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -661,6 +661,7 @@
 	q6asm_audio_client_free(audio->ac);
 	mutex_unlock(&audio->lock);
 	kfree(audio->enc_cfg);
+	kfree(audio->codec_cfg);
 	kfree(audio);
 	return 0;
 }
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
index 16258eb..f978554 100644
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -43,7 +43,7 @@
 struct lpa_if {
 	struct mutex lock;
 	struct msm_audio_config cfg;
-	struct audio_buffer audio_buf[2];
+	struct audio_buffer audio_buf[6];
 	int cpu_buf;		/* next buffer the CPU will touch */
 	int dma_buf;		/* next buffer the DMA will touch */
 	u8 *buffer;
@@ -52,6 +52,7 @@
 	wait_queue_head_t wait;
 	u32 config;
 	u32 dma_period_sz;
+	unsigned int num_periods;
 };
 
 static struct lpa_if  *lpa_if_ptr;
@@ -85,9 +86,11 @@
 
 		pr_debug("dma_buf %d  used %d\n", lpa_if->dma_buf,
 			lpa_if->audio_buf[lpa_if->dma_buf].used);
+		lpa_if->dma_buf++;
+		lpa_if->dma_buf = lpa_if->dma_buf % lpa_if->cfg.buffer_count;
 
-		lpa_if->dma_buf ^= 1;
-
+		if (lpa_if->dma_buf == lpa_if->cpu_buf)
+			pr_err("Err:both dma_buf and cpu_buf are on same index\n");
 		wake_up(&lpa_if->wait);
 	}
 	return IRQ_HANDLED;
@@ -114,7 +117,7 @@
 
 	dma_params.src_start = lpa_if->buffer_phys;
 	dma_params.buffer = lpa_if->buffer;
-	dma_params.buffer_size = lpa_if->dma_period_sz * 2;
+	dma_params.buffer_size = lpa_if->dma_period_sz * lpa_if->num_periods;
 	dma_params.period_size = lpa_if->dma_period_sz;
 	dma_params.channels = 2;
 
@@ -143,7 +146,7 @@
 {
 	struct lpa_if *lpa_if = file->private_data;
 	int rc = 0;
-
+	unsigned int i;
 	pr_debug("cmd %u\n", cmd);
 
 	mutex_lock(&lpa_if->lock);
@@ -188,25 +191,28 @@
 			pr_debug("%s:failed to copy from user\n", __func__);
 			rc = -EFAULT;
 		}
-		if ((lpa_if->dma_period_sz * 2) > DMA_ALLOC_BUF_SZ) {
+		if ((lpa_if->dma_period_sz * lpa_if->num_periods) >
+			DMA_ALLOC_BUF_SZ) {
 			pr_err("Dma buffer size greater than allocated size\n");
 			return -EINVAL;
 		}
 		pr_debug("Dma_period_sz %d\n", lpa_if->dma_period_sz);
-		lpa_if->cfg.buffer_count = 2;
-		lpa_if->cfg.buffer_size = lpa_if->dma_period_sz * 2;
+		if (lpa_if->dma_period_sz < (2 * SZ_4K))
+			lpa_if->num_periods = 6;
+		pr_debug("No. of Periods %d\n", lpa_if->num_periods);
 
-		lpa_if->audio_buf[0].phys = lpa_if->buffer_phys;
-		lpa_if->audio_buf[0].data = lpa_if->buffer;
-		lpa_if->audio_buf[0].size = lpa_if->dma_period_sz;
-		lpa_if->audio_buf[0].used = 0;
+		lpa_if->cfg.buffer_count = lpa_if->num_periods;
+		lpa_if->cfg.buffer_size = lpa_if->dma_period_sz *
+						lpa_if->num_periods;
 
-		lpa_if->audio_buf[1].phys =
-				lpa_if->buffer_phys + lpa_if->dma_period_sz;
-		lpa_if->audio_buf[1].data =
-				lpa_if->buffer + lpa_if->dma_period_sz;
-		lpa_if->audio_buf[1].size = lpa_if->dma_period_sz;
-		lpa_if->audio_buf[1].used = 0;
+		for (i = 0; i < lpa_if->cfg.buffer_count; i++) {
+			lpa_if->audio_buf[i].phys =
+				lpa_if->buffer_phys + i * lpa_if->dma_period_sz;
+			lpa_if->audio_buf[i].data =
+				lpa_if->buffer + i * lpa_if->dma_period_sz;
+			lpa_if->audio_buf[i].size = lpa_if->dma_period_sz;
+			lpa_if->audio_buf[i].used = 0;
+		}
 		break;
 	default:
 		pr_err("UnKnown Ioctl\n");
@@ -225,8 +231,9 @@
 
 	file->private_data = lpa_if_ptr;
 	dma_buf_index = 0;
-	lpa_if_ptr->cpu_buf = 0;
+	lpa_if_ptr->cpu_buf = 2;
 	lpa_if_ptr->dma_buf = 0;
+	lpa_if_ptr->num_periods = 4;
 
 	core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
 	mb();
@@ -234,6 +241,17 @@
 	return 0;
 }
 
+static inline int rt_policy(int policy)
+{
+	if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+		return 1;
+	return 0;
+}
+
+static inline int task_has_rt_policy(struct task_struct *p)
+{
+	return rt_policy(p->policy);
+}
 static ssize_t lpa_if_write(struct file *file, const char __user *buf,
 		size_t count, loff_t *pos)
 {
@@ -241,7 +259,19 @@
 	struct audio_buffer *ab;
 	const char __user *start = buf;
 	int xfer, rc;
+	struct sched_param s = { .sched_priority = 1 };
+	int old_prio = current->rt_priority;
+	int old_policy = current->policy;
+	int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
 
+	 /* just for this write, set us real-time */
+	if (!task_has_rt_policy(current)) {
+		struct cred *new = prepare_creds();
+		cap_raise(new->cap_effective, CAP_SYS_NICE);
+		commit_creds(new);
+		if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
+			pr_err("sched_setscheduler failed\n");
+	}
 	mutex_lock(&lpa_if->lock);
 
 	if (dma_buf_index < 2) {
@@ -299,12 +329,23 @@
 
 		pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
 			xfer, ab->size, ab->used, lpa_if->cpu_buf);
-
-		lpa_if->cpu_buf ^= 1;
+		lpa_if->cpu_buf++;
+		lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count;
 	}
 	rc = buf - start;
 end:
 	mutex_unlock(&lpa_if->lock);
+	/* restore old scheduling policy */
+	if (!rt_policy(old_policy)) {
+		struct sched_param v = { .sched_priority = old_prio };
+		if ((sched_setscheduler(current, old_policy, &v)) < 0)
+			pr_err("sched_setscheduler failed\n");
+		if (likely(!cap_nice)) {
+			struct cred *new = prepare_creds();
+			cap_lower(new->cap_effective, CAP_SYS_NICE);
+			commit_creds(new);
+		}
+	}
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 7c7a822..4744f1f 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -63,7 +63,6 @@
 	int i;
 
 	int blocking_write;
-	int needed_space;
 	int is_open;
 	unsigned ch_size;
 	uint open_modem_wait;
@@ -155,7 +154,7 @@
 	smd_pkt_devp->is_open = 0;
 
 	wake_up(&smd_pkt_devp->ch_read_wait_queue);
-	wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+	wake_up(&smd_pkt_devp->ch_write_wait_queue);
 	wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
 }
 
@@ -305,7 +304,7 @@
 		       size_t count,
 		       loff_t *ppos)
 {
-	int r = 0;
+	int r = 0, bytes_written;
 	struct smd_pkt_dev *smd_pkt_devp;
 	DEFINE_WAIT(write_wait);
 
@@ -317,84 +316,56 @@
 	if (!smd_pkt_devp || !smd_pkt_devp->ch)
 		return -EINVAL;
 
-	if (count > smd_pkt_devp->ch_size)
-		return -EINVAL;
-
 	if (smd_pkt_devp->do_reset_notification) {
 		/* notify client that a reset occurred */
 		return notify_reset(smd_pkt_devp);
 	}
 
-	if (smd_pkt_devp->blocking_write) {
-		for (;;) {
-			mutex_lock(&smd_pkt_devp->tx_lock);
-			if (smd_pkt_devp->has_reset) {
-				smd_disable_read_intr(smd_pkt_devp->ch);
-				mutex_unlock(&smd_pkt_devp->tx_lock);
-				return notify_reset(smd_pkt_devp);
-			}
-			if (signal_pending(current)) {
-				smd_disable_read_intr(smd_pkt_devp->ch);
-				mutex_unlock(&smd_pkt_devp->tx_lock);
-				return -ERESTARTSYS;
-			}
-
-			prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
-					&write_wait, TASK_INTERRUPTIBLE);
-			smd_enable_read_intr(smd_pkt_devp->ch);
-			if (smd_write_avail(smd_pkt_devp->ch) < count) {
-				if (!smd_pkt_devp->needed_space ||
-				    count < smd_pkt_devp->needed_space)
-					smd_pkt_devp->needed_space = count;
-				mutex_unlock(&smd_pkt_devp->tx_lock);
-				schedule();
-			} else
-				break;
-		}
-		finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
-		smd_disable_read_intr(smd_pkt_devp->ch);
-		if (smd_pkt_devp->has_reset) {
-			mutex_unlock(&smd_pkt_devp->tx_lock);
-			return notify_reset(smd_pkt_devp);
-		}
-		if (signal_pending(current)) {
-			mutex_unlock(&smd_pkt_devp->tx_lock);
-			return -ERESTARTSYS;
-		}
-	} else {
-		if (smd_pkt_devp->has_reset)
-			return notify_reset(smd_pkt_devp);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-
-		mutex_lock(&smd_pkt_devp->tx_lock);
+	mutex_lock(&smd_pkt_devp->tx_lock);
+	if (!smd_pkt_devp->blocking_write) {
 		if (smd_write_avail(smd_pkt_devp->ch) < count) {
 			D(KERN_ERR "%s: Not enough space to write\n",
-				    __func__);
+				   __func__);
 			mutex_unlock(&smd_pkt_devp->tx_lock);
 			return -ENOMEM;
 		}
 	}
 
-	D_DUMP_BUFFER("write: ", count, buf);
-
-	smd_pkt_devp->needed_space = 0;
-
-	r = smd_write_user_buffer(smd_pkt_devp->ch, buf, count);
-	if (r != count) {
+	r = smd_write_start(smd_pkt_devp->ch, count);
+	if (r < 0) {
 		mutex_unlock(&smd_pkt_devp->tx_lock);
-		if (smd_pkt_devp->has_reset)
-			return notify_reset(smd_pkt_devp);
-
-		printk(KERN_ERR "ERROR:%s:%i:%s: "
-		       "smd_write(ch,buf,count = %i) ret %i.\n",
-		       __FILE__,
-		       __LINE__,
-		       __func__,
-		       count,
-		       r);
+		pr_err("%s: Error %d @ smd_write_start\n", __func__, r);
 		return r;
 	}
+
+	bytes_written = 0;
+	do {
+		prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
+				&write_wait, TASK_UNINTERRUPTIBLE);
+		if (!smd_write_avail(smd_pkt_devp->ch) &&
+		    !smd_pkt_devp->has_reset) {
+			smd_enable_read_intr(smd_pkt_devp->ch);
+			schedule();
+		}
+		finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
+		smd_disable_read_intr(smd_pkt_devp->ch);
+
+		if (smd_pkt_devp->has_reset) {
+			mutex_unlock(&smd_pkt_devp->tx_lock);
+			return notify_reset(smd_pkt_devp);
+		} else {
+			r = smd_write_segment(smd_pkt_devp->ch,
+					      (void *)(buf + bytes_written),
+					      (count - bytes_written), 1);
+			if (r < 0) {
+				mutex_unlock(&smd_pkt_devp->tx_lock);
+				if (smd_pkt_devp->has_reset)
+					return notify_reset(smd_pkt_devp);
+			}
+			bytes_written += r;
+		}
+	} while (bytes_written != count);
+	smd_write_end(smd_pkt_devp->ch);
 	mutex_unlock(&smd_pkt_devp->tx_lock);
 
 	D(KERN_ERR "%s: just wrote %i bytes\n",
@@ -451,11 +422,11 @@
 		return;
 
 	sz = smd_write_avail(smd_pkt_devp->ch);
-	if (sz >= smd_pkt_devp->needed_space) {
+	if (sz) {
 		D(KERN_ERR "%s: %d bytes Write Space available\n",
 			    __func__, sz);
 		smd_disable_read_intr(smd_pkt_devp->ch);
-		wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+		wake_up(&smd_pkt_devp->ch_write_wait_queue);
 	}
 }
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 96a4563..c4bc76c 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -31,6 +31,7 @@
 	HW_PLATFORM_FLUID   = 3,
 	HW_PLATFORM_SVLTE_FFA	= 4,
 	HW_PLATFORM_SVLTE_SURF	= 5,
+	HW_PLATFORM_LIQUID  = 9,
 	/* Dragonboard platform id is assigned as 10 in CDT */
 	HW_PLATFORM_DRAGON	= 10,
 	HW_PLATFORM_INVALID
@@ -41,6 +42,7 @@
 	[HW_PLATFORM_SURF] = "Surf",
 	[HW_PLATFORM_FFA] = "FFA",
 	[HW_PLATFORM_FLUID] = "Fluid",
+	[HW_PLATFORM_LIQUID] = "Liquid",
 	[HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
 	[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
 	[HW_PLATFORM_DRAGON] = "Dragon"
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 2ef5c61..18b7334 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -21,6 +21,7 @@
 #include <mach/scm.h>
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
+#include <mach/peripheral-loader.h>
 #include "smd_private.h"
 #include "ramdump.h"
 
@@ -35,10 +36,14 @@
 static void *riva_ramdump_dev;
 static int riva_crash;
 static int ss_restart_inprogress;
+static int enable_riva_ssr;
 
 static void riva_smsm_cb_fn(struct work_struct *work)
 {
-	panic(MODULE_NAME ": SMSM reset request received from Riva");
+	if (!enable_riva_ssr)
+		panic(MODULE_NAME ": SMSM reset request received from Riva");
+	else
+		subsystem_restart("riva");
 }
 
 static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
@@ -74,13 +79,13 @@
 /* Subsystem handlers */
 static int riva_shutdown(const struct subsys_data *subsys)
 {
-	/* TODO for phase 3 */
+	pil_force_shutdown("wcnss");
 	return 0;
 }
 
 static int riva_powerup(const struct subsys_data *subsys)
 {
-	/* TODO for phase 3 */
+	pil_force_boot("wcnss");
 	return 0;
 }
 
@@ -118,6 +123,23 @@
 	.crash_shutdown = riva_crash_shutdown
 };
 
+static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_set_int(val, kp);
+	if (ret)
+		return ret;
+
+	if (enable_riva_ssr)
+		pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
+
+	return 0;
+}
+
+module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
+			&enable_riva_ssr, S_IRUGO | S_IWUSR);
+
 static int __init riva_restart_init(void)
 {
 	return ssr_register_subsystem(&riva_8960);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 2c6957d..baf3170 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1131,3 +1131,4 @@
 msm7625a_surf		MACH_MSM7625A_SURF	MSM7625A_SURF		3772
 msm8627_cdp		MACH_MSM8627_CDP	MSM8627_CDP		3861
 msm8627_mtp		MACH_MSM8627_MTP	MSM8627_MTP		3862
+msm8625_rumi3		MACH_MSM8625_RUMI3	MSM8625_RUMI3		3871
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d57e8d0..12f5c47 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -168,4 +168,18 @@
 	bool
 	default n
 
+config GENLOCK
+	bool "Enable a generic cross-process locking mechanism"
+	depends on ANON_INODES
+	help
+	  Enable a generic cross-process locking API to provide protection
+	  for shared memory objects such as graphics buffers.
+
+config GENLOCK_MISCDEVICE
+	bool "Enable a misc-device for userspace to access the genlock engine"
+	depends on GENLOCK
+	help
+	  Create a miscdevice for the purposes of allowing userspace to create
+	  and interact with locks created using genlock.
+
 endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 4c5701c..d3e2ec1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -8,6 +8,7 @@
 obj-y			+= power/
 obj-$(CONFIG_HAS_DMA)	+= dma-mapping.o
 obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
+obj-$(CONFIG_GENLOCK) += genlock.o
 obj-$(CONFIG_ISA)	+= isa.o
 obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
 obj-$(CONFIG_NUMA)	+= node.o
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
new file mode 100644
index 0000000..40b9575
--- /dev/null
+++ b/drivers/base/genlock.c
@@ -0,0 +1,620 @@
+/* Copyright (c) 2011, 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/fb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/file.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/anon_inodes.h>
+#include <linux/miscdevice.h>
+#include <linux/genlock.h>
+
+/* Lock states - can either be unlocked, held as an exclusive write lock or a
+ * shared read lock
+ */
+
+#define _UNLOCKED 0
+#define _RDLOCK  GENLOCK_RDLOCK
+#define _WRLOCK GENLOCK_WRLOCK
+
+struct genlock {
+	struct list_head active;  /* List of handles holding lock */
+	spinlock_t lock;          /* Spinlock to protect the lock internals */
+	wait_queue_head_t queue;  /* Holding pen for processes pending lock */
+	struct file *file;        /* File structure for exported lock */
+	int state;                /* Current state of the lock */
+};
+
+struct genlock_handle {
+	struct genlock *lock;     /* Lock currently attached to the handle */
+	struct list_head entry;   /* List node for attaching to a lock */
+	struct file *file;        /* File structure associated with handle */
+	int active;		  /* Number of times the active lock has been
+				     taken */
+};
+
+/*
+ * Release the genlock object. Called when all the references to
+ * the genlock file descriptor are released
+ */
+
+static int genlock_release(struct inode *inodep, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations genlock_fops = {
+	.release = genlock_release,
+};
+
+/**
+ * genlock_create_lock - Create a new lock
+ * @handle - genlock handle to attach the lock to
+ *
+ * Returns: a pointer to the genlock
+ */
+
+struct genlock *genlock_create_lock(struct genlock_handle *handle)
+{
+	struct genlock *lock;
+
+	if (handle->lock != NULL)
+		return ERR_PTR(-EINVAL);
+
+	lock = kzalloc(sizeof(*lock), GFP_KERNEL);
+	if (lock == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&lock->active);
+	init_waitqueue_head(&lock->queue);
+	spin_lock_init(&lock->lock);
+
+	lock->state = _UNLOCKED;
+
+	/*
+	 * Create an anonyonmous inode for the object that can exported to
+	 * other processes
+	 */
+
+	lock->file = anon_inode_getfile("genlock", &genlock_fops,
+		lock, O_RDWR);
+
+	/* Attach the new lock to the handle */
+	handle->lock = lock;
+
+	return lock;
+}
+EXPORT_SYMBOL(genlock_create_lock);
+
+/*
+ * Get a file descriptor reference to a lock suitable for sharing with
+ * other processes
+ */
+
+static int genlock_get_fd(struct genlock *lock)
+{
+	int ret;
+
+	if (!lock->file)
+		return -EINVAL;
+
+	ret = get_unused_fd_flags(0);
+	if (ret < 0)
+		return ret;
+	fd_install(ret, lock->file);
+	return ret;
+}
+
+/**
+ * genlock_attach_lock - Attach an existing lock to a handle
+ * @handle - Pointer to a genlock handle to attach the lock to
+ * @fd - file descriptor for the exported lock
+ *
+ * Returns: A pointer to the attached lock structure
+ */
+
+struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
+{
+	struct file *file;
+
+	if (handle->lock != NULL)
+		return ERR_PTR(-EINVAL);
+
+	file = fget(fd);
+	if (file == NULL)
+		return ERR_PTR(-EBADF);
+
+	handle->lock = file->private_data;
+
+	return handle->lock;
+}
+EXPORT_SYMBOL(genlock_attach_lock);
+
+/* Helper function that returns 1 if the specified handle holds the lock */
+
+static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
+{
+	struct genlock_handle *h;
+
+	list_for_each_entry(h, &lock->active, entry) {
+		if (h == handle)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* If the lock just became available, signal the next entity waiting for it */
+
+static void _genlock_signal(struct genlock *lock)
+{
+	if (list_empty(&lock->active)) {
+		/* If the list is empty, then the lock is free */
+		lock->state = _UNLOCKED;
+		/* Wake up the first process sitting in the queue */
+		wake_up(&lock->queue);
+	}
+}
+
+/* Attempt to release the handle's ownership of the lock */
+
+static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
+{
+	int ret = -EINVAL;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&lock->lock, irqflags);
+
+	if (lock->state == _UNLOCKED)
+		goto done;
+
+	/* Make sure this handle is an owner of the lock */
+	if (!handle_has_lock(lock, handle))
+		goto done;
+
+	/* If the handle holds no more references to the lock then
+	   release it (maybe) */
+
+	if (--handle->active == 0) {
+		list_del(&handle->entry);
+		_genlock_signal(lock);
+	}
+
+	ret = 0;
+
+done:
+	spin_unlock_irqrestore(&lock->lock, irqflags);
+	return ret;
+}
+
+/* Attempt to acquire the lock for the handle */
+
+static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
+	int op, int flags, uint32_t timeout)
+{
+	unsigned long irqflags;
+	int ret = 0;
+	unsigned int ticks = msecs_to_jiffies(timeout);
+
+	spin_lock_irqsave(&lock->lock, irqflags);
+
+	/* Sanity check - no blocking locks in a debug context. Even if it
+	 * succeed to not block, the mere idea is too dangerous to continue
+	 */
+
+	if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
+		BUG();
+
+	/* Fast path - the lock is unlocked, so go do the needful */
+
+	if (lock->state == _UNLOCKED)
+		goto dolock;
+
+	if (handle_has_lock(lock, handle)) {
+
+		/*
+		 * If the handle already holds the lock and the type matches,
+		 * then just increment the active pointer. This allows the
+		 * handle to do recursive locks
+		 */
+
+		if (lock->state == op) {
+			handle->active++;
+			goto done;
+		}
+
+		/*
+		 * If the handle holds a write lock then the owner can switch
+		 * to a read lock if they want. Do the transition atomically
+		 * then wake up any pending waiters in case they want a read
+		 * lock too.
+		 */
+
+		if (op == _RDLOCK && handle->active == 1) {
+			lock->state = _RDLOCK;
+			wake_up(&lock->queue);
+			goto done;
+		}
+
+		/*
+		 * Otherwise the user tried to turn a read into a write, and we
+		 * don't allow that.
+		 */
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 * If we request a read and the lock is held by a read, then go
+	 * ahead and share the lock
+	 */
+
+	if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
+		goto dolock;
+
+	/* Treat timeout 0 just like a NOBLOCK flag and return if the
+	   lock cannot be aquired without blocking */
+
+	if (flags & GENLOCK_NOBLOCK || timeout == 0) {
+		ret = -EAGAIN;
+		goto done;
+	}
+
+	/* Wait while the lock remains in an incompatible state */
+
+	while (lock->state != _UNLOCKED) {
+		unsigned int elapsed;
+
+		spin_unlock_irqrestore(&lock->lock, irqflags);
+
+		elapsed = wait_event_interruptible_timeout(lock->queue,
+			lock->state == _UNLOCKED, ticks);
+
+		spin_lock_irqsave(&lock->lock, irqflags);
+
+		if (elapsed <= 0) {
+			ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
+			goto done;
+		}
+
+		ticks = elapsed;
+	}
+
+dolock:
+	/* We can now get the lock, add ourselves to the list of owners */
+
+	list_add_tail(&handle->entry, &lock->active);
+	lock->state = op;
+	handle->active = 1;
+
+done:
+	spin_unlock_irqrestore(&lock->lock, irqflags);
+	return ret;
+
+}
+
+/**
+ * genlock_lock - Acquire or release a lock
+ * @handle - pointer to the genlock handle that is requesting the lock
+ * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
+ * @flags - flags to control the operation
+ * @timeout - optional timeout to wait for the lock to come free
+ *
+ * Returns: 0 on success or error code on failure
+ */
+
+int genlock_lock(struct genlock_handle *handle, int op, int flags,
+	uint32_t timeout)
+{
+	struct genlock *lock = handle->lock;
+	int ret = 0;
+
+	if (lock == NULL)
+		return -EINVAL;
+
+	switch (op) {
+	case GENLOCK_UNLOCK:
+		ret = _genlock_unlock(lock, handle);
+		break;
+	case GENLOCK_RDLOCK:
+	case GENLOCK_WRLOCK:
+		ret = _genlock_lock(lock, handle, op, flags, timeout);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(genlock_lock);
+
+/**
+ * genlock_wait - Wait for the lock to be released
+ * @handle - pointer to the genlock handle that is waiting for the lock
+ * @timeout - optional timeout to wait for the lock to get released
+ */
+
+int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
+{
+	struct genlock *lock = handle->lock;
+	unsigned long irqflags;
+	int ret = 0;
+	unsigned int ticks = msecs_to_jiffies(timeout);
+
+	if (lock == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(&lock->lock, irqflags);
+
+	/*
+	 * if timeout is 0 and the lock is already unlocked, then success
+	 * otherwise return -EAGAIN
+	 */
+
+	if (timeout == 0) {
+		ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
+		goto done;
+	}
+
+	while (lock->state != _UNLOCKED) {
+		unsigned int elapsed;
+
+		spin_unlock_irqrestore(&lock->lock, irqflags);
+
+		elapsed = wait_event_interruptible_timeout(lock->queue,
+			lock->state == _UNLOCKED, ticks);
+
+		spin_lock_irqsave(&lock->lock, irqflags);
+
+		if (elapsed <= 0) {
+			ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
+			break;
+		}
+
+		ticks = elapsed;
+	}
+
+done:
+	spin_unlock_irqrestore(&lock->lock, irqflags);
+	return ret;
+}
+
+/**
+ * genlock_release_lock - Release a lock attached to a handle
+ * @handle - Pointer to the handle holding the lock
+ */
+
+void genlock_release_lock(struct genlock_handle *handle)
+{
+	unsigned long flags;
+
+	if (handle == NULL || handle->lock == NULL)
+		return;
+
+	spin_lock_irqsave(&handle->lock->lock, flags);
+
+	/* If the handle is holding the lock, then force it closed */
+
+	if (handle_has_lock(handle->lock, handle)) {
+		list_del(&handle->entry);
+		_genlock_signal(handle->lock);
+	}
+	spin_unlock_irqrestore(&handle->lock->lock, flags);
+
+	fput(handle->lock->file);
+	handle->lock = NULL;
+	handle->active = 0;
+}
+EXPORT_SYMBOL(genlock_release_lock);
+
+/*
+ * Release function called when all references to a handle are released
+ */
+
+static int genlock_handle_release(struct inode *inodep, struct file *file)
+{
+	struct genlock_handle *handle = file->private_data;
+
+	genlock_release_lock(handle);
+	kfree(handle);
+
+	return 0;
+}
+
+static const struct file_operations genlock_handle_fops = {
+	.release = genlock_handle_release
+};
+
+/*
+ * Allocate a new genlock handle
+ */
+
+static struct genlock_handle *_genlock_get_handle(void)
+{
+	struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (handle == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	return handle;
+}
+
+/**
+ * genlock_get_handle - Create a new genlock handle
+ *
+ * Returns: A pointer to a new genlock handle
+ */
+
+struct genlock_handle *genlock_get_handle(void)
+{
+	struct genlock_handle *handle = _genlock_get_handle();
+	if (IS_ERR(handle))
+		return handle;
+
+	handle->file = anon_inode_getfile("genlock-handle",
+		&genlock_handle_fops, handle, O_RDWR);
+
+	return handle;
+}
+EXPORT_SYMBOL(genlock_get_handle);
+
+/**
+ * genlock_put_handle - release a reference to a genlock handle
+ * @handle - A pointer to the handle to release
+ */
+
+void genlock_put_handle(struct genlock_handle *handle)
+{
+	if (handle)
+		fput(handle->file);
+}
+EXPORT_SYMBOL(genlock_put_handle);
+
+/**
+ * genlock_get_handle_fd - Get a handle reference from a file descriptor
+ * @fd - The file descriptor for a genlock handle
+ */
+
+struct genlock_handle *genlock_get_handle_fd(int fd)
+{
+	struct file *file = fget(fd);
+
+	if (file == NULL)
+		return ERR_PTR(-EINVAL);
+
+	return file->private_data;
+}
+EXPORT_SYMBOL(genlock_get_handle_fd);
+
+#ifdef CONFIG_GENLOCK_MISCDEVICE
+
+static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	struct genlock_lock param;
+	struct genlock_handle *handle = filep->private_data;
+	struct genlock *lock;
+	int ret;
+
+	switch (cmd) {
+	case GENLOCK_IOC_NEW: {
+		lock = genlock_create_lock(handle);
+		if (IS_ERR(lock))
+			return PTR_ERR(lock);
+
+		return 0;
+	}
+	case GENLOCK_IOC_EXPORT: {
+		if (handle->lock == NULL)
+			return -EINVAL;
+
+		ret = genlock_get_fd(handle->lock);
+		if (ret < 0)
+			return ret;
+
+		param.fd = ret;
+
+		if (copy_to_user((void __user *) arg, &param,
+			sizeof(param)))
+			return -EFAULT;
+
+		return 0;
+		}
+	case GENLOCK_IOC_ATTACH: {
+		if (copy_from_user(&param, (void __user *) arg,
+			sizeof(param)))
+			return -EFAULT;
+
+		lock = genlock_attach_lock(handle, param.fd);
+		if (IS_ERR(lock))
+			return PTR_ERR(lock);
+
+		return 0;
+	}
+	case GENLOCK_IOC_LOCK: {
+		if (copy_from_user(&param, (void __user *) arg,
+		sizeof(param)))
+			return -EFAULT;
+
+		return genlock_lock(handle, param.op, param.flags,
+			param.timeout);
+	}
+	case GENLOCK_IOC_WAIT: {
+		if (copy_from_user(&param, (void __user *) arg,
+		sizeof(param)))
+			return -EFAULT;
+
+		return genlock_wait(handle, param.timeout);
+	}
+	case GENLOCK_IOC_RELEASE: {
+		genlock_release_lock(handle);
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int genlock_dev_release(struct inode *inodep, struct file *file)
+{
+	struct genlock_handle *handle = file->private_data;
+
+	genlock_put_handle(handle);
+
+	return 0;
+}
+
+static int genlock_dev_open(struct inode *inodep, struct file *file)
+{
+	struct genlock_handle *handle = _genlock_get_handle();
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+
+	handle->file = file;
+	file->private_data = handle;
+	return 0;
+}
+
+static const struct file_operations genlock_dev_fops = {
+	.open = genlock_dev_open,
+	.release = genlock_dev_release,
+	.unlocked_ioctl = genlock_dev_ioctl,
+};
+
+static struct miscdevice genlock_dev;
+
+static int genlock_dev_init(void)
+{
+	genlock_dev.minor = MISC_DYNAMIC_MINOR;
+	genlock_dev.name = "genlock";
+	genlock_dev.fops = &genlock_dev_fops;
+	genlock_dev.parent = NULL;
+
+	return misc_register(&genlock_dev);
+}
+
+static void genlock_dev_close(void)
+{
+	misc_deregister(&genlock_dev);
+}
+
+module_init(genlock_dev_init);
+module_exit(genlock_dev_close);
+
+#endif
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index e2f7271..bddc80f 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -125,14 +125,6 @@
 #define LOAD_INT(x) ((x) >> FSHIFT)
 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 
-static int get_loadavg(void)
-{
-	unsigned long this = this_cpu_load();
-
-
-	return LOAD_INT(this) * 10 + LOAD_FRAC(this) / 10;
-}
-
 static inline int which_bucket(unsigned int duration)
 {
 	int bucket = 0;
@@ -170,15 +162,6 @@
 {
 	int mult = 1;
 
-	/* for higher loadavg, we are more reluctant */
-
-	/*
-	 * this doesn't work as intended - it is almost always 0, but can
-	 * sometimes, depending on workload, spike very high into the hundreds
-	 * even when the average cpu load is under 10%.
-	 */
-	/* mult += 2 * get_loadavg(); */
-
 	/* for IO wait tasks (per cpu!) we add 5x each */
 	mult += 10 * nr_iowait_cpu(smp_processor_id());
 
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 893933b..d725851 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -58,8 +58,9 @@
 	void __iomem *iobase;	    /* Virtual io base of CE HW  */
 	unsigned int phy_iobase;    /* Physical io base of CE HW    */
 
-	struct clk *ce_core_clk;	    /* Handle to CE clk */
-	struct clk *ce_clk;	    /* Handle to CE clk */
+	struct clk *ce_core_src_clk;	/* Handle to CE src clk*/
+	struct clk *ce_core_clk;	/* Handle to CE clk */
+	struct clk *ce_clk;		/* Handle to CE clk */
 
 	qce_comp_func_ptr_t qce_cb;	/* qce callback function pointer */
 
@@ -207,6 +208,7 @@
 
 static int _init_ce_engine(struct qce_device *pce_dev)
 {
+	int status;
 	/* Reset ce */
 	clk_reset(pce_dev->ce_core_clk, CLK_RESET_ASSERT);
 	clk_reset(pce_dev->ce_core_clk, CLK_RESET_DEASSERT);
@@ -223,6 +225,11 @@
 	config_ce_engine(pce_dev);
 
 	/*
+	 * Clear ACCESS_VIOL bit in CRYPTO_STATUS REGISTER
+	*/
+	status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+	*((uint32_t *)(pce_dev->ce_dm.buffer.status)) = status & (~0x40000);
+	/*
 	* Ensure ce configuration is completed.
 	*/
 	mb();
@@ -473,12 +480,20 @@
 		}
 	}
 
-	if (creq->mode == QCE_MODE_CCM)
+	switch (creq->mode) {
+	case QCE_MODE_CCM:
 		pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
-						cmdptrlist->aead_ce_out;
-	else
+					cmdptrlist->aead_ce_out;
+		break;
+	case QCE_MODE_ECB:
 		pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
-						cmdptrlist->cipher_ce_out;
+					cmdptrlist->cipher_ce_out;
+		break;
+	default:
+		pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
+					cmdptrlist->cipher_ce_out_get_iv;
+		break;
+	}
 
 	return 0;
 }
@@ -1329,21 +1344,6 @@
 	pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
 	pscmd++;
 
-	pce_dev->ce_dm.cmdlist.get_cipher_aes_iv = pscmd;
-	pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
-				CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
-	pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
-	pscmd->len = CRYPTO_REG_SIZE * 4;
-	pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
-	pscmd++;
-
-	pce_dev->ce_dm.cmdlist.get_cipher_aes_xts_iv = pscmd;
-	pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
-	pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
-	pscmd->len = CRYPTO_REG_SIZE * 4;
-	pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
-	pscmd++;
-
 	pce_dev->ce_dm.cmdlist.set_cipher_des_iv = pscmd;
 	pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
 				CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
@@ -1352,11 +1352,11 @@
 	pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
 	pscmd++;
 
-	pce_dev->ce_dm.cmdlist.get_cipher_des_iv = pscmd;
+	pce_dev->ce_dm.cmdlist.get_cipher_iv = pscmd;
 	pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
 				CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
 	pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
-	pscmd->len = CRYPTO_REG_SIZE * 2;
+	pscmd->len = CRYPTO_REG_SIZE * 4;
 	pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
 	pscmd++;
 
@@ -1612,6 +1612,14 @@
 	pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
 	pscmd++;
 
+	/* CLEAR STATUS COMMAND LIST */
+	pce_dev->ce_dm.cmdlist.clear_status = pscmd;
+	pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCU;
+	pscmd->dst = (unsigned) (CRYPTO_STATUS_REG + pce_dev->phy_iobase);
+	pscmd->len = CRYPTO_REG_SIZE;
+	pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
+	pscmd++;
+
 	/* SET GO_PROC REGISTERS COMMAND LIST */
 	pce_dev->ce_dm.cmdlist.set_go_proc = pscmd;
 	pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
@@ -1692,8 +1700,7 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
-	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
-	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv);
+	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
 
 	cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
 	cmdptrlist->cipher_aes_256_cbc_ctr = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1705,8 +1712,7 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
-	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
-	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv);
+	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
 
 	cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
 	cmdptrlist->cipher_aes_128_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1742,8 +1748,7 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
-	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
-	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv);
+	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
 
 	cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
 	cmdptrlist->cipher_aes_256_xts = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1757,8 +1762,7 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
-	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
-	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv);
+	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
 
 	cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
 	cmdptrlist->cipher_des_cbc = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1769,8 +1773,7 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
-	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
-	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv);
+	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
 
 	cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
 	cmdptrlist->cipher_des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1791,8 +1794,7 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
-	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
-	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv);
+	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
 
 	cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
 	cmdptrlist->cipher_3des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1809,6 +1811,14 @@
 
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out);
 	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
+
+	cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
+	cmdptrlist->cipher_ce_out_get_iv = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
+
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_cipher_iv);
+	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
+
 	*pvaddr = (unsigned char *) cmd_ptr_vaddr;
 
 	return 0;
@@ -2007,6 +2017,7 @@
 	cmdptrlist->probe_ce_hw = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
 
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_hw_version);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status);
 	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
 
 	*pvaddr = (unsigned char *) cmd_ptr_vaddr;
@@ -2391,6 +2402,8 @@
 	struct resource *resource;
 	struct clk *ce_core_clk;
 	struct clk *ce_clk;
+	struct clk *ce_core_src_clk;
+	int ret = 0;
 
 	pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
 	if (!pce_dev) {
@@ -2461,10 +2474,26 @@
 		goto err;
 	}
 
+	/* Get CE3 src core clk. */
+	ce_core_src_clk = clk_get(pce_dev->pdev, "ce3_core_src_clk");
+	if (!IS_ERR(ce_core_src_clk)) {
+		pce_dev->ce_core_src_clk = ce_core_src_clk;
+
+		/* Set the core src clk @100Mhz */
+		ret = clk_set_rate(pce_dev->ce_core_src_clk, 100000000);
+		if (ret) {
+			clk_put(pce_dev->ce_core_src_clk);
+			goto err;
+		}
+	} else
+		pce_dev->ce_core_src_clk = NULL;
+
 	/* Get CE core clk */
 	ce_core_clk = clk_get(pce_dev->pdev, "core_clk");
 	if (IS_ERR(ce_core_clk)) {
 		*rc = PTR_ERR(ce_core_clk);
+		if (pce_dev->ce_core_src_clk != NULL)
+			clk_put(pce_dev->ce_core_src_clk);
 		goto err;
 	}
 	pce_dev->ce_core_clk = ce_core_clk;
@@ -2472,6 +2501,8 @@
 	ce_clk = clk_get(pce_dev->pdev, "iface_clk");
 	if (IS_ERR(ce_clk)) {
 		*rc = PTR_ERR(ce_clk);
+		if (pce_dev->ce_core_src_clk != NULL)
+			clk_put(pce_dev->ce_core_src_clk);
 		clk_put(pce_dev->ce_core_clk);
 		goto err;
 	}
@@ -2480,6 +2511,8 @@
 	/* Enable CE core clk */
 	*rc = clk_enable(pce_dev->ce_core_clk);
 	if (*rc) {
+		if (pce_dev->ce_core_src_clk != NULL)
+			clk_put(pce_dev->ce_core_src_clk);
 		clk_put(pce_dev->ce_core_clk);
 		clk_put(pce_dev->ce_clk);
 		goto err;
@@ -2488,6 +2521,8 @@
 		*rc = clk_enable(pce_dev->ce_clk);
 		if (*rc) {
 			clk_disable(pce_dev->ce_core_clk);
+			if (pce_dev->ce_core_src_clk != NULL)
+				clk_put(pce_dev->ce_core_src_clk);
 			clk_put(pce_dev->ce_core_clk);
 			clk_put(pce_dev->ce_clk);
 			goto err;
@@ -2539,6 +2574,9 @@
 	clk_disable(pce_dev->ce_clk);
 	clk_disable(pce_dev->ce_core_clk);
 
+	if (pce_dev->ce_core_src_clk != NULL)
+		clk_put(pce_dev->ce_core_src_clk);
+
 	clk_put(pce_dev->ce_clk);
 	clk_put(pce_dev->ce_core_clk);
 
@@ -2571,4 +2609,4 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.13");
+MODULE_VERSION("2.14");
diff --git a/drivers/crypto/msm/qce40.h b/drivers/crypto/msm/qce40.h
index c9fbb17..809ba7f 100644
--- a/drivers/crypto/msm/qce40.h
+++ b/drivers/crypto/msm/qce40.h
@@ -117,6 +117,7 @@
 /* CE Command lists */
 struct ce_cmdlists {
 	dmov_s *get_hw_version;
+	dmov_s *clear_status;
 	dmov_s *get_status_ocu;
 
 	dmov_s *set_cipher_cfg;
@@ -132,10 +133,8 @@
 
 	dmov_s *set_cipher_aes_iv;
 	dmov_s *set_cipher_aes_xts_iv;
-	dmov_s *get_cipher_aes_iv;
-	dmov_s *get_cipher_aes_xts_iv;
 	dmov_s *set_cipher_des_iv;
-	dmov_s *get_cipher_des_iv;
+	dmov_s *get_cipher_iv;
 
 	dmov_s *set_cipher_mask;
 
@@ -195,6 +194,7 @@
 	uint32_t aead_aes_256_ccm;
 
 	uint32_t cipher_ce_out;
+	uint32_t cipher_ce_out_get_iv;
 	uint32_t aead_ce_out;
 };
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 4138e06..06c4d90 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -837,6 +837,12 @@
 	return status;
 }
 
+static inline void adreno_poke(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	adreno_regwrite(device, REG_CP_RB_WPTR, adreno_dev->ringbuffer.wptr);
+}
+
 /* Caller must hold the device mutex. */
 int adreno_idle(struct kgsl_device *device, unsigned int timeout)
 {
@@ -855,6 +861,7 @@
 retry:
 	if (rb->flags & KGSL_FLAGS_STARTED) {
 		do {
+			adreno_poke(device);
 			GSL_RB_GET_READPTR(rb, &rb->rptr);
 			if (time_after(jiffies, wait_time)) {
 				KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
@@ -1083,6 +1090,9 @@
 	static uint io_cnt;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	int retries;
+	unsigned int msecs_first;
+	unsigned int msecs_part;
 
 	/* Don't wait forever, set a max value for now */
 	if (msecs == -1)
@@ -1097,43 +1107,59 @@
 		status = -EINVAL;
 		goto done;
 	}
-	if (!kgsl_check_timestamp(device, timestamp)) {
-		io_cnt = (io_cnt + 1) % 100;
-		if (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
-			io = 0;
-		mutex_unlock(&device->mutex);
-		/* We need to make sure that the process is placed in wait-q
-		 * before its condition is called */
-		status = kgsl_wait_event_interruptible_timeout(
-				device->wait_queue,
-				kgsl_check_interrupt_timestamp(device,
-					timestamp),
-				msecs_to_jiffies(msecs), io);
-		mutex_lock(&device->mutex);
 
-		if (status > 0)
-			status = 0;
-		else if (status == 0) {
-			if (!kgsl_check_timestamp(device, timestamp)) {
-				status = -ETIMEDOUT;
-				KGSL_DRV_ERR(device,
-					"Device hang detected while waiting "
-					"for timestamp: %x, last "
-					"submitted(rb->timestamp): %x, wptr: "
-					"%x\n", timestamp,
-					adreno_dev->ringbuffer.timestamp,
-					adreno_dev->ringbuffer.wptr);
-				if (!adreno_dump_and_recover(device)) {
-					/* wait for idle after recovery as the
-					 * timestamp that this process wanted
-					 * to wait on may be invalid */
-					if (!adreno_idle(device,
-						KGSL_TIMEOUT_DEFAULT))
-						status = 0;
-				}
+	/* Keep the first timeout as 100msecs before rewriting
+	 * the WPTR. Less visible impact if the WPTR has not
+	 * been updated properly.
+	 */
+	msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
+	msecs_part = (msecs - msecs_first + 3) / 4;
+	for (retries = 0; retries < 5; retries++) {
+		if (!kgsl_check_timestamp(device, timestamp)) {
+			adreno_poke(device);
+			io_cnt = (io_cnt + 1) % 100;
+			if (io_cnt <
+				pwr->pwrlevels[pwr->active_pwrlevel].
+					io_fraction)
+				io = 0;
+			mutex_unlock(&device->mutex);
+			/* We need to make sure that the process is
+			 * placed in wait-q before its condition is called
+			 */
+			status = kgsl_wait_event_interruptible_timeout(
+					device->wait_queue,
+					kgsl_check_interrupt_timestamp(device,
+						timestamp),
+					msecs_to_jiffies(retries ?
+						msecs_part : msecs_first), io);
+			mutex_lock(&device->mutex);
+
+			if (status > 0) {
+				status = 0;
+				goto done;
 			}
 		}
 	}
+	if (!kgsl_check_timestamp(device, timestamp)) {
+		status = -ETIMEDOUT;
+		KGSL_DRV_ERR(device,
+			"Device hang detected while waiting "
+			"for timestamp: %x, last "
+			"submitted(rb->timestamp): %x, wptr: "
+			"%x\n", timestamp,
+			adreno_dev->ringbuffer.timestamp,
+			adreno_dev->ringbuffer.wptr);
+		if (!adreno_dump_and_recover(device)) {
+			/* wait for idle after recovery as the
+			 * timestamp that this process wanted
+			 * to wait on may be invalid */
+			if (!adreno_idle(device,
+				KGSL_TIMEOUT_DEFAULT))
+				status = 0;
+		}
+	} else {
+		status = 0;
+	}
 
 done:
 	return (int)status;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e84d473..a0a4056 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -24,6 +24,7 @@
 #include <linux/ashmem.h>
 #include <linux/major.h>
 #include <linux/ion.h>
+#include <mach/socinfo.h>
 
 #include "kgsl.h"
 #include "kgsl_debugfs.h"
@@ -1939,8 +1940,8 @@
 	kgsl_cffdump_close(device->id);
 	kgsl_pwrctrl_uninit_sysfs(device);
 
-	wake_lock_destroy(&device->idle_wakelock);
-	pm_qos_remove_request(&device->pm_qos_req_dma);
+	if (cpu_is_msm8x60())
+		wake_lock_destroy(&device->idle_wakelock);
 
 	idr_destroy(&device->context_idr);
 
@@ -2031,9 +2032,9 @@
 	if (ret != 0)
 		goto err_close_mmu;
 
-	wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
-	pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
-				PM_QOS_DEFAULT_VALUE);
+	if (cpu_is_msm8x60())
+		wake_lock_init(&device->idle_wakelock,
+					   WAKE_LOCK_IDLE, device->name);
 
 	idr_init(&device->context_idr);
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6ae9258..fd203ef 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -15,7 +15,6 @@
 
 #include <linux/idr.h>
 #include <linux/wakelock.h>
-#include <linux/pm_qos_params.h>
 #include <linux/earlysuspend.h>
 
 #include "kgsl.h"
@@ -165,7 +164,6 @@
 	struct wake_lock idle_wakelock;
 	struct kgsl_pwrscale pwrscale;
 	struct kobject pwrscale_kobj;
-	struct pm_qos_request_list pm_qos_req_dma;
 	struct work_struct ts_expired_ws;
 };
 
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8ec9572..7034fd8 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -13,6 +13,7 @@
 #include <linux/interrupt.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_bus.h>
+#include <mach/socinfo.h>
 
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
@@ -23,7 +24,6 @@
 #define KGSL_PWRFLAGS_AXI_ON   2
 #define KGSL_PWRFLAGS_IRQ_ON   3
 
-#define GPU_SWFI_LATENCY	3
 #define UPDATE_BUSY_VAL		1000000
 #define UPDATE_BUSY		50
 
@@ -697,6 +697,8 @@
 				goto slumber;
 			}
 	} else if (device->requested_state == KGSL_STATE_SLUMBER) {
+		if (device->state == KGSL_STATE_INIT)
+			return 0;
 		if (device->ftbl->isidle(device))
 			goto slumber;
 	}
@@ -729,9 +731,8 @@
 
 	device->state = device->requested_state;
 	device->requested_state = KGSL_STATE_NONE;
-	wake_unlock(&device->idle_wakelock);
-	pm_qos_update_request(&device->pm_qos_req_dma,
-				PM_QOS_DEFAULT_VALUE);
+	if (device->idle_wakelock.name)
+		wake_unlock(&device->idle_wakelock);
 	KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n",
 				  device->state, device->id);
 
@@ -761,7 +762,7 @@
 /* Caller must hold the device mutex. */
 void kgsl_pwrctrl_wake(struct kgsl_device *device)
 {
-	if (device->state == KGSL_STATE_SUSPEND)
+	if (device->state & (KGSL_STATE_SUSPEND | KGSL_STATE_INIT))
 		return;
 
 	if (device->state == KGSL_STATE_SLUMBER)
@@ -784,8 +785,9 @@
 	mod_timer(&device->idle_timer,
 				jiffies + device->pwrctrl.interval_timeout);
 
-	wake_lock(&device->idle_wakelock);
-	pm_qos_update_request(&device->pm_qos_req_dma, GPU_SWFI_LATENCY);
+	if (device->idle_wakelock.name)
+		wake_lock(&device->idle_wakelock);
+
 	KGSL_PWR_INFO(device, "wake return for device %d\n", device->id);
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_wake);
diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c
index d2bd4df..35507e1 100644
--- a/drivers/input/touchscreen/atmel_maxtouch.c
+++ b/drivers/input/touchscreen/atmel_maxtouch.c
@@ -939,6 +939,7 @@
 				input_mt_sync(mxt->input);
 			}
 		}
+		input_report_key(mxt->input, BTN_TOUCH, !!active_touches);
 		if (active_touches == 0)
 			input_mt_sync(mxt->input);
 		input_sync(mxt->input);
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index f267f80..e01d2c7 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -12,7 +12,6 @@
  */
 
 #include "msm_actuator.h"
-#include "msm_logging.h"
 #include "msm_camera_i2c.h"
 
 #define	IMX074_TOTAL_STEPS_NEAR_TO_FAR			41
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index 7f570e6..f0023d7 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -11,10 +11,6 @@
  */
 
 #include "msm_actuator.h"
-#include "msm_logging.h"
-
-LDECVAR(a_profstarttime);
-LDECVAR(a_profendtime);
 
 int32_t msm_actuator_write_focus(
 	struct msm_actuator_ctrl_t *a_ctrl,
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index d612dad..6fad8dd 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -18,6 +18,24 @@
 #include <media/msm_camera.h>
 #include "msm_camera_i2c.h"
 
+#ifdef LERROR
+#undef LERROR
+#endif
+
+#ifdef LINFO
+#undef LINFO
+#endif
+
+#define LERROR(fmt, args...) pr_err(fmt, ##args)
+
+#define CONFIG_MSM_CAMERA_ACT_DBG 0
+
+#if CONFIG_MSM_CAMERA_ACT_DBG
+#define LINFO(fmt, args...) printk(fmt, ##args)
+#else
+#define LINFO(fmt, args...) CDBG(fmt, ##args)
+#endif
+
 struct msm_actuator_ctrl_t;
 
 struct region_params_t {
diff --git a/drivers/media/video/msm/msm_logging.h b/drivers/media/video/msm/msm_logging.h
deleted file mode 100644
index 5e1547c..0000000
--- a/drivers/media/video/msm/msm_logging.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MSM_LOGGING_H
-#define __MSM_LOGGING_H
-
-#include <linux/time.h>
-
-#ifdef MSM_LOG_LEVEL_ERROR
-#undef MSM_LOG_LEVEL_ERROR
-#endif
-
-#ifdef MSM_LOG_LEVEL_PROFILE
-#undef MSM_LOG_LEVEL_PROFILE
-#endif
-
-#ifdef MSM_LOG_LEVEL_ALL
-#undef MSM_LOG_LEVEL_ALL
-#endif
-
-/* MSM_LOG_LEVEL_ERROR - prints only error logs
- * MSM_LOG_LEVEL_PROFILE - prints all profile and error logs
- * MSM_LOG_LEVEL_ALL - prints all logs */
-
-#define MSM_LOG_LEVEL_ERROR
-/* #define MSM_LOG_LEVEL_PROFILE */
-/* #define MSM_LOG_LEVEL_ALL */
-
-#ifdef LINFO
-#undef LINFO
-#endif
-
-#ifdef LERROR
-#undef LERROR
-#endif
-
-#ifdef LPROFSTART
-#undef LPROFSTART
-#endif
-
-#ifdef LPROFEND
-#undef LPROFEND
-#endif
-
-#if defined(MSM_LOG_LEVEL_ERROR)
-#define LDECVAR(VAR)
-#define LINFO(fmt, args...) pr_debug(fmt, ##args)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) do {} while (0)
-#define LPROFEND(START, END) do {} while (0)
-#elif defined(MSM_LOG_LEVEL_PROFILE)
-#define LDECVAR(VAR) \
-	static struct timespec VAR
-#define LINFO(fmt, args...) do {} while (0)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) \
-	START = current_kernel_time()
-#define LPROFEND(START, END) \
-	do { \
-		END = current_kernel_time(); \
-		pr_info("profile start time in ns: %lu\n", \
-			(START.tv_sec * NSEC_PER_SEC) + \
-			START.tv_nsec); \
-		pr_info("profile end time in ns: %lu\n", \
-			(END.tv_sec * NSEC_PER_SEC) + \
-			END.tv_nsec); \
-		pr_info("profile diff time in ns: %lu\n", \
-			((END.tv_sec - START.tv_sec) * NSEC_PER_SEC) + \
-			(END.tv_nsec - START.tv_nsec)); \
-		START = END; \
-	} while (0)
-
-#elif defined(MSM_LOG_LEVEL_ALL)
-#define LDECVAR(VAR) \
-	static struct timespec VAR
-#define LINFO(fmt, args...) pr_debug(fmt, ##args)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) \
-	START = current_kernel_time()
-#define LPROFEND(START, END) \
-	do { \
-		END = current_kernel_time(); \
-		pr_info("profile start time in ns: %lu\n", \
-			(START.tv_sec * NSEC_PER_SEC) + \
-			START.tv_nsec); \
-		pr_info("profile end time in ns: %lu\n", \
-			(END.tv_sec * NSEC_PER_SEC) + \
-			END.tv_nsec); \
-		pr_info("profile diff time in ns: %lu\n", \
-			((END.tv_sec - START.tv_sec) * NSEC_PER_SEC) + \
-			(END.tv_nsec - START.tv_nsec)); \
-		START = END; \
-	} while (0)
-#else
-#define LDECVAR(VAR)
-#define LINFO(fmt, args...) do {} while (0)
-#define LERROR(fmt, args...) do {} while (0)
-#define LPROFSTART(START) do {} while (0)
-#define LPROFEND(START, END) do {} while (0)
-#endif
-#endif
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index 528f232..8d89568 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -29,6 +29,7 @@
 #define REG_HWREV_2		0x0E8  /* PMIC4 revision 2 */
 
 #define REG_MPP_BASE		0x050
+#define REG_IRQ_BASE		0x1BB
 
 #define REG_RTC_BASE		0x11D
 
@@ -237,6 +238,7 @@
 
 	if (pdata->irq_pdata) {
 		pdata->irq_pdata->irq_cdata.nirqs = PM8018_NR_IRQS;
+		pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
 		irq_base = pdata->irq_pdata->irq_base;
 		irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
 
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index ed29785..8a556bd 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -26,6 +26,7 @@
 #define REG_HWREV_2		0x0E8  /* PMIC4 revision 2 */
 
 #define REG_MPP_BASE		0x050
+#define REG_IRQ_BASE		0x1BB
 
 #define PM8821_VERSION_MASK	0xFFF0
 #define PM8821_VERSION_VALUE	0x07F0
@@ -150,6 +151,7 @@
 
 	if (pdata->irq_pdata) {
 		pdata->irq_pdata->irq_cdata.nirqs = PM8821_NR_IRQS;
+		pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
 		irq_base = pdata->irq_pdata->irq_base;
 		irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
 
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 742d8dd..d225dfa 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -27,6 +27,7 @@
 #define REG_HWREV_2		0x0E8  /* PMIC4 revision 2 */
 
 #define REG_MPP_BASE		0x050
+#define REG_IRQ_BASE		0x1BB
 
 #define REG_TEMP_ALARM_CTRL	0x1B
 #define REG_TEMP_ALARM_PWM	0x9B
@@ -270,7 +271,6 @@
 	SINGLE_IRQ_RESOURCE("PM8921_BMS_OCV_FOR_R", PM8921_BMS_OCV_FOR_R),
 	SINGLE_IRQ_RESOURCE("PM8921_BMS_GOOD_OCV", PM8921_BMS_GOOD_OCV),
 	SINGLE_IRQ_RESOURCE("PM8921_BMS_VSENSE_AVG", PM8921_BMS_VSENSE_AVG),
-	SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
 };
 
 static struct mfd_cell charger_cell __devinitdata = {
@@ -342,6 +342,17 @@
 	.pdata_size	= sizeof(struct pm8xxx_batt_alarm_core_data),
 };
 
+static const struct resource ccadc_cell_resources[] __devinitconst = {
+	SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
+};
+
+static struct mfd_cell ccadc_cell __devinitdata = {
+	.name		= PM8XXX_CCADC_DEV_NAME,
+	.id		= -1,
+	.resources	= ccadc_cell_resources,
+	.num_resources	= ARRAY_SIZE(ccadc_cell_resources),
+};
+
 static struct mfd_cell vibrator_cell __devinitdata = {
 	.name           = PM8XXX_VIBRATOR_DEV_NAME,
 	.id             = -1,
@@ -358,6 +369,7 @@
 
 	if (pdata->irq_pdata) {
 		pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
+		pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
 		irq_base = pdata->irq_pdata->irq_base;
 		irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
 
@@ -566,6 +578,19 @@
 		}
 	}
 
+	if (pdata->ccadc_pdata) {
+		ccadc_cell.platform_data = pdata->ccadc_pdata;
+		ccadc_cell.pdata_size =
+				sizeof(struct pm8xxx_ccadc_platform_data);
+
+		ret = mfd_add_devices(pmic->dev, 0, &ccadc_cell, 1, NULL,
+					irq_base);
+		if (ret) {
+			pr_err("Failed to add ccadc subdevice ret=%d\n", ret);
+			goto bail;
+		}
+	}
+
 	return 0;
 bail:
 	if (pmic->irq_chip) {
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index c6221b8..5864b85 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -24,17 +24,15 @@
 
 /* PMIC8xxx IRQ */
 
-#define	SSBI_REG_ADDR_IRQ_BASE		0x1BB
-
-#define	SSBI_REG_ADDR_IRQ_ROOT		(SSBI_REG_ADDR_IRQ_BASE + 0)
-#define	SSBI_REG_ADDR_IRQ_M_STATUS1	(SSBI_REG_ADDR_IRQ_BASE + 1)
-#define	SSBI_REG_ADDR_IRQ_M_STATUS2	(SSBI_REG_ADDR_IRQ_BASE + 2)
-#define	SSBI_REG_ADDR_IRQ_M_STATUS3	(SSBI_REG_ADDR_IRQ_BASE + 3)
-#define	SSBI_REG_ADDR_IRQ_M_STATUS4	(SSBI_REG_ADDR_IRQ_BASE + 4)
-#define	SSBI_REG_ADDR_IRQ_BLK_SEL	(SSBI_REG_ADDR_IRQ_BASE + 5)
-#define	SSBI_REG_ADDR_IRQ_IT_STATUS	(SSBI_REG_ADDR_IRQ_BASE + 6)
-#define	SSBI_REG_ADDR_IRQ_CONFIG	(SSBI_REG_ADDR_IRQ_BASE + 7)
-#define	SSBI_REG_ADDR_IRQ_RT_STATUS	(SSBI_REG_ADDR_IRQ_BASE + 8)
+#define SSBI_REG_ADDR_IRQ_ROOT(base)		(base + 0)
+#define SSBI_REG_ADDR_IRQ_M_STATUS1(base)	(base + 1)
+#define SSBI_REG_ADDR_IRQ_M_STATUS2(base)	(base + 2)
+#define SSBI_REG_ADDR_IRQ_M_STATUS3(base)	(base + 3)
+#define SSBI_REG_ADDR_IRQ_M_STATUS4(base)	(base + 4)
+#define SSBI_REG_ADDR_IRQ_BLK_SEL(base)		(base + 5)
+#define SSBI_REG_ADDR_IRQ_IT_STATUS(base)	(base + 6)
+#define SSBI_REG_ADDR_IRQ_CONFIG(base)		(base + 7)
+#define SSBI_REG_ADDR_IRQ_RT_STATUS(base)	(base + 8)
 
 #define	PM_IRQF_LVL_SEL			0x01	/* level select */
 #define	PM_IRQF_MASK_FE			0x02	/* mask falling edge */
@@ -50,6 +48,7 @@
 struct pm_irq_chip {
 	struct device		*dev;
 	spinlock_t		pm_irq_lock;
+	unsigned int		base_addr;
 	unsigned int		devirq;
 	unsigned int		irq_base;
 	unsigned int		num_irqs;
@@ -60,13 +59,14 @@
 
 static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
 {
-	return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
+	return pm8xxx_readb(chip->dev,
+			SSBI_REG_ADDR_IRQ_ROOT(chip->base_addr), rp);
 }
 
 static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
 {
 	return pm8xxx_readb(chip->dev,
-			SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
+			SSBI_REG_ADDR_IRQ_M_STATUS1(chip->base_addr) + m, bp);
 }
 
 static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
@@ -74,13 +74,15 @@
 	int	rc;
 
 	spin_lock(&chip->pm_irq_lock);
-	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+	rc = pm8xxx_writeb(chip->dev,
+			SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
 	if (rc) {
 		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
 		goto bail;
 	}
 
-	rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+	rc = pm8xxx_readb(chip->dev,
+			SSBI_REG_ADDR_IRQ_IT_STATUS(chip->base_addr), ip);
 	if (rc)
 		pr_err("Failed Reading Status rc=%d\n", rc);
 bail:
@@ -93,17 +95,20 @@
 	int	rc;
 
 	spin_lock(&chip->pm_irq_lock);
-	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+	rc = pm8xxx_writeb(chip->dev,
+			SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
 	if (rc) {
 		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
 		goto bail;
 	}
 
-	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+	rc = pm8xxx_writeb(chip->dev,
+			SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
 	if (rc)
 		pr_err("Failed Configuring IRQ rc=%d\n", rc);
 
-	rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, r);
+	rc = pm8xxx_readb(chip->dev,
+			SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), r);
 	if (rc)
 		pr_err("Failed reading IRQ rc=%d\n", rc);
 bail:
@@ -116,14 +121,16 @@
 	int	rc;
 
 	spin_lock(&chip->pm_irq_lock);
-	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+	rc = pm8xxx_writeb(chip->dev,
+			SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
 	if (rc) {
 		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
 		goto bail;
 	}
 
 	cp |= PM_IRQF_WRITE;
-	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+	rc = pm8xxx_writeb(chip->dev,
+			SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
 	if (rc)
 		pr_err("Failed Configuring IRQ rc=%d\n", rc);
 bail:
@@ -335,14 +342,16 @@
 
 	spin_lock_irqsave(&chip->pm_irq_lock, flags);
 
-	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
+	rc = pm8xxx_writeb(chip->dev,
+			SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), block);
 	if (rc) {
 		pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
 			irq, pmirq, block, rc);
 		goto bail_out;
 	}
 
-	rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
+	rc = pm8xxx_readb(chip->dev,
+			SSBI_REG_ADDR_IRQ_RT_STATUS(chip->base_addr), &bits);
 	if (rc) {
 		pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
 			irq, pmirq, block, rc);
@@ -388,6 +397,7 @@
 	chip->devirq = devirq;
 	chip->irq_base = pdata->irq_base;
 	chip->num_irqs = pdata->irq_cdata.nirqs;
+	chip->base_addr = pdata->irq_cdata.base_addr;
 	chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
 	chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
 	spin_lock_init(&chip->pm_irq_lock);
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index 77e393e..ae721e4 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -25,6 +25,7 @@
 #include <linux/msm_adc.h>
 
 #define REG_MPP_BASE			0x50
+#define REG_IRQ_BASE			0x1BB
 
 /* PMIC8058 Revision */
 #define PM8058_REG_REV			0x002  /* PMIC4 revision */
@@ -901,6 +902,7 @@
 
 	if (pdata->irq_pdata) {
 		pdata->irq_pdata->irq_cdata.nirqs = PM8058_NR_IRQS;
+		pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
 		irq_base = pdata->irq_pdata->irq_base;
 		irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
 
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
index 8eca7aa..aabc2cc 100644
--- a/drivers/mfd/wcd9310-core.c
+++ b/drivers/mfd/wcd9310-core.c
@@ -22,10 +22,25 @@
 #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 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)
 {
@@ -566,6 +581,214 @@
 	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->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->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 fail;
+	}
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+		dev_dbg(&client->dev, "can't talk I2C?\n");
+		ret = -EIO;
+		goto fail;
+	}
+	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)
+{
+	pr_debug("exit\n");
+	return 0;
+}
+
 static int tabla_slim_probe(struct slim_device *slim)
 {
 	struct tabla *tabla;
@@ -600,7 +823,7 @@
 
 	ret = tabla_enable_supplies(tabla);
 	if (ret) {
-		pr_info("%s: Fail to enable Tabla supplies\n", __func__);
+		pr_err("%s: Fail to enable Tabla supplies\n", __func__);
 		goto err_tabla;
 	}
 	usleep_range(5, 5);
@@ -661,6 +884,7 @@
 		break;
 	}
 	tabla_inf_la = tabla->slim_slave->laddr;
+	tabla_intf = TABLA_INTERFACE_TYPE_SLIMBUS;
 
 	ret = tabla_device_init(tabla, tabla->irq);
 	if (ret) {
@@ -744,9 +968,33 @@
 	.id_table = slimtest2x_id,
 };
 
+#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),
+};
+
 static int __init tabla_init(void)
 {
-	int ret1, ret2;
+	int ret1, ret2, ret3;
 
 	ret1 = slim_driver_register(&tabla_slim_driver);
 	if (ret1 != 0)
@@ -756,7 +1004,11 @@
 	if (ret2 != 0)
 		pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
 
-	return (ret1 && ret2) ? -1 : 0;
+	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);
 
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
index bc7841e..9cc4761 100644
--- a/drivers/mfd/wcd9310-irq.c
+++ b/drivers/mfd/wcd9310-irq.c
@@ -110,11 +110,19 @@
 				(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;
 		}
diff --git a/drivers/net/msm_rmnet_bam.c b/drivers/net/msm_rmnet_bam.c
index 3b3758e..bb20a3f 100644
--- a/drivers/net/msm_rmnet_bam.c
+++ b/drivers/net/msm_rmnet_bam.c
@@ -308,6 +308,7 @@
 	}
 
 	dev->trans_start = jiffies;
+	/* if write() succeeds, skb access is unsafe in this process */
 	bam_ret = msm_bam_dmux_write(p->ch_id, skb);
 
 	if (bam_ret != 0) {
@@ -316,16 +317,6 @@
 		goto xmit_out;
 	}
 
-	if (count_this_packet(skb->data, skb->len)) {
-		p->stats.tx_packets++;
-		p->stats.tx_bytes += skb->len;
-#ifdef CONFIG_MSM_RMNET_DEBUG
-		p->wakeups_xmit += rmnet_cause_wakeup(p);
-#endif
-	}
-	DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
-	    dev->name, p->stats.tx_packets, skb->len, skb->mark);
-
 	return 0;
 xmit_out:
 	/* data xmited, safe to release skb */
@@ -335,7 +326,21 @@
 
 static void bam_write_done(void *dev, struct sk_buff *skb)
 {
+	struct rmnet_private *p = netdev_priv(dev);
+	u32 opmode = p->operation_mode;
+
 	DBG1("%s: write complete\n", __func__);
+	if (RMNET_IS_MODE_IP(opmode) ||
+				count_this_packet(skb->data, skb->len)) {
+		p->stats.tx_packets++;
+		p->stats.tx_bytes += skb->len;
+#ifdef CONFIG_MSM_RMNET_DEBUG
+		p->wakeups_xmit += rmnet_cause_wakeup(p);
+#endif
+	}
+	DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+	    ((struct net_device *)(dev))->name, p->stats.tx_packets,
+	    skb->len, skb->mark);
 	dev_kfree_skb_any(skb);
 	netif_wake_queue(dev);
 }
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3590e6d..7c8dfea 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -332,7 +332,14 @@
 	help
 	  Say Y here to enable support for pm8921 chip charger subdevice
 
+config PM8XXX_CCADC
+	tristate "PM8XXX battery current adc driver"
+	depends on MFD_PM8921_CORE
+	help
+	  Say Y here to enable support for pm8921 chip bms subdevice
+
 config PM8921_BMS
+	select PM8XXX_CCADC
 	tristate "PM8921 Battery Monitoring System driver"
 	depends on MFD_PM8921_CORE
 	help
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index f61c88a..e168590 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -45,5 +45,6 @@
 obj-$(CONFIG_BATTERY_BQ27520)	+= bq27520_fuelgauger.o
 obj-$(CONFIG_BATTERY_BQ27541)	+= bq27541_fuelgauger.o
 obj-$(CONFIG_SMB137B_CHARGER)   += smb137b.o
+obj-$(CONFIG_PM8XXX_CCADC)	+= pm8xxx-ccadc.o
 obj-$(CONFIG_PM8921_BMS)	+= pm8921-bms.o
 obj-$(CONFIG_PM8921_CHARGER)	+= pm8921-charger.o
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index d7cf3a8..143d9b5 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -19,6 +19,7 @@
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
@@ -29,15 +30,6 @@
 #define BMS_OUTPUT0		0x230
 #define BMS_OUTPUT1		0x231
 #define BMS_TEST1		0x237
-#define CCADC_ANA_PARAM		0x240
-#define CCADC_DIG_PARAM		0x241
-#define CCADC_RSV		0x242
-#define CCADC_DATA0		0x244
-#define CCADC_DATA1		0x245
-#define CCADC_OFFSET_TRIM1	0x34A
-#define CCADC_OFFSET_TRIM0	0x34B
-#define CCADC_FULLSCALE_TRIM1	0x34C
-#define CCADC_FULLSCALE_TRIM0	0x34D
 
 #define ADC_ARB_SECP_CNTRL	0x190
 #define ADC_ARB_SECP_AMUX_CNTRL	0x191
@@ -57,7 +49,6 @@
 	PM8921_BMS_OCV_FOR_R,
 	PM8921_BMS_GOOD_OCV,
 	PM8921_BMS_VSENSE_AVG,
-	PM8921_BMS_CCADC_EOC,
 	PM_BMS_MAX_INTS,
 };
 
@@ -75,8 +66,6 @@
 	struct work_struct	calib_hkadc_work;
 	struct delayed_work	calib_ccadc_work;
 	unsigned int		calib_delay_ms;
-	int			ccadc_gain_uv;
-	u16			ccadc_result_offset;
 	unsigned int		revision;
 	unsigned int		xoadc_v0625;
 	unsigned int		xoadc_v125;
@@ -400,56 +389,6 @@
 				cc_to_microvolt_v2((s64)cc);
 }
 
-#define CCADC_READING_RESOLUTION_N_V1	1085069
-#define CCADC_READING_RESOLUTION_D_V1	100000
-#define CCADC_READING_RESOLUTION_N_V2	542535
-#define CCADC_READING_RESOLUTION_D_V2	100000
-static s64 ccadc_reading_to_microvolt_v1(s64 cc)
-{
-	return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
-					CCADC_READING_RESOLUTION_D_V1);
-}
-
-static s64 ccadc_reading_to_microvolt_v2(s64 cc)
-{
-	return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
-					CCADC_READING_RESOLUTION_D_V2);
-}
-
-static s64 ccadc_reading_to_microvolt(struct pm8921_bms_chip *chip, s64 cc)
-{
-	/*
-	 * resolution (the value of a single bit) was changed after revision 2.0
-	 * for more accurate readings
-	 */
-	return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
-				ccadc_reading_to_microvolt_v1((s64)cc) :
-				ccadc_reading_to_microvolt_v2((s64)cc);
-}
-
-static s64 microvolt_to_ccadc_reading_v1(s64 uv)
-{
-	return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
-				CCADC_READING_RESOLUTION_N_V1);
-}
-
-static s64 microvolt_to_ccadc_reading_v2(s64 uv)
-{
-	return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
-				CCADC_READING_RESOLUTION_N_V2);
-}
-
-static s64 microvolt_to_ccadc_reading(struct pm8921_bms_chip *chip, s64 cc)
-{
-	/*
-	 * resolution (the value of a single bit) was changed after revision 2.0
-	 * for more accurate readings
-	 */
-	return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
-				microvolt_to_ccadc_reading_v1((s64)cc) :
-				microvolt_to_ccadc_reading_v2((s64)cc);
-}
-
 #define CC_READING_TICKS	55
 #define SLEEP_CLK_HZ		32768
 #define SECONDS_PER_HOUR	3600
@@ -459,19 +398,6 @@
 			SLEEP_CLK_HZ * SECONDS_PER_HOUR);
 }
 
-#define GAIN_REFERENCE_UV 25000
-/*
- * gain compensation for ccadc readings - common for vsense based and
- * couloumb counter based readings
- */
-static s64 cc_adjust_for_gain(struct pm8921_bms_chip *chip, s64 cc)
-{
-	if (chip->ccadc_gain_uv == 0)
-		return cc;
-
-	return div_s64(cc * GAIN_REFERENCE_UV, chip->ccadc_gain_uv);
-}
-
 /* returns the signed value read from the hardware */
 static int read_cc(struct pm8921_bms_chip *chip, int *result)
 {
@@ -559,9 +485,9 @@
 		pr_err("fail to read VSENSE_FOR_RBATT rc = %d\n", rc);
 		return rc;
 	}
-	*result = ccadc_reading_to_microvolt(chip, reading);
+	*result = pm8xxx_ccadc_reading_to_microvolt(chip->revision, reading);
 	pr_debug("raw = %04x vsense_for_r_uV = %u\n", reading, *result);
-	*result = cc_adjust_for_gain(chip, *result);
+	*result = pm8xxx_cc_adjust_for_gain(*result);
 	pr_debug("after adj vsense_for_r_uV = %u\n", *result);
 	return 0;
 }
@@ -593,9 +519,10 @@
 		pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
 		return rc;
 	}
-	*result = ccadc_reading_to_microvolt(chip, reading);
+	*result = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+								reading);
 	pr_debug("raw = %04x vsense = %d\n", reading, *result);
-	*result = cc_adjust_for_gain(the_chip, (s64)*result);
+	*result = pm8xxx_cc_adjust_for_gain((s64)*result);
 	pr_debug("after adj vsense = %d\n", *result);
 	return 0;
 }
@@ -976,7 +903,7 @@
 	rc = read_cc(the_chip, coulumb_counter);
 	cc_voltage_uv = (int64_t)*coulumb_counter;
 	cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
-	cc_voltage_uv = cc_adjust_for_gain(chip, cc_voltage_uv);
+	cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
 	pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
 	cc_uvh = ccmicrovolt_to_uvh(cc_voltage_uv);
 	pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh);
@@ -1224,386 +1151,12 @@
 	calib_hkadc(chip);
 }
 
-#define START_CONV_BIT	BIT(7)
-#define EOC_CONV_BIT	BIT(6)
-#define SEL_CCADC_BIT	BIT(1)
-#define EN_ARB_BIT	BIT(0)
-
-#define CCADC_CALIB_DIG_PARAM	0xE3
-#define CCADC_CALIB_RSV_GND	0x40
-#define CCADC_CALIB_RSV_25MV	0x80
-#define CCADC_CALIB_ANA_PARAM	0x1B
-#define SAMPLE_COUNT		16
-#define ADC_WAIT_COUNT		10
-
-#define CCADC_MAX_25MV		30000
-#define CCADC_MIN_25MV		20000
-#define CCADC_MAX_0UV		-4000
-#define CCADC_MIN_0UV		-7000
-
-#define CCADC_INTRINSIC_OFFSET  0xC000
-
-#define REG_SBI_CONFIG		0x04F
-#define PAGE3_ENABLE_MASK	0x6
-
-static int calib_ccadc_enable_trim_access(struct pm8921_bms_chip *chip,
-								u8 *sbi_config)
-{
-	u8 reg;
-	int rc;
-
-	rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
-	if (rc) {
-		pr_err("error = %d reading sbi config reg\n", rc);
-		return rc;
-	}
-
-	reg = *sbi_config | PAGE3_ENABLE_MASK;
-	return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
-}
-
-static int calib_ccadc_restore_trim_access(struct pm8921_bms_chip *chip,
-							u8 sbi_config)
-{
-	return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
-}
-
-static int calib_ccadc_enable_arbiter(struct pm8921_bms_chip *chip)
-{
-	int rc;
-
-	/* enable Arbiter, must be sent twice */
-	rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
-			SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
-	if (rc < 0) {
-		pr_err("error = %d enabling arbiter for offset\n", rc);
-		return rc;
-	}
-	rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
-			SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
-	if (rc < 0) {
-		pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
-		return rc;
-	}
-	return 0;
-}
-
-static int calib_start_conv(struct pm8921_bms_chip *chip,
-					u16 *result)
-{
-	int rc, i;
-	u8 data_msb, data_lsb, reg;
-
-	/* Start conversion */
-	rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
-					START_CONV_BIT, START_CONV_BIT);
-	if (rc < 0) {
-		pr_err("error = %d starting offset meas\n", rc);
-		return rc;
-	}
-
-	/* Wait for End of conversion */
-	for (i = 0; i < ADC_WAIT_COUNT; i++) {
-		rc = pm8xxx_readb(chip->dev->parent,
-					ADC_ARB_SECP_CNTRL, &reg);
-		if (rc < 0) {
-			pr_err("error = %d read eoc for offset\n", rc);
-			return rc;
-		}
-		if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
-			msleep(60);
-		else
-			break;
-	}
-	if (i == ADC_WAIT_COUNT) {
-		pr_err("waited too long for offset eoc\n");
-		return rc;
-	}
-
-	rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
-	if (rc < 0) {
-		pr_err("error = %d reading offset lsb\n", rc);
-		return rc;
-	}
-
-	rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
-	if (rc < 0) {
-		pr_err("error = %d reading offset msb\n", rc);
-		return rc;
-	}
-
-	*result = (data_msb << 8) | data_lsb;
-	return 0;
-}
-
-static int calib_ccadc_read_trim(struct pm8921_bms_chip *chip,
-					int addr, u8 *data_msb, u8 *data_lsb)
-{
-	int rc;
-	u8 sbi_config;
-
-	calib_ccadc_enable_trim_access(chip, &sbi_config);
-	rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
-	if (rc < 0) {
-		pr_err("error = %d read msb\n", rc);
-		return rc;
-	}
-	rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
-	if (rc < 0) {
-		pr_err("error = %d read lsb\n", rc);
-		return rc;
-	}
-	calib_ccadc_restore_trim_access(chip, sbi_config);
-	return 0;
-}
-
-static int calib_ccadc_read_gain_uv(struct pm8921_bms_chip *chip)
-{
-	s8 data_msb;
-	u8 data_lsb;
-	int rc, gain, offset;
-
-	rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
-						&data_msb, &data_lsb);
-	gain = (data_msb << 8) | data_lsb;
-
-	rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
-						&data_msb, &data_lsb);
-	offset = (data_msb << 8) | data_lsb;
-
-	pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", gain, offset);
-	gain = ccadc_reading_to_microvolt(chip, (s64)gain - offset);
-	return gain;
-}
-
-#define CCADC_PROGRAM_TRIM_COUNT	2
-#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT	4
-#define ADC_ARB_BMS_CNTRL_CONV_MASK	0x03
-#define BMS_CONV_IN_PROGRESS		0x2
-
-static int calib_ccadc_program_trim(struct pm8921_bms_chip *chip,
-					int addr, u8 data_msb, u8 data_lsb,
-					int wait)
-{
-	int i, rc, loop;
-	u8 cntrl, sbi_config;
-	bool in_progress = 0;
-
-	loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
-
-	calib_ccadc_enable_trim_access(chip, &sbi_config);
-
-	for (i = 0; i < loop; i++) {
-		rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
-		if (rc < 0) {
-			pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
-			return rc;
-		}
-
-		/* break if a ccadc conversion is not happening */
-		in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
-			& ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
-
-		if (!in_progress)
-			break;
-	}
-
-	if (in_progress) {
-		pr_debug("conv in progress cannot write trim,returing EBUSY\n");
-		return -EBUSY;
-	}
-
-	rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
-	if (rc < 0) {
-		pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
-		return rc;
-	}
-	rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
-	if (rc < 0) {
-		pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
-		return rc;
-	}
-	calib_ccadc_restore_trim_access(chip, sbi_config);
-	return 0;
-}
-
-static void calib_ccadc(struct pm8921_bms_chip *chip)
-{
-	u8 data_msb, data_lsb, sec_cntrl;
-	int result_offset, voltage_offset, result_gain;
-	u16 result;
-	int i, rc;
-
-	rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_CNTRL, &sec_cntrl);
-	if (rc < 0) {
-		pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
-		return;
-	}
-
-	rc = calib_ccadc_enable_arbiter(chip);
-	if (rc < 0) {
-		pr_err("error = %d enabling arbiter for offset\n", rc);
-		goto bail;
-	}
-
-	/*
-	 * Set decimation ratio to 4k, lower ratio may be used in order to speed
-	 * up, pending verification through bench
-	 */
-	rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
-							CCADC_CALIB_DIG_PARAM);
-	if (rc < 0) {
-		pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
-		goto bail;
-	}
-
-	result_offset = 0;
-	for (i = 0; i < SAMPLE_COUNT; i++) {
-		/* Short analog inputs to CCADC internally to ground */
-		rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_RSV,
-							CCADC_CALIB_RSV_GND);
-		if (rc < 0) {
-			pr_err("error = %d selecting gnd voltage\n", rc);
-			goto bail;
-		}
-
-		/* Enable CCADC */
-		rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
-							CCADC_CALIB_ANA_PARAM);
-		if (rc < 0) {
-			pr_err("error = %d enabling ccadc\n", rc);
-			goto bail;
-		}
-
-		rc = calib_start_conv(chip, &result);
-		if (rc < 0) {
-			pr_err("error = %d for zero volt measurement\n", rc);
-			goto bail;
-		}
-
-		result_offset += result;
-	}
-
-	result_offset = result_offset / SAMPLE_COUNT;
-
-	voltage_offset = ccadc_reading_to_microvolt(chip,
-			((s64)result_offset - CCADC_INTRINSIC_OFFSET));
-
-	pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
-				result_offset, voltage_offset);
-
-	/* Sanity Check */
-	if (voltage_offset > CCADC_MAX_0UV) {
-		pr_err("offset voltage = %d is huge limiting to %d\n",
-					voltage_offset, CCADC_MAX_0UV);
-		result_offset = CCADC_INTRINSIC_OFFSET
-			+ microvolt_to_ccadc_reading(chip, (s64)CCADC_MAX_0UV);
-	} else if (voltage_offset < CCADC_MIN_0UV) {
-		pr_err("offset voltage = %d is too low limiting to %d\n",
-					voltage_offset, CCADC_MIN_0UV);
-		result_offset = CCADC_INTRINSIC_OFFSET
-			+ microvolt_to_ccadc_reading(chip, (s64)CCADC_MIN_0UV);
-	}
-
-	chip->ccadc_result_offset = result_offset;
-	data_msb = chip->ccadc_result_offset >> 8;
-	data_lsb = chip->ccadc_result_offset;
-
-	rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
-						data_msb, data_lsb, 1);
-	if (rc) {
-		pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
-					rc, data_msb, data_lsb);
-		/* enable the interrupt and write it when it fires */
-		pm8921_bms_enable_irq(chip, PM8921_BMS_CCADC_EOC);
-	}
-
-	rc = calib_ccadc_enable_arbiter(chip);
-	if (rc < 0) {
-		pr_err("error = %d enabling arbiter for gain\n", rc);
-		goto bail;
-	}
-
-	/*
-	 * Set decimation ratio to 4k, lower ratio may be used in order to speed
-	 * up, pending verification through bench
-	 */
-	rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
-							CCADC_CALIB_DIG_PARAM);
-	if (rc < 0) {
-		pr_err("error = %d enabling decimation ration for gain\n", rc);
-		goto bail;
-	}
-
-	result_gain = 0;
-	for (i = 0; i < SAMPLE_COUNT; i++) {
-		rc = pm8xxx_writeb(chip->dev->parent,
-					ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
-		if (rc < 0) {
-			pr_err("error = %d selecting 25mV for gain\n", rc);
-			goto bail;
-		}
-
-		/* Enable CCADC */
-		rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
-							CCADC_CALIB_ANA_PARAM);
-		if (rc < 0) {
-			pr_err("error = %d enabling ccadc\n", rc);
-			goto bail;
-		}
-
-		rc = calib_start_conv(chip, &result);
-		if (rc < 0) {
-			pr_err("error = %d for adc reading 25mV\n", rc);
-			goto bail;
-		}
-
-		result_gain += result;
-	}
-	result_gain = result_gain / SAMPLE_COUNT;
-
-	/*
-	 * result_offset includes INTRINSIC OFFSET
-	 * chip->ccadc_gain_uv will be the actual voltage
-	 * measured for 25000UV
-	 */
-	chip->ccadc_gain_uv = ccadc_reading_to_microvolt(chip,
-				((s64)result_gain - result_offset));
-
-	pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
-							result_gain,
-							chip->ccadc_gain_uv);
-	/* Sanity Check */
-	if (chip->ccadc_gain_uv > CCADC_MAX_25MV) {
-		pr_err("gain voltage = %d is huge limiting to %d\n",
-					chip->ccadc_gain_uv, CCADC_MAX_25MV);
-		chip->ccadc_gain_uv = CCADC_MAX_25MV;
-		result_gain = result_offset +
-			microvolt_to_ccadc_reading(chip, CCADC_MAX_25MV);
-	} else if (chip->ccadc_gain_uv < CCADC_MIN_25MV) {
-		pr_err("gain voltage = %d is too low limiting to %d\n",
-					chip->ccadc_gain_uv, CCADC_MIN_25MV);
-		chip->ccadc_gain_uv = CCADC_MIN_25MV;
-		result_gain = result_offset +
-			microvolt_to_ccadc_reading(chip, CCADC_MIN_25MV);
-	}
-
-	data_msb = result_gain >> 8;
-	data_lsb = result_gain;
-	rc = calib_ccadc_program_trim(chip, CCADC_FULLSCALE_TRIM1,
-						data_msb, data_lsb, 0);
-	if (rc)
-		pr_debug("error = %d programming gain trim\n", rc);
-bail:
-	pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
-}
-
 static void calibrate_ccadc_work(struct work_struct *work)
 {
 	struct pm8921_bms_chip *chip = container_of(work,
 				struct pm8921_bms_chip, calib_ccadc_work.work);
 
-	calib_ccadc(chip);
+	pm8xxx_calib_ccadc();
 	schedule_delayed_work(&chip->calib_ccadc_work,
 			round_jiffies_relative(msecs_to_jiffies
 			(chip->calib_delay_ms)));
@@ -1810,23 +1363,6 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
-{
-	u8 data_msb, data_lsb;
-	struct pm8921_bms_chip *chip = data;
-	int rc;
-
-	pr_debug("irq = %d triggered\n", irq);
-	data_msb = chip->ccadc_result_offset >> 8;
-	data_lsb = chip->ccadc_result_offset;
-
-	rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
-						data_msb, data_lsb, 0);
-	pm8921_bms_disable_irq(chip, PM8921_BMS_CCADC_EOC);
-
-	return IRQ_HANDLED;
-}
-
 struct pm_bms_irq_init_data {
 	unsigned int	irq_id;
 	char		*name;
@@ -1857,8 +1393,6 @@
 				pm8921_bms_good_ocv_handler),
 	BMS_IRQ(PM8921_BMS_VSENSE_AVG, IRQF_TRIGGER_RISING,
 				pm8921_bms_vsense_avg_handler),
-	BMS_IRQ(PM8921_BMS_CCADC_EOC, IRQF_TRIGGER_RISING,
-				pm8921_bms_ccadc_eoc_handler),
 };
 
 static void free_irqs(struct pm8921_bms_chip *chip)
@@ -2076,7 +1610,7 @@
 	case CALIB_CCADC:
 		/* reading this will trigger calibration */
 		*val = 0;
-		calib_ccadc(the_chip);
+		pm8xxx_calib_ccadc();
 		break;
 	default:
 		ret = -EINVAL;
@@ -2169,7 +1703,7 @@
 {
 	int i;
 
-	chip->dent = debugfs_create_dir("pm8921_bms", NULL);
+	chip->dent = debugfs_create_dir("pm8921-bms", NULL);
 
 	if (IS_ERR(chip->dent)) {
 		pr_err("pmic bms couldnt create debugfs dir\n");
@@ -2184,20 +1718,6 @@
 			(void *)BMS_OUTPUT1, &reg_fops);
 	debugfs_create_file("BMS_TEST1", 0644, chip->dent,
 			(void *)BMS_TEST1, &reg_fops);
-	debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
-			(void *)CCADC_ANA_PARAM, &reg_fops);
-	debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
-			(void *)CCADC_DIG_PARAM, &reg_fops);
-	debugfs_create_file("CCADC_RSV", 0644, chip->dent,
-			(void *)CCADC_RSV, &reg_fops);
-	debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
-			(void *)CCADC_DATA0, &reg_fops);
-	debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
-			(void *)CCADC_DATA1, &reg_fops);
-	debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
-			(void *)CCADC_OFFSET_TRIM1, &reg_fops);
-	debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
-			(void *)CCADC_OFFSET_TRIM0, &reg_fops);
 
 	debugfs_create_file("test_batt_temp", 0644, chip->dent,
 				(void *)TEST_BATT_TEMP, &temp_fops);
@@ -2296,7 +1816,6 @@
 	create_debugfs_entries(chip);
 
 	check_initial_ocv(chip);
-	chip->ccadc_gain_uv = calib_ccadc_read_gain_uv(chip);
 
 	INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
 	/* begin calibration only on chips > 2.0 */
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 148a5e5..e517146 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -19,6 +19,7 @@
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/interrupt.h>
 #include <linux/power_supply.h>
@@ -201,8 +202,8 @@
  * @update_time:		how frequently the userland needs to be updated
  * @max_voltage:		the max volts the batt should be charged up to
  * @min_voltage:		the min battery voltage before turning the FETon
- * @resume_voltage:		the voltage at which the battery should resume
- *				charging
+ * @resume_voltage_delta:	the voltage delta from vdd max at which the
+ *				battery should resume charging
  * @term_current:		The charging based term current
  *
  */
@@ -225,7 +226,9 @@
 	unsigned int			warm_bat_chg_current;
 	unsigned int			cool_bat_voltage;
 	unsigned int			warm_bat_voltage;
-	unsigned int			resume_voltage;
+	unsigned int			is_bat_cool;
+	unsigned int			is_bat_warm;
+	unsigned int			resume_voltage_delta;
 	unsigned int			term_current;
 	unsigned int			vbat_channel;
 	unsigned int			batt_temp_channel;
@@ -935,10 +938,28 @@
 	return (int)result.physical;
 }
 
+static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
+{
+	unsigned int current_voltage = get_prop_battery_mvolts(chip);
+	unsigned int low_voltage = chip->min_voltage;
+	unsigned int high_voltage = chip->max_voltage;
+
+	if (current_voltage <= low_voltage)
+		return 0;
+	else if (current_voltage >= high_voltage)
+		return 100;
+	else
+		return (current_voltage - low_voltage) * 100
+		    / (high_voltage - low_voltage);
+}
+
 static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
 {
 	int percent_soc = pm8921_bms_get_percent_charge();
 
+	if (percent_soc == -ENXIO)
+		percent_soc = voltage_based_capacity(chip);
+
 	if (percent_soc <= 10)
 		pr_warn("low battery charge = %d%%\n", percent_soc);
 
@@ -950,6 +971,10 @@
 	int result_ma, rc;
 
 	rc = pm8921_bms_get_battery_current(&result_ma);
+	if (rc == -ENXIO) {
+		rc = pm8xxx_ccadc_get_battery_current(&result_ma);
+	}
+
 	if (rc) {
 		pr_err("unable to get batt current rc = %d\n", rc);
 		return rc;
@@ -1898,11 +1923,17 @@
 			the_chip->cool_temp + TEMP_HYSTERISIS_DEGC;
 		pm_chg_ibatmax_set(the_chip, the_chip->cool_bat_chg_current);
 		pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
+		pm_chg_vbatdet_set(the_chip,
+			the_chip->cool_bat_voltage
+			- the_chip->resume_voltage_delta);
 	} else {
 		btm_config.low_thr_temp = the_chip->cool_temp;
 		pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
 		pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+		pm_chg_vbatdet_set(the_chip,
+			the_chip->max_voltage - the_chip->resume_voltage_delta);
 	}
+	the_chip->is_bat_cool = enter;
 	schedule_work(&btm_config_work);
 }
 
@@ -1914,11 +1945,17 @@
 			the_chip->warm_temp - TEMP_HYSTERISIS_DEGC;
 		pm_chg_ibatmax_set(the_chip, the_chip->warm_bat_chg_current);
 		pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
+		pm_chg_vbatdet_set(the_chip,
+			the_chip->warm_bat_voltage
+			- the_chip->resume_voltage_delta);
 	} else {
 		btm_config.high_thr_temp = the_chip->warm_temp;
 		pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
 		pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+		pm_chg_vbatdet_set(the_chip,
+			the_chip->max_voltage - the_chip->resume_voltage_delta);
 	}
+	the_chip->is_bat_warm = enter;
 	schedule_work(&btm_config_work);
 }
 
@@ -2211,10 +2248,11 @@
 						chip->max_voltage, rc);
 		return rc;
 	}
-	rc = pm_chg_vbatdet_set(chip, chip->resume_voltage);
+	rc = pm_chg_vbatdet_set(chip,
+				chip->max_voltage - chip->resume_voltage_delta);
 	if (rc) {
 		pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
-						chip->resume_voltage, rc);
+			chip->max_voltage - chip->resume_voltage_delta, rc);
 		return rc;
 	}
 
@@ -2458,6 +2496,24 @@
 }
 DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
 
+enum {
+	BAT_WARM_ZONE,
+	BAT_COOL_ZONE,
+};
+static int get_warm_cool(void *data, u64 * val)
+{
+	if (!the_chip) {
+		pr_err("%s called before init\n", __func__);
+		return -EINVAL;
+	}
+	if ((int)data == BAT_WARM_ZONE)
+		*val = the_chip->is_bat_warm;
+	if ((int)data == BAT_COOL_ZONE)
+		*val = the_chip->is_bat_cool;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
+
 static void create_debugfs_entries(struct pm8921_chg_chip *chip)
 {
 	int i;
@@ -2524,6 +2580,11 @@
 	debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
 			    &reg_loop_fops);
 
+	debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
+				(void *)BAT_WARM_ZONE, &warm_cool_fops);
+	debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
+				(void *)BAT_COOL_ZONE, &warm_cool_fops);
+
 	for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
 		if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
 			debugfs_create_file(chg_irq_data[i].name, 0444,
@@ -2558,7 +2619,7 @@
 	chip->update_time = pdata->update_time;
 	chip->max_voltage = pdata->max_voltage;
 	chip->min_voltage = pdata->min_voltage;
-	chip->resume_voltage = pdata->resume_voltage;
+	chip->resume_voltage_delta = pdata->resume_voltage_delta;
 	chip->term_current = pdata->term_current;
 	chip->vbat_channel = pdata->charger_cdata.vbat_channel;
 	chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
new file mode 100644
index 0000000..1245045
--- /dev/null
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -0,0 +1,761 @@
+/* Copyright (c) 2011, 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.
+ *
+ */
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#define CCADC_ANA_PARAM		0x240
+#define CCADC_DIG_PARAM		0x241
+#define CCADC_RSV		0x242
+#define CCADC_DATA0		0x244
+#define CCADC_DATA1		0x245
+#define CCADC_OFFSET_TRIM1	0x34A
+#define CCADC_OFFSET_TRIM0	0x34B
+#define CCADC_FULLSCALE_TRIM1	0x34C
+#define CCADC_FULLSCALE_TRIM0	0x34D
+
+/* note : TRIM1 is the msb and TRIM0 is the lsb */
+#define ADC_ARB_SECP_CNTRL	0x190
+#define ADC_ARB_SECP_AMUX_CNTRL	0x191
+#define ADC_ARB_SECP_ANA_PARAM	0x192
+#define ADC_ARB_SECP_DIG_PARAM	0x193
+#define ADC_ARB_SECP_RSV	0x194
+#define ADC_ARB_SECP_DATA1	0x195
+#define ADC_ARB_SECP_DATA0	0x196
+
+#define ADC_ARB_BMS_CNTRL	0x18D
+
+#define START_CONV_BIT	BIT(7)
+#define EOC_CONV_BIT	BIT(6)
+#define SEL_CCADC_BIT	BIT(1)
+#define EN_ARB_BIT	BIT(0)
+
+#define CCADC_CALIB_DIG_PARAM	0xE3
+#define CCADC_CALIB_RSV_GND	0x40
+#define CCADC_CALIB_RSV_25MV	0x80
+#define CCADC_CALIB_ANA_PARAM	0x1B
+#define SAMPLE_COUNT		16
+#define ADC_WAIT_COUNT		10
+
+#define CCADC_MAX_25MV		30000
+#define CCADC_MIN_25MV		20000
+#define CCADC_MAX_0UV		-4000
+#define CCADC_MIN_0UV		-7000
+
+#define CCADC_INTRINSIC_OFFSET  0xC000
+
+struct pm8xxx_ccadc_chip {
+	struct device		*dev;
+	struct dentry		*dent;
+	u16			ccadc_offset;
+	int			ccadc_gain_uv;
+	unsigned int		revision;
+	int			eoc_irq;
+	int			r_sense;
+};
+
+static struct pm8xxx_ccadc_chip *the_chip;
+
+static s64 microvolt_to_ccadc_reading_v1(s64 uv)
+{
+	return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
+				CCADC_READING_RESOLUTION_N_V1);
+}
+
+static s64 microvolt_to_ccadc_reading_v2(s64 uv)
+{
+	return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
+				CCADC_READING_RESOLUTION_N_V2);
+}
+
+static s64 microvolt_to_ccadc_reading(struct pm8xxx_ccadc_chip *chip, s64 cc)
+{
+	/*
+	 * resolution (the value of a single bit) was changed after revision 2.0
+	 * for more accurate readings
+	 */
+	return (the_chip->revision < PM8XXX_REVISION_8921_2p0) ?
+				microvolt_to_ccadc_reading_v1((s64)cc) :
+				microvolt_to_ccadc_reading_v2((s64)cc);
+}
+
+static int cc_adjust_for_offset(u16 raw)
+{
+	/* this has the intrinsic offset */
+	return (int)raw - the_chip->ccadc_offset;
+}
+
+#define GAIN_REFERENCE_UV 25000
+/*
+ * gain compensation for ccadc readings - common for vsense based and
+ * couloumb counter based readings
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+	if (the_chip == NULL || the_chip->ccadc_gain_uv == 0)
+		return uv;
+
+	return div_s64(uv * GAIN_REFERENCE_UV, the_chip->ccadc_gain_uv);
+}
+EXPORT_SYMBOL(pm8xxx_cc_adjust_for_gain);
+
+static int pm_ccadc_masked_write(struct pm8xxx_ccadc_chip *chip, u16 addr,
+							u8 mask, u8 val)
+{
+	int rc;
+	u8 reg;
+
+	rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
+	if (rc) {
+		pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
+		return rc;
+	}
+	reg &= ~mask;
+	reg |= val & mask;
+	rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+	if (rc) {
+		pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
+		return rc;
+	}
+	return 0;
+}
+
+#define REG_SBI_CONFIG		0x04F
+#define PAGE3_ENABLE_MASK	0x6
+static int calib_ccadc_enable_trim_access(struct pm8xxx_ccadc_chip *chip,
+								u8 *sbi_config)
+{
+	u8 reg;
+	int rc;
+
+	rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+	if (rc) {
+		pr_err("error = %d reading sbi config reg\n", rc);
+		return rc;
+	}
+
+	reg = *sbi_config | PAGE3_ENABLE_MASK;
+	return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
+}
+
+static int calib_ccadc_restore_trim_access(struct pm8xxx_ccadc_chip *chip,
+							u8 sbi_config)
+{
+	return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+}
+
+static int calib_ccadc_enable_arbiter(struct pm8xxx_ccadc_chip *chip)
+{
+	int rc;
+
+	/* enable Arbiter, must be sent twice */
+	rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+			SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+	if (rc < 0) {
+		pr_err("error = %d enabling arbiter for offset\n", rc);
+		return rc;
+	}
+	rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+			SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+	if (rc < 0) {
+		pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int calib_start_conv(struct pm8xxx_ccadc_chip *chip,
+					u16 *result)
+{
+	int rc, i;
+	u8 data_msb, data_lsb, reg;
+
+	/* Start conversion */
+	rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+					START_CONV_BIT, START_CONV_BIT);
+	if (rc < 0) {
+		pr_err("error = %d starting offset meas\n", rc);
+		return rc;
+	}
+
+	/* Wait for End of conversion */
+	for (i = 0; i < ADC_WAIT_COUNT; i++) {
+		rc = pm8xxx_readb(chip->dev->parent,
+					ADC_ARB_SECP_CNTRL, &reg);
+		if (rc < 0) {
+			pr_err("error = %d read eoc for offset\n", rc);
+			return rc;
+		}
+		if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
+			msleep(60);
+		else
+			break;
+	}
+	if (i == ADC_WAIT_COUNT) {
+		pr_err("waited too long for offset eoc\n");
+		return rc;
+	}
+
+	rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
+	if (rc < 0) {
+		pr_err("error = %d reading offset lsb\n", rc);
+		return rc;
+	}
+
+	rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
+	if (rc < 0) {
+		pr_err("error = %d reading offset msb\n", rc);
+		return rc;
+	}
+
+	*result = (data_msb << 8) | data_lsb;
+	return 0;
+}
+
+static int calib_ccadc_read_trim(struct pm8xxx_ccadc_chip *chip,
+					int addr, u8 *data_msb, u8 *data_lsb)
+{
+	int rc;
+	u8 sbi_config;
+
+	calib_ccadc_enable_trim_access(chip, &sbi_config);
+	rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
+	if (rc < 0) {
+		pr_err("error = %d read msb\n", rc);
+		return rc;
+	}
+	rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
+	if (rc < 0) {
+		pr_err("error = %d read lsb\n", rc);
+		return rc;
+	}
+	calib_ccadc_restore_trim_access(chip, sbi_config);
+	return 0;
+}
+
+static void calib_ccadc_read_offset_and_gain(struct pm8xxx_ccadc_chip *chip,
+						int *gain, u16 *offset)
+{
+	s8 data_msb;
+	u8 data_lsb;
+	int rc;
+
+	rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
+						&data_msb, &data_lsb);
+	*gain = (data_msb << 8) | data_lsb;
+
+	rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
+						&data_msb, &data_lsb);
+	*offset = (data_msb << 8) | data_lsb;
+
+	pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", *gain, *offset);
+	*gain = pm8xxx_ccadc_reading_to_microvolt(chip->revision,
+							(s64)*gain - *offset);
+	pr_debug("gain uv = %duV offset=0x%x\n", *gain, *offset);
+}
+
+#define CCADC_PROGRAM_TRIM_COUNT	2
+#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT	4
+#define ADC_ARB_BMS_CNTRL_CONV_MASK	0x03
+#define BMS_CONV_IN_PROGRESS		0x2
+
+static int calib_ccadc_program_trim(struct pm8xxx_ccadc_chip *chip,
+					int addr, u8 data_msb, u8 data_lsb,
+					int wait)
+{
+	int i, rc, loop;
+	u8 cntrl, sbi_config;
+	bool in_progress = 0;
+
+	loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
+
+	calib_ccadc_enable_trim_access(chip, &sbi_config);
+
+	for (i = 0; i < loop; i++) {
+		rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
+		if (rc < 0) {
+			pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
+			return rc;
+		}
+
+		/* break if a ccadc conversion is not happening */
+		in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
+			& ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
+
+		if (!in_progress)
+			break;
+	}
+
+	if (in_progress) {
+		pr_debug("conv in progress cannot write trim,returing EBUSY\n");
+		return -EBUSY;
+	}
+
+	rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
+	if (rc < 0) {
+		pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
+		return rc;
+	}
+	rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
+	if (rc < 0) {
+		pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
+		return rc;
+	}
+	calib_ccadc_restore_trim_access(chip, sbi_config);
+	return 0;
+}
+
+void pm8xxx_calib_ccadc(void)
+{
+	u8 data_msb, data_lsb, sec_cntrl;
+	int result_offset, voltage_offset, result_gain;
+	u16 result;
+	int i, rc;
+
+	rc = pm8xxx_readb(the_chip->dev->parent,
+					ADC_ARB_SECP_CNTRL, &sec_cntrl);
+	if (rc < 0) {
+		pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
+		return;
+	}
+
+	rc = calib_ccadc_enable_arbiter(the_chip);
+	if (rc < 0) {
+		pr_err("error = %d enabling arbiter for offset\n", rc);
+		goto bail;
+	}
+
+	/*
+	 * Set decimation ratio to 4k, lower ratio may be used in order to speed
+	 * up, pending verification through bench
+	 */
+	rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+							CCADC_CALIB_DIG_PARAM);
+	if (rc < 0) {
+		pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+		goto bail;
+	}
+
+	result_offset = 0;
+	for (i = 0; i < SAMPLE_COUNT; i++) {
+		/* Short analog inputs to CCADC internally to ground */
+		rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+							CCADC_CALIB_RSV_GND);
+		if (rc < 0) {
+			pr_err("error = %d selecting gnd voltage\n", rc);
+			goto bail;
+		}
+
+		/* Enable CCADC */
+		rc = pm8xxx_writeb(the_chip->dev->parent,
+				ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+		if (rc < 0) {
+			pr_err("error = %d enabling ccadc\n", rc);
+			goto bail;
+		}
+
+		rc = calib_start_conv(the_chip, &result);
+		if (rc < 0) {
+			pr_err("error = %d for zero volt measurement\n", rc);
+			goto bail;
+		}
+
+		result_offset += result;
+	}
+
+	result_offset = result_offset / SAMPLE_COUNT;
+
+	voltage_offset = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+			((s64)result_offset - CCADC_INTRINSIC_OFFSET));
+
+	pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
+				result_offset, voltage_offset);
+
+	/* Sanity Check */
+	if (voltage_offset > CCADC_MAX_0UV) {
+		pr_err("offset voltage = %d is huge limiting to %d\n",
+					voltage_offset, CCADC_MAX_0UV);
+		result_offset = CCADC_INTRINSIC_OFFSET
+			+ microvolt_to_ccadc_reading(the_chip,
+							(s64)CCADC_MAX_0UV);
+	} else if (voltage_offset < CCADC_MIN_0UV) {
+		pr_err("offset voltage = %d is too low limiting to %d\n",
+					voltage_offset, CCADC_MIN_0UV);
+		result_offset = CCADC_INTRINSIC_OFFSET
+			+ microvolt_to_ccadc_reading(the_chip,
+							(s64)CCADC_MIN_0UV);
+	}
+
+	the_chip->ccadc_offset = result_offset;
+	data_msb = the_chip->ccadc_offset >> 8;
+	data_lsb = the_chip->ccadc_offset;
+
+	rc = calib_ccadc_program_trim(the_chip, CCADC_OFFSET_TRIM1,
+						data_msb, data_lsb, 1);
+	if (rc) {
+		pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
+					rc, data_msb, data_lsb);
+		/* enable the interrupt and write it when it fires */
+		enable_irq(the_chip->eoc_irq);
+	}
+
+	rc = calib_ccadc_enable_arbiter(the_chip);
+	if (rc < 0) {
+		pr_err("error = %d enabling arbiter for gain\n", rc);
+		goto bail;
+	}
+
+	/*
+	 * Set decimation ratio to 4k, lower ratio may be used in order to speed
+	 * up, pending verification through bench
+	 */
+	rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+							CCADC_CALIB_DIG_PARAM);
+	if (rc < 0) {
+		pr_err("error = %d enabling decimation ration for gain\n", rc);
+		goto bail;
+	}
+
+	result_gain = 0;
+	for (i = 0; i < SAMPLE_COUNT; i++) {
+		rc = pm8xxx_writeb(the_chip->dev->parent,
+					ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
+		if (rc < 0) {
+			pr_err("error = %d selecting 25mV for gain\n", rc);
+			goto bail;
+		}
+
+		/* Enable CCADC */
+		rc = pm8xxx_writeb(the_chip->dev->parent,
+			ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+		if (rc < 0) {
+			pr_err("error = %d enabling ccadc\n", rc);
+			goto bail;
+		}
+
+		rc = calib_start_conv(the_chip, &result);
+		if (rc < 0) {
+			pr_err("error = %d for adc reading 25mV\n", rc);
+			goto bail;
+		}
+
+		result_gain += result;
+	}
+	result_gain = result_gain / SAMPLE_COUNT;
+
+	/*
+	 * result_offset includes INTRINSIC OFFSET
+	 * the_chip->ccadc_gain_uv will be the actual voltage
+	 * measured for 25000UV
+	 */
+	the_chip->ccadc_gain_uv = pm8xxx_ccadc_reading_to_microvolt(
+				the_chip->revision,
+				((s64)result_gain - result_offset));
+
+	pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
+					result_gain, the_chip->ccadc_gain_uv);
+	/* Sanity Check */
+	if (the_chip->ccadc_gain_uv > CCADC_MAX_25MV) {
+		pr_err("gain voltage = %d is huge limiting to %d\n",
+					the_chip->ccadc_gain_uv,
+					CCADC_MAX_25MV);
+		the_chip->ccadc_gain_uv = CCADC_MAX_25MV;
+		result_gain = result_offset +
+			microvolt_to_ccadc_reading(the_chip, CCADC_MAX_25MV);
+	} else if (the_chip->ccadc_gain_uv < CCADC_MIN_25MV) {
+		pr_err("gain voltage = %d is too low limiting to %d\n",
+					the_chip->ccadc_gain_uv,
+					CCADC_MIN_25MV);
+		the_chip->ccadc_gain_uv = CCADC_MIN_25MV;
+		result_gain = result_offset +
+			microvolt_to_ccadc_reading(the_chip, CCADC_MIN_25MV);
+	}
+
+	data_msb = result_gain >> 8;
+	data_lsb = result_gain;
+	rc = calib_ccadc_program_trim(the_chip, CCADC_FULLSCALE_TRIM1,
+						data_msb, data_lsb, 0);
+	if (rc)
+		pr_debug("error = %d programming gain trim\n", rc);
+bail:
+	pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
+}
+EXPORT_SYMBOL(pm8xxx_calib_ccadc);
+
+static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
+{
+	u8 data_msb, data_lsb;
+	struct pm8xxx_ccadc_chip *chip = data;
+	int rc;
+
+	pr_debug("irq = %d triggered\n", irq);
+	data_msb = chip->ccadc_offset >> 8;
+	data_lsb = chip->ccadc_offset;
+
+	rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
+						data_msb, data_lsb, 0);
+	disable_irq_nosync(chip->eoc_irq);
+
+	return IRQ_HANDLED;
+}
+
+#define CCADC_IBAT_DIG_PARAM	0xA3
+#define CCADC_IBAT_RSV		0x10
+#define CCADC_IBAT_ANA_PARAM	0x1A
+static int ccadc_get_rsense_voltage(int *voltage_uv)
+{
+	u16 raw;
+	int result;
+	int rc = 0;
+
+	rc = calib_ccadc_enable_arbiter(the_chip);
+	if (rc < 0) {
+		pr_err("error = %d enabling arbiter for offset\n", rc);
+		return rc;
+	}
+
+	rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+							CCADC_IBAT_DIG_PARAM);
+	if (rc < 0) {
+		pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+		return rc;
+	}
+
+	rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+						CCADC_IBAT_RSV);
+	if (rc < 0) {
+		pr_err("error = %d selecting rsense\n", rc);
+		return rc;
+	}
+
+	rc = pm8xxx_writeb(the_chip->dev->parent,
+			ADC_ARB_SECP_ANA_PARAM, CCADC_IBAT_ANA_PARAM);
+	if (rc < 0) {
+		pr_err("error = %d enabling ccadc\n", rc);
+		return rc;
+	}
+
+	rc = calib_start_conv(the_chip, &raw);
+	if (rc < 0) {
+		pr_err("error = %d for zero volt measurement\n", rc);
+		return rc;
+	}
+
+	pr_debug("Vsense raw = 0x%x\n", raw);
+	result = cc_adjust_for_offset(raw);
+	pr_debug("Vsense after offset raw = 0x%x offset=0x%x\n",
+					result,
+					the_chip->ccadc_offset);
+	*voltage_uv = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+			((s64)result));
+	pr_debug("Vsense before gain = %d uV\n", *voltage_uv);
+	*voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
+
+	pr_debug("Vsense = %d uV\n", *voltage_uv);
+	return 0;
+}
+
+int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+	int voltage_uv, rc;
+
+	rc = ccadc_get_rsense_voltage(&voltage_uv);
+	if (rc) {
+		pr_err("cant get voltage across rsense rc = %d\n", rc);
+		return rc;
+	}
+
+	*bat_current = voltage_uv/the_chip->r_sense;
+	/*
+	 * ccadc reads +ve current when the battery is charging
+	 * We need to return -ve if the battery is charging
+	 */
+	*bat_current = -1 * (*bat_current);
+	pr_debug("bat current = %d ma\n", *bat_current);
+	return 0;
+}
+EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
+
+static int get_reg(void *data, u64 * val)
+{
+	int addr = (int)data;
+	int ret;
+	u8 temp;
+
+	ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
+	if (ret) {
+		pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
+			addr, temp, ret);
+		return -EAGAIN;
+	}
+	*val = temp;
+	return 0;
+}
+
+static int set_reg(void *data, u64 val)
+{
+	int addr = (int)data;
+	int ret;
+	u8 temp;
+
+	temp = (u8) val;
+	ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
+	if (ret) {
+		pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
+			addr, temp, ret);
+		return -EAGAIN;
+	}
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+
+static int get_calc(void *data, u64 * val)
+{
+	int ibat, rc;
+
+	rc = pm8xxx_ccadc_get_battery_current(&ibat);
+	*val = ibat;
+	return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%lld\n");
+
+static void create_debugfs_entries(struct pm8xxx_ccadc_chip *chip)
+{
+	chip->dent = debugfs_create_dir("pm8xxx-ccadc", NULL);
+
+	if (IS_ERR(chip->dent)) {
+		pr_err("ccadc couldnt create debugfs dir\n");
+		return;
+	}
+
+	debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
+			(void *)CCADC_ANA_PARAM, &reg_fops);
+	debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
+			(void *)CCADC_DIG_PARAM, &reg_fops);
+	debugfs_create_file("CCADC_RSV", 0644, chip->dent,
+			(void *)CCADC_RSV, &reg_fops);
+	debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
+			(void *)CCADC_DATA0, &reg_fops);
+	debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
+			(void *)CCADC_DATA1, &reg_fops);
+	debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
+			(void *)CCADC_OFFSET_TRIM1, &reg_fops);
+	debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
+			(void *)CCADC_OFFSET_TRIM0, &reg_fops);
+	debugfs_create_file("CCADC_FULLSCALE_TRIM1", 0644, chip->dent,
+			(void *)CCADC_FULLSCALE_TRIM1, &reg_fops);
+	debugfs_create_file("CCADC_FULLSCALE_TRIM0", 0644, chip->dent,
+			(void *)CCADC_FULLSCALE_TRIM0, &reg_fops);
+
+	debugfs_create_file("show_ibatt", 0644, chip->dent,
+				(void *)0, &calc_fops);
+}
+
+static int __devinit pm8xxx_ccadc_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct pm8xxx_ccadc_chip *chip;
+	struct resource *res;
+	const struct pm8xxx_ccadc_platform_data *pdata
+				= pdev->dev.platform_data;
+
+	if (!pdata) {
+		pr_err("missing platform data\n");
+		return -EINVAL;
+	}
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+			"PM8921_BMS_CCADC_EOC");
+	if  (!res) {
+		pr_err("failed to get irq\n");
+		return -EINVAL;
+	}
+
+	chip = kzalloc(sizeof(struct pm8xxx_ccadc_chip), GFP_KERNEL);
+	if (!chip) {
+		pr_err("Cannot allocate pm_bms_chip\n");
+		return -ENOMEM;
+	}
+	chip->dev = &pdev->dev;
+	chip->revision = pm8xxx_get_revision(chip->dev->parent);
+	chip->eoc_irq = res->start;
+	chip->r_sense = pdata->r_sense;
+
+	rc = request_irq(chip->eoc_irq,
+			pm8921_bms_ccadc_eoc_handler, IRQF_TRIGGER_RISING,
+			"bms_eoc_ccadc", chip);
+	if (rc) {
+		pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
+		goto free_chip;
+	}
+
+	platform_set_drvdata(pdev, chip);
+	the_chip = chip;
+
+	create_debugfs_entries(chip);
+
+	calib_ccadc_read_offset_and_gain(chip,
+					&chip->ccadc_gain_uv,
+					&chip->ccadc_offset);
+	return 0;
+
+free_chip:
+	kfree(chip);
+	return rc;
+}
+
+static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev)
+{
+	struct pm8xxx_ccadc_chip *chip = platform_get_drvdata(pdev);
+
+	debugfs_remove_recursive(chip->dent);
+	the_chip = NULL;
+	kfree(chip);
+	return 0;
+}
+
+static struct platform_driver pm8xxx_ccadc_driver = {
+	.probe	= pm8xxx_ccadc_probe,
+	.remove	= __devexit_p(pm8xxx_ccadc_remove),
+	.driver	= {
+		.name	= PM8XXX_CCADC_DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pm8xxx_ccadc_init(void)
+{
+	return platform_driver_register(&pm8xxx_ccadc_driver);
+}
+
+static void __exit pm8xxx_ccadc_exit(void)
+{
+	platform_driver_unregister(&pm8xxx_ccadc_driver);
+}
+
+module_init(pm8xxx_ccadc_init);
+module_exit(pm8xxx_ccadc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC8XXX ccadc driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_CCADC_DEV_NAME);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4622725..f8b320f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -567,6 +567,7 @@
 	struct msm_otg_platform_data *pdata = motg->pdata;
 	int cnt = 0;
 	bool session_active;
+	u32 phy_ctrl_val = 0;
 
 	if (atomic_read(&motg->in_lpm))
 		return 0;
@@ -638,8 +639,13 @@
 	writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
 
 	if (motg->caps & ALLOW_PHY_RETENTION && !session_active) {
-		writel_relaxed(readl_relaxed(USB_PHY_CTRL) & ~PHY_RETEN,
-				USB_PHY_CTRL);
+		phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+		if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+			/* Enable PHY HV interrupts to wake MPM/Link */
+			phy_ctrl_val |=
+				(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+
+		writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
 		motg->lpm_flags |= PHY_RETENTIONED;
 	}
 
@@ -688,6 +694,7 @@
 	struct usb_bus *bus = otg->host;
 	int cnt = 0;
 	unsigned temp;
+	u32 phy_ctrl_val = 0;
 
 	if (!atomic_read(&motg->in_lpm))
 		return 0;
@@ -711,8 +718,13 @@
 	if (motg->lpm_flags & PHY_RETENTIONED) {
 		msm_hsusb_mhl_switch_enable(motg, 1);
 		msm_hsusb_config_vddcx(1);
-		writel_relaxed(readl_relaxed(USB_PHY_CTRL) | PHY_RETEN,
-				USB_PHY_CTRL);
+		phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+		phy_ctrl_val |= PHY_RETEN;
+		if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+			/* Disable PHY HV interrupts */
+			phy_ctrl_val &=
+				~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+		writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
 		motg->lpm_flags &= ~PHY_RETENTIONED;
 	}
 
@@ -2362,13 +2374,17 @@
 	if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
 		pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
 
-	if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
-			motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+	if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
+		if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
 			motg->pdata->pmic_id_irq)
-		motg->caps = ALLOW_PHY_POWER_COLLAPSE |
+			motg->caps = ALLOW_PHY_POWER_COLLAPSE |
 				ALLOW_PHY_RETENTION |
 				ALLOW_PHY_COMP_DISABLE;
 
+		if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+			motg->caps = ALLOW_PHY_RETENTION;
+	}
+
 	wake_lock(&motg->wlock);
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 4ef0da6..3467e0d 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -3384,35 +3384,35 @@
 }
 
 
-static uint8 hdmi_msm_avi_iframe_lut[][15] = {
-/*	480p60	480i60	576p50	576i50	720p60	720p50	1080p60	1080i60	1080p50
-	1080i50	1080p24	1080p30	1080p25	640x480p        480p60_16_9*/
-	{0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,
-	 0x10,	0x10,	0x10,	0x10,	0x10, 0x10}, /*00*/
-	{0x18,	0x18,	0x28,	0x28,	0x28,	0x28,	0x28,	0x28,	0x28,
-	 0x28,	0x28,	0x28,	0x28,	0x18, 0x28}, /*01*/
-	{0x04,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,
-	 0x04,	0x04,	0x04,	0x04,	0x88, 0x04}, /*02*/
-	{0x02,	0x06,	0x11,	0x15,	0x04,	0x13,	0x10,	0x05,	0x1F,
-	 0x14,	0x20,	0x22,	0x21,	0x01, 0x03}, /*03*/
-	{0x00,	0x01,	0x00,	0x01,	0x00,	0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00}, /*04*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00}, /*05*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00}, /*06*/
-	{0xE1,	0xE1,	0x41,	0x41,	0xD1,	0xd1,	0x39,	0x39,	0x39,
-	 0x39,	0x39,	0x39,	0x39,	0xe1, 0xE1}, /*07*/
-	{0x01,	0x01,	0x02,	0x02,	0x02,	0x02,	0x04,	0x04,	0x04,
-	 0x04,	0x04,	0x04,	0x04,	0x01, 0x01}, /*08*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00}, /*09*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00}, /*10*/
-	{0xD1,	0xD1,	0xD1,	0xD1,	0x01,	0x01,	0x81,	0x81,	0x81,
-	 0x81,	0x81,	0x81,	0x81,	0x81, 0xD1}, /*11*/
-	{0x02,	0x02,	0x02,	0x02,	0x05,	0x05,	0x07,	0x07,	0x07,
-	 0x07,	0x07,	0x07,	0x07,	0x02, 0x02} /*12*/
+static uint8 hdmi_msm_avi_iframe_lut[][16] = {
+/*	480p60	480i60	576p50	576i50	720p60	 720p50	1080p60	1080i60	1080p50
+	1080i50	1080p24	1080p30	1080p25	640x480p 480p60_16_9 576p50_4_3 */
+	{0x10,	0x10,	0x10,	0x10,	0x10,	 0x10,	0x10,	0x10,	0x10,
+	 0x10,	0x10,	0x10,	0x10,	0x10, 0x10, 0x10}, /*00*/
+	{0x18,	0x18,	0x28,	0x28,	0x28,	 0x28,	0x28,	0x28,	0x28,
+	 0x28,	0x28,	0x28,	0x28,	0x18, 0x28, 0x18}, /*01*/
+	{0x04,	0x04,	0x04,	0x04,	0x04,	 0x04,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x88, 0x04, 0x04}, /*02*/
+	{0x02,	0x06,	0x11,	0x15,	0x04,	 0x13,	0x10,	0x05,	0x1F,
+	 0x14,	0x20,	0x22,	0x21,	0x01, 0x03, 0x11}, /*03*/
+	{0x00,	0x01,	0x00,	0x01,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*04*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*05*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*06*/
+	{0xE1,	0xE1,	0x41,	0x41,	0xD1,	 0xd1,	0x39,	0x39,	0x39,
+	 0x39,	0x39,	0x39,	0x39,	0xe1, 0xE1, 0x41}, /*07*/
+	{0x01,	0x01,	0x02,	0x02,	0x02,	 0x02,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x01, 0x01, 0x02}, /*08*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*09*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*10*/
+	{0xD1,	0xD1,	0xD1,	0xD1,	0x01,	 0x01,	0x81,	0x81,	0x81,
+	 0x81,	0x81,	0x81,	0x81,	0x81, 0xD1, 0xD1}, /*11*/
+	{0x02,	0x02,	0x02,	0x02,	0x05,	 0x05,	0x07,	0x07,	0x07,
+	 0x07,	0x07,	0x07,	0x07,	0x02, 0x02, 0x02}  /*12*/
 };
 
 static void hdmi_msm_avi_info_frame(void)
@@ -3471,6 +3471,9 @@
 	case HDMI_VFRMT_720x480p60_16_9:
 		mode = 14;
 		break;
+	case HDMI_VFRMT_720x576p50_4_3:
+		mode = 15;
+		break;
 	default:
 		DEV_INFO("%s: mode %d not supported\n", __func__,
 			external_common_state->video_resolution);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index ad7fc04..a511e3c 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -35,6 +35,10 @@
 #define MDP4_RGB_BASE 0x40000
 #define MDP4_RGB_OFF 0x10000
 
+/* chip select controller */
+#define CS_CONTROLLER_0 0x0707ffff
+#define CS_CONTROLLER_1 0x03073f3f
+
 enum {
 	OVERLAY_PERF_LEVEL1 = 1,
 	OVERLAY_PERF_LEVEL2,
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 1b80d4c..383a16d 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -43,11 +43,13 @@
 struct mdp4_overlay_ctrl {
 	struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
 	struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
+	uint32 cs_controller;
 	uint32 panel_3d;
 	uint32 panel_mode;
 	uint32 mixer0_played;
 	uint32 mixer1_played;
 } mdp4_overlay_db = {
+	.cs_controller = CS_CONTROLLER_0,
 	.plist = {
 		{
 			.pipe_type = OVERLAY_TYPE_RGB,
@@ -484,6 +486,7 @@
 	char *vg_base;
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
+	uint32 mask;
 	int pnum, ptype;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -574,6 +577,24 @@
 									1));
 	}
 
+	if (mdp_rev > MDP_REV_41) {
+		/* mdp chip select controller */
+		mask = 0;
+		if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+			mask = 0x020; /* bit 5 */
+		else if (pipe->pipe_num == OVERLAY_PIPE_VG2)
+			mask = 0x02000; /* bit 13 */
+		if (mask) {
+			if (pipe->op_mode & MDP4_OP_SCALEY_MN_PHASE)
+				ctrl->cs_controller &= ~mask;
+			else
+				ctrl->cs_controller |= mask;
+			/* NOT double buffered */
+			outpdw(MDP_BASE + 0x00c0, ctrl->cs_controller);
+		}
+	}
+
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	mdp4_stat.pipe[pipe->pipe_num]++;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 143df46..770424a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -615,10 +615,21 @@
 void mdp4_dsi_cmd_kickoff_video(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe)
 {
+	/*
+	 * a video kickoff may happen before UI kickoff after
+	 * blt enabled. mdp4_overlay_update_dsi_cmd() need
+	 * to be called before kickoff.
+	 * vice versa for blt disabled.
+	 */
 	if (dsi_pipe->blt_addr && dsi_pipe->blt_cnt == 0)
-		mdp4_overlay_update_dsi_cmd(mfd);
+		mdp4_overlay_update_dsi_cmd(mfd); /* first time */
+	else if (dsi_pipe->blt_addr == 0  && dsi_pipe->blt_cnt) {
+		mdp4_overlay_update_dsi_cmd(mfd); /* last time */
+		dsi_pipe->blt_cnt = 0;
+	}
 
-	pr_debug("%s: pid=%d\n", __func__, current->pid);
+	pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
+		__func__, (int)dsi_pipe->blt_addr, dsi_pipe->blt_cnt);
 
 	if (dsi_pipe->blt_addr)
 		mdp4_dsi_blt_dmap_busy_wait(dsi_mfd);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 8370208..f96c7ea 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -258,6 +258,12 @@
 	mdp4_sw_reset(0x17);
 #endif
 
+	if (mdp_rev > MDP_REV_41) {
+		/* mdp chip select controller */
+		outpdw(MDP_BASE + 0x00c0, CS_CONTROLLER_0);
+		outpdw(MDP_BASE + 0x00c4, CS_CONTROLLER_1);
+	}
+
 	mdp4_clear_lcdc();
 
 	mdp4_mixer_blend_init(0);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 2252c8b..1a606b5 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -428,3 +428,4 @@
 header-y += tzcom.h
 header-y += qcedev.h
 header-y += idle_stats_device.h
+header-y += genlock.h
diff --git a/include/linux/genlock.h b/include/linux/genlock.h
new file mode 100644
index 0000000..2e9f9d6
--- /dev/null
+++ b/include/linux/genlock.h
@@ -0,0 +1,45 @@
+#ifndef _GENLOCK_H_
+#define _GENLOCK_H_
+
+#ifdef __KERNEL__
+
+struct genlock;
+struct genlock_handle;
+
+struct genlock_handle *genlock_get_handle(void);
+struct genlock_handle *genlock_get_handle_fd(int fd);
+void genlock_put_handle(struct genlock_handle *handle);
+struct genlock *genlock_create_lock(struct genlock_handle *);
+struct genlock *genlock_attach_lock(struct genlock_handle *, int fd);
+int genlock_wait(struct genlock_handle *handle, u32 timeout);
+void genlock_release_lock(struct genlock_handle *);
+int genlock_lock(struct genlock_handle *handle, int op, int flags,
+	u32 timeout);
+#endif
+
+#define GENLOCK_UNLOCK 0
+#define GENLOCK_WRLOCK 1
+#define GENLOCK_RDLOCK 2
+
+#define GENLOCK_NOBLOCK (1 << 0)
+
+struct genlock_lock {
+	int fd;
+	int op;
+	int flags;
+	int timeout;
+};
+
+#define GENLOCK_IOC_MAGIC     'G'
+
+#define GENLOCK_IOC_NEW _IO(GENLOCK_IOC_MAGIC, 0)
+#define GENLOCK_IOC_EXPORT _IOR(GENLOCK_IOC_MAGIC, 1, \
+	struct genlock_lock)
+#define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \
+	struct genlock_lock)
+#define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \
+	struct genlock_lock)
+#define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4)
+#define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \
+	struct genlock_lock)
+#endif
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
new file mode 100644
index 0000000..6f6cb39
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2010-2011, 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 __PMIC8XXX_CCADC_H__
+#define __PMIC8XXX_CCADC_H__
+
+#include <linux/mfd/pm8xxx/core.h>
+
+#define PM8XXX_CCADC_DEV_NAME "pm8xxx-ccadc"
+
+/**
+ * struct pm8xxx_ccadc_platform_data -
+ * @r_sense:		sense resistor value in (mOhms)
+ */
+struct pm8xxx_ccadc_platform_data {
+	int r_sense;
+};
+
+#define CCADC_READING_RESOLUTION_N_V1	1085069
+#define CCADC_READING_RESOLUTION_D_V1	100000
+#define CCADC_READING_RESOLUTION_N_V2	542535
+#define CCADC_READING_RESOLUTION_D_V2	100000
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v1(s64 cc)
+{
+	return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
+					CCADC_READING_RESOLUTION_D_V1);
+}
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v2(s64 cc)
+{
+	return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
+					CCADC_READING_RESOLUTION_D_V2);
+}
+
+static inline s64 pm8xxx_ccadc_reading_to_microvolt(int revision, s64 cc)
+{
+	/*
+	 * resolution (the value of a single bit) was changed after revision 2.0
+	 * for more accurate readings
+	 */
+	return (revision < PM8XXX_REVISION_8921_2p0) ?
+				pm8xxx_ccadc_reading_to_microvolt_v1((s64)cc) :
+				pm8xxx_ccadc_reading_to_microvolt_v2((s64)cc);
+}
+
+#if defined(CONFIG_PM8XXX_CCADC) || defined(CONFIG_PM8XXX_CCADC_MODULE)
+/**
+ * pm8xxx_cc_adjust_for_gain - the function to adjust the voltage read from
+ *			ccadc for gain compensation
+ * @v:	the voltage which needs to be gain compensated in microVolts
+ *
+ *
+ * RETURNS: gain compensated voltage
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv);
+
+/**
+ * pm8xxx_calib_ccadc - calibration for ccadc. This will calculate gain
+ *			and offset and reprogram them in the appropriate
+ *			registers
+ */
+void pm8xxx_calib_ccadc(void);
+
+/**
+ * pm8xxx_ccadc_get_battery_current - return the battery current based on vsense
+ *				resitor in milliamperes
+ * @result:	The pointer where the voltage will be updated. A -ve
+ *		result means that the current is flowing in
+ *		the battery - during battery charging
+ *
+ * RETURNS:	Error code if there was a problem reading vsense, Zero otherwise
+ *		The result won't be updated in case of an error.
+ *
+ */
+int pm8xxx_ccadc_get_battery_current(int *bat_current);
+#else
+static inline s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+	return -ENXIO;
+}
+static inline void pm8xxx_calib_ccadc(void)
+{
+}
+static inline int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+	return -ENXIO;
+}
+#endif
+
+#endif /* __PMIC8XXX_CCADC_H__ */
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
index 4e2570c..1e1fe6c 100644
--- a/include/linux/mfd/pm8xxx/irq.h
+++ b/include/linux/mfd/pm8xxx/irq.h
@@ -24,6 +24,7 @@
 struct pm8xxx_irq_core_data {
 	u32		rev;
 	int		nirqs;
+	unsigned int	base_addr;
 };
 
 struct pm8xxx_irq_platform_data {
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 73067b7..f39c00f 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -44,8 +44,8 @@
  * @min_voltage:	the voltage (mV) where charging method switches from
  *			trickle to fast. This is also the minimum voltage the
  *			system operates at
- * @resume_voltage:	the voltage (mV) to wait for before resume charging
- *			after the battery has been fully charged
+ * @resume_voltage_delta:	the (mV) drop to wait for before resume charging
+ *				after the battery has been fully charged
  * @term_current:	the charger current (mA) at which EOC happens
  * @cool_temp:		the temperature (degC) at which the battery is
  *			considered cool charging current and voltage is reduced
@@ -91,7 +91,7 @@
 	unsigned int			update_time;
 	unsigned int			max_voltage;
 	unsigned int			min_voltage;
-	unsigned int			resume_voltage;
+	unsigned int			resume_voltage_delta;
 	unsigned int			term_current;
 	unsigned int			cool_temp;
 	unsigned int			warm_temp;
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 64bdab1..2c931b6 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -35,6 +35,7 @@
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/leds-pm8xxx.h>
 #include <linux/mfd/pm8xxx/vibrator.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
 
 #define PM8921_NR_IRQS		256
 
@@ -128,6 +129,7 @@
 	struct pm8921_adc_platform_data		*adc_pdata;
 	struct pm8xxx_led_platform_data		*leds_pdata;
 	struct pm8xxx_vibrator_platform_data	*vibrator_pdata;
+	struct pm8xxx_ccadc_platform_data	*ccadc_pdata;
 };
 
 #endif
diff --git a/include/linux/mfd/wcd9310/core.h b/include/linux/mfd/wcd9310/core.h
index 2d03c95..0eb875c 100644
--- a/include/linux/mfd/wcd9310/core.h
+++ b/include/linux/mfd/wcd9310/core.h
@@ -19,6 +19,9 @@
 
 #define TABLA_SLIM_NUM_PORT_REG 3
 
+#define TABLA_INTERFACE_TYPE_SLIMBUS	0x00
+#define TABLA_INTERFACE_TYPE_I2C	0x01
+
 enum {
 	TABLA_IRQ_SLIMBUS = 0,
 	TABLA_IRQ_MBHC_REMOVAL,
@@ -82,6 +85,7 @@
 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);
 
 static inline int tabla_request_irq(struct tabla *tabla, int irq,
 				     irq_handler_t handler, const char *name,
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 9cb8356..fcd91da 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -51,6 +51,8 @@
 #define ASYNC_INTR_CTRL         (1 << 29) /* Enable async interrupt */
 #define ULPI_STP_CTRL           (1 << 30) /* Block communication with PHY */
 #define PHY_RETEN               (1 << 1) /* PHY retention enable/disable */
+#define PHY_IDHV_INTEN          (1 << 8) /* PHY ID HV interrupt */
+#define PHY_OTGSESSVLDHV_INTEN  (1 << 9) /* PHY Session Valid HV int. */
 
 /* OTG definitions */
 #define OTGSC_INTSTS_MASK	(0x7f << 16)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b7bbe02..a27358f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -612,6 +612,8 @@
 
 static int hci_dev_do_close(struct hci_dev *hdev)
 {
+	unsigned long keepflags = 0;
+
 	BT_DBG("%s %p", hdev->name, hdev);
 
 	hci_req_cancel(hdev, ENODEV);
@@ -669,8 +671,15 @@
 	if (hdev->dev_type == HCI_BREDR)
 		mgmt_powered(hdev->id, 0);
 
-	/* Clear flags */
-	hdev->flags = 0;
+	/* Clear only non-persistent flags */
+	if (test_bit(HCI_MGMT, &hdev->flags))
+		set_bit(HCI_MGMT, &keepflags);
+	if (test_bit(HCI_LINK_KEYS, &hdev->flags))
+		set_bit(HCI_LINK_KEYS, &keepflags);
+	if (test_bit(HCI_DEBUG_KEYS, &hdev->flags))
+		set_bit(HCI_DEBUG_KEYS, &keepflags);
+
+	hdev->flags = keepflags;
 
 	hci_req_unlock(hdev);
 
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 16bb5ea..c4b9950 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1203,6 +1203,7 @@
 			if (list_empty(&s->dlcs)) {
 				s->state = BT_DISCONN;
 				rfcomm_send_disc(s, 0);
+				rfcomm_session_clear_timer(s);
 			}
 
 			break;
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 97c08c0..cbe2eae 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -54,7 +54,6 @@
     "inode.c:72",
     "inode.c:73",
     "inode.c:74",
-    "menu.c:128",
     "msm_sdcc.c:126",
     "msm_sdcc.c:128",
     "nf_conntrack_netlink.c:790",
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 7f7bdc9..d330f7a 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -14,12 +14,15 @@
 #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/wcd9310/core.h>
 #include <linux/mfd/wcd9310/registers.h>
 #include <linux/mfd/wcd9310/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/jack.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -39,6 +42,8 @@
 
 #define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
 
+#define TABLA_I2S_MASTER_MODE_MASK 0x08
+
 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);
@@ -87,6 +92,9 @@
 	u8 cfilt_k_value;
 	bool mbhc_micbias_switched;
 
+	/*track tabla 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
@@ -1426,6 +1434,12 @@
 		break;
 	}
 }
+static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
+	4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
+	0, NULL, 0),
+};
 
 static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
 	/*RX stuff */
@@ -1438,6 +1452,8 @@
 
 	SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	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),
 
 	/* Headphone */
 	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
@@ -1701,6 +1717,19 @@
 	SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
 };
 
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+	{"RX_I2S_CLK", NULL, "CDC_CONN"},
+	{"SLIM RX1", NULL, "RX_I2S_CLK"},
+	{"SLIM RX2", NULL, "RX_I2S_CLK"},
+	{"SLIM RX3", NULL, "RX_I2S_CLK"},
+	{"SLIM RX4", NULL, "RX_I2S_CLK"},
+
+	{"SLIM TX7", NULL, "TX_I2S_CLK"},
+	{"SLIM TX8", NULL, "TX_I2S_CLK"},
+	{"SLIM TX9", NULL, "TX_I2S_CLK"},
+	{"SLIM TX10", NULL, "TX_I2S_CLK"},
+};
+
 static const struct snd_soc_dapm_route audio_map[] = {
 	/* SLIMBUS Connections */
 
@@ -1814,45 +1843,73 @@
 
 	{"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"},
 	{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX4 MIX1 INP2", "IIR1", "IIR1"},
 	{"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX5 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX5 MIX1 INP2", "IIR1", "IIR1"},
 	{"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX6 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX6 MIX1 INP2", "IIR1", "IIR1"},
 	{"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX7 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX7 MIX1 INP2", "IIR1", "IIR1"},
 
 	/* Decimator Inputs */
@@ -2191,7 +2248,39 @@
 
 static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
+	u8 val = 0;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
+
 	pr_debug("%s\n", __func__);
+	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 (dai->id == TABLA_TX_DAI_ID)
+				snd_soc_update_bits(dai->codec,
+					TABLA_A_CDC_CLK_TX_I2S_CTL,
+					TABLA_I2S_MASTER_MODE_MASK, 0);
+			else if (dai->id == TABLA_RX_DAI_ID)
+				snd_soc_update_bits(dai->codec,
+					TABLA_A_CDC_CLK_RX_I2S_CTL,
+					TABLA_I2S_MASTER_MODE_MASK, 0);
+		}
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+	/* CPU is slave */
+		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+			val = TABLA_I2S_MASTER_MODE_MASK;
+			if (dai->id == TABLA_TX_DAI_ID)
+				snd_soc_update_bits(dai->codec,
+					TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
+			else if (dai->id == TABLA_RX_DAI_ID)
+				snd_soc_update_bits(dai->codec,
+					TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
 	return 0;
 }
 
@@ -2200,6 +2289,7 @@
 			    struct snd_soc_dai *dai)
 {
 	struct snd_soc_codec *codec = dai->codec;
+	struct tabla_priv *tabla = 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;
@@ -2255,6 +2345,25 @@
 							0x03, tx_fs_rate);
 			}
 		}
+		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					TABLA_A_CDC_CLK_TX_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					TABLA_A_CDC_CLK_TX_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				pr_err("invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
+						0x03, tx_fs_rate);
+		}
 	}
 
 	/**
@@ -2281,6 +2390,25 @@
 						0xE0, rx_fs_rate);
 			}
 		}
+		if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					TABLA_A_CDC_CLK_RX_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					TABLA_A_CDC_CLK_RX_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				pr_err("invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
+						0x03, (rx_fs_rate >> 0x05));
+		}
 	}
 
 	return 0;
@@ -2324,6 +2452,37 @@
 		.ops = &tabla_dai_ops,
 	},
 };
+
+static struct snd_soc_dai_driver tabla_i2s_dai[] = {
+	{
+		.name = "tabla_i2s_rx1",
+		.id = 1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9310_RATES,
+			.formats = TABLA_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tabla_dai_ops,
+	},
+	{
+		.name = "tabla_i2s_tx1",
+		.id = 2,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9310_RATES,
+			.formats = TABLA_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tabla_dai_ops,
+	},
+};
 static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
 {
 	u8 bias_msb, bias_lsb;
@@ -3186,6 +3345,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_update_reg_defaults(codec);
 	tabla_codec_init_reg(codec);
@@ -3204,6 +3364,12 @@
 		ARRAY_SIZE(tabla_snd_controls));
 	snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
 		ARRAY_SIZE(tabla_dapm_widgets));
+	if (tabla->intf_type == TABLA_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,
+			ARRAY_SIZE(audio_i2s_map));
+	}
 	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 	snd_soc_dapm_sync(dapm);
 
@@ -3362,13 +3528,19 @@
 
 static int __devinit tabla_probe(struct platform_device *pdev)
 {
+	int ret = 0;
 #ifdef CONFIG_DEBUG_FS
 	debugfs_poke = debugfs_create_file("TRRS",
 		S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
 
 #endif
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
-		tabla_dai, ARRAY_SIZE(tabla_dai));
+	if (tabla_get_intf_type() == TABLA_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)
+		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
+			tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
+	return ret;
 }
 static int __devexit tabla_remove(struct platform_device *pdev)
 {